@kelnishi/satmouse-client 0.12.0 → 0.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/config.ts","../../src/utils/persistence.ts","../../src/utils/input-manager.ts"],"names":["DEFAULT_ROUTES","TypedEmitter","applyRoutes","buildRoutes"],"mappings":"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","file":"index.cjs","sourcesContent":["import { DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\n/** Maps a device button to a keyboard key */\nexport interface ButtonRoute {\n /** Device button index */\n button: number;\n /** Keyboard key value (KeyboardEvent.key, e.g., \"a\", \"Shift\", \"ArrowUp\") */\n key: string;\n /** Keyboard code (KeyboardEvent.code, e.g., \"KeyA\", \"ShiftLeft\"). Optional. */\n code?: string;\n}\n\n/** Per-device configuration */\nexport interface DeviceConfig {\n /** Axis routing — each entry maps a device input to an output with optional flip */\n routes?: AxisRoute[];\n /** Button-to-key mappings */\n buttonRoutes?: ButtonRoute[];\n /** Scale multiplier for translation axes (tx, ty, tz) */\n translateScale?: number;\n /** Scale multiplier for rotation axes (rx, ry, rz) */\n rotateScale?: number;\n /** Scale multiplier for W axis */\n wScale?: number;\n /** Dead zone threshold (0-1). Values below this are zeroed. */\n deadZone?: number;\n /** Only pass the strongest axis, zero all others */\n dominant?: boolean;\n}\n\n/** Global configuration */\nexport interface InputConfig {\n /** Default axis routes (used when device has no override) */\n routes: AxisRoute[];\n /** Default button-to-key mappings */\n buttonRoutes: ButtonRoute[];\n /** Scale multiplier for translation axes */\n translateScale: number;\n /** Scale multiplier for rotation axes */\n rotateScale: number;\n /** Scale multiplier for W axis */\n wScale: number;\n /** Dead zone threshold */\n deadZone: number;\n /** Dominant axis mode */\n dominant: boolean;\n /** Lock translation to zero */\n lockPosition: boolean;\n /** Lock rotation to zero */\n lockRotation: boolean;\n /** Per-device overrides keyed by device ID or pattern (e.g., \"cnx-*\") */\n devices: Record<string, DeviceConfig>;\n}\n\nexport const DEFAULT_CONFIG: InputConfig = {\n routes: DEFAULT_ROUTES,\n buttonRoutes: [],\n translateScale: 0.001,\n rotateScale: 0.001,\n wScale: 0.001,\n deadZone: 0,\n dominant: false,\n lockPosition: false,\n lockRotation: false,\n devices: {\n \"cnx-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"ty\", target: \"ty\", flip: true },\n { source: \"tz\", target: \"tz\", flip: true },\n { source: \"rx\", target: \"rx\" },\n { source: \"ry\", target: \"ry\", flip: true },\n { source: \"rz\", target: \"rz\", flip: true },\n ],\n },\n // PlayStation: L2 (ty) → TY, R2 (ry) → TY flipped (push-pull)\n \"hid-54c-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"tz\", target: \"tz\" },\n { source: \"rz\", target: \"rz\" },\n { source: \"rx\", target: \"rx\" },\n { source: \"ty\", target: \"ty\" },\n { source: \"ry\", target: \"ty\", flip: true },\n ],\n },\n },\n};\n\nexport function mergeConfig(base: InputConfig, partial: Partial<InputConfig>): InputConfig {\n const merged = {\n ...base,\n ...partial,\n routes: partial.routes ?? [...base.routes],\n buttonRoutes: partial.buttonRoutes ?? [...base.buttonRoutes],\n devices: { ...base.devices },\n };\n\n if (partial.devices) {\n for (const [key, devCfg] of Object.entries(partial.devices)) {\n merged.devices[key] = { ...merged.devices[key], ...devCfg };\n }\n }\n\n return merged;\n}\n\n/** Resolve the effective config for a specific device */\nexport function resolveDeviceConfig(config: InputConfig, deviceId: string): InputConfig {\n let deviceOverride: DeviceConfig | undefined;\n\n if (config.devices[deviceId]) {\n deviceOverride = config.devices[deviceId];\n } else {\n for (const [pattern, cfg] of Object.entries(config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n deviceOverride = cfg;\n break;\n }\n }\n }\n\n if (!deviceOverride) return config;\n\n return {\n ...config,\n routes: deviceOverride.routes ?? config.routes,\n buttonRoutes: deviceOverride.buttonRoutes ?? config.buttonRoutes,\n translateScale: deviceOverride.translateScale ?? config.translateScale,\n rotateScale: deviceOverride.rotateScale ?? config.rotateScale,\n wScale: deviceOverride.wScale ?? config.wScale,\n deadZone: deviceOverride.deadZone ?? config.deadZone,\n dominant: deviceOverride.dominant ?? config.dominant,\n };\n}\n","import type { InputConfig } from \"./config.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\nconst STORAGE_KEY = \"satmouse:settings\";\n\nfunction getStorage(storage?: StorageAdapter): StorageAdapter | null {\n if (storage) return storage;\n try {\n return globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nexport function saveSettings(config: InputConfig, storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, JSON.stringify(config));\n}\n\nexport function clearSettings(storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, \"{}\");\n}\n\nexport function loadSettings(storage?: StorageAdapter): Partial<InputConfig> | null {\n const s = getStorage(storage);\n if (!s) return null;\n const raw = s.getItem(STORAGE_KEY);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as Partial<InputConfig>;\n } catch {\n return null;\n }\n}\n","import { TypedEmitter } from \"../core/emitter.js\";\nimport type { SatMouseConnection } from \"../core/connection.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo, ConnectionState, TransportProtocol } from \"../core/types.js\";\nimport type { InputConfig, DeviceConfig } from \"./config.js\";\nimport { DEFAULT_CONFIG, mergeConfig, resolveDeviceConfig } from \"./config.js\";\nimport { loadSettings, saveSettings, clearSettings, type StorageAdapter } from \"./persistence.js\";\nimport { applyRoutes, buildRoutes, DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\nexport interface InputManagerEvents {\n spatialData: (data: SpatialData) => void;\n rawSpatialData: (data: SpatialData) => void;\n buttonEvent: (data: ButtonEvent) => void;\n stateChange: (state: ConnectionState, protocol: TransportProtocol) => void;\n deviceStatus: (event: \"connected\" | \"disconnected\", device: DeviceInfo) => void;\n configChange: (config: InputConfig) => void;\n}\n\nexport interface DeviceWithConfig {\n device: DeviceInfo;\n config: DeviceConfig;\n}\n\nexport class InputManager extends TypedEmitter<InputManagerEvents> {\n private connections: SatMouseConnection[] = [];\n private storage?: StorageAdapter;\n private knownDevices = new Map<string, DeviceInfo>();\n\n private deviceAccumulators = new Map<string, { tx: number; ty: number; tz: number; rx: number; ry: number; rz: number; w: number }>();\n private accDirty = false;\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n\n private _config: InputConfig;\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get config(): InputConfig {\n return this._config;\n }\n\n get state(): ConnectionState {\n return this._state;\n }\n\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(config?: Partial<InputConfig>, storage?: StorageAdapter) {\n super();\n this.storage = storage;\n const persisted = loadSettings(storage);\n this._config = mergeConfig(DEFAULT_CONFIG, { ...config, ...persisted });\n this.flushTimer = setInterval(() => this.flushAccumulator(), 16);\n }\n\n addConnection(connection: SatMouseConnection): void {\n this.connections.push(connection);\n this.wireConnection(connection);\n }\n\n /** Reset retry count and reconnect all failed connections. */\n retry(): void {\n for (const c of this.connections) c.retry();\n }\n\n removeConnection(connection: SatMouseConnection): void {\n const idx = this.connections.indexOf(connection);\n if (idx !== -1) this.connections.splice(idx, 1);\n connection.removeAllListeners();\n }\n\n async connect(): Promise<void> {\n await Promise.all(this.connections.map((c) => c.connect()));\n }\n\n disconnect(): void {\n for (const c of this.connections) c.disconnect();\n if (this.flushTimer) { clearInterval(this.flushTimer); this.flushTimer = null; }\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));\n const devices = results.flat();\n for (const d of devices) this.knownDevices.set(d.id, d);\n return devices;\n }\n\n getDevicesWithConfig(): DeviceWithConfig[] {\n return Array.from(this.knownDevices.values()).map((device) => ({\n device,\n config: this.getDeviceConfig(device.id),\n }));\n }\n\n getDeviceConfig(deviceId: string): DeviceConfig {\n const resolved = resolveDeviceConfig(this._config, deviceId);\n return {\n routes: resolved.routes,\n buttonRoutes: resolved.buttonRoutes,\n translateScale: resolved.translateScale,\n rotateScale: resolved.rotateScale,\n wScale: resolved.wScale,\n deadZone: resolved.deadZone,\n dominant: resolved.dominant,\n };\n }\n\n updateConfig(partial: Partial<InputConfig>, persist = true): void {\n this._config = mergeConfig(this._config, partial);\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n updateDeviceConfig(deviceId: string, partial: DeviceConfig, persist = true): void {\n const existing = this._config.devices[deviceId] ?? {};\n this._config = mergeConfig(this._config, {\n devices: { [deviceId]: { ...existing, ...partial } },\n });\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetDeviceConfig(deviceId: string, persist = true): void {\n const { [deviceId]: _, ...rest } = this._config.devices;\n this._config = { ...this._config, devices: rest };\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetAllConfig(): void {\n clearSettings(this.storage);\n this._config = { ...DEFAULT_CONFIG };\n this.emit(\"configChange\", this._config);\n }\n\n onSpatialData(callback: (data: SpatialData) => void): () => void {\n this.on(\"spatialData\", callback);\n return () => this.off(\"spatialData\", callback);\n }\n\n onButtonEvent(callback: (data: ButtonEvent) => void): () => void {\n this.on(\"buttonEvent\", callback);\n return () => this.off(\"buttonEvent\", callback);\n }\n\n private wireConnection(connection: SatMouseConnection): void {\n connection.on(\"spatialData\", (raw) => {\n this.emit(\"rawSpatialData\", raw);\n\n const id = raw.deviceId ?? \"_default\";\n const processed = this.processPerDevice(raw, id);\n\n this.deviceAccumulators.set(id, {\n tx: processed.translation.x,\n ty: processed.translation.y,\n tz: processed.translation.z,\n rx: processed.rotation.x,\n ry: processed.rotation.y,\n rz: processed.rotation.z,\n w: processed.w ?? 0,\n });\n this.accDirty = true;\n });\n\n connection.on(\"buttonEvent\", (event) => {\n // Check all device configs for matching button routes\n this.dispatchButtonKeys(event);\n this.emit(\"buttonEvent\", event);\n });\n connection.on(\"stateChange\", (state, proto) => {\n this._state = state;\n this._protocol = proto;\n this.emit(\"stateChange\", state, proto);\n });\n connection.on(\"deviceStatus\", (event, device) => {\n if (event === \"connected\") this.knownDevices.set(device.id, device);\n else this.knownDevices.delete(device.id);\n this.emit(\"deviceStatus\", event, device);\n });\n }\n\n private flushAccumulator(): void {\n if (!this.accDirty) return;\n\n const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0, w: 0 };\n for (const acc of this.deviceAccumulators.values()) {\n merged.tx += acc.tx;\n merged.ty += acc.ty;\n merged.tz += acc.tz;\n merged.rx += acc.rx;\n merged.ry += acc.ry;\n merged.rz += acc.rz;\n merged.w += acc.w;\n }\n\n this.deviceAccumulators.clear();\n this.accDirty = false;\n\n let data: SpatialData = {\n translation: { x: merged.tx, y: merged.ty, z: merged.tz },\n rotation: { x: merged.rx, y: merged.ry, z: merged.rz },\n w: merged.w || undefined,\n timestamp: performance.now() * 1000,\n };\n\n if (this._config.lockPosition) {\n data = { ...data, translation: { x: 0, y: 0, z: 0 } };\n }\n if (this._config.lockRotation) {\n data = { ...data, rotation: { x: 0, y: 0, z: 0 } };\n }\n\n this.emit(\"spatialData\", data);\n }\n\n /** Per-device: deadZone → dominant → routes (flip + scale + remap in one pass) */\n private processPerDevice(raw: SpatialData, deviceId: string): SpatialData {\n const cfg = resolveDeviceConfig(this._config, deviceId);\n let data = raw;\n\n // Dead zone\n if (cfg.deadZone > 0) {\n const dz = (v: number) => (Math.abs(v) < cfg.deadZone ? 0 : v);\n data = {\n ...data,\n translation: { x: dz(data.translation.x), y: dz(data.translation.y), z: dz(data.translation.z) },\n rotation: { x: dz(data.rotation.x), y: dz(data.rotation.y), z: dz(data.rotation.z) },\n };\n }\n\n // Dominant axis\n if (cfg.dominant) {\n const axes = [\n { g: \"t\" as const, k: \"x\" as const, v: Math.abs(data.translation.x) },\n { g: \"t\" as const, k: \"y\" as const, v: Math.abs(data.translation.y) },\n { g: \"t\" as const, k: \"z\" as const, v: Math.abs(data.translation.z) },\n { g: \"r\" as const, k: \"x\" as const, v: Math.abs(data.rotation.x) },\n { g: \"r\" as const, k: \"y\" as const, v: Math.abs(data.rotation.y) },\n { g: \"r\" as const, k: \"z\" as const, v: Math.abs(data.rotation.z) },\n ];\n const max = axes.reduce((a, b) => (b.v > a.v ? b : a));\n const t = { x: 0, y: 0, z: 0 };\n const r = { x: 0, y: 0, z: 0 };\n if (max.g === \"t\") t[max.k] = data.translation[max.k];\n else r[max.k] = data.rotation[max.k];\n data = { ...data, translation: t, rotation: r };\n }\n\n // Routes: flip + scale + remap in one pass\n // Use device-specific routes if configured, otherwise build from device axes metadata\n const device = this.knownDevices.get(deviceId);\n const deviceRoutes = this.resolveRoutes(deviceId, device);\n data = applyRoutes(data, deviceRoutes, cfg.translateScale, cfg.rotateScale, cfg.wScale);\n\n return data;\n }\n\n /** Get the effective routes for a device: device config override > device axes metadata > global default */\n private resolveRoutes(deviceId: string, device?: DeviceInfo): AxisRoute[] {\n // Check for explicit device config (exact match or pattern)\n const devCfg = this._config.devices[deviceId];\n if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;\n\n // Check pattern matches\n for (const [pattern, cfg] of Object.entries(this._config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;\n }\n }\n\n // Build from device axes metadata\n if (device?.axes) return buildRoutes(device.axes);\n\n // Global fallback\n return DEFAULT_ROUTES;\n }\n\n /** Dispatch KeyboardEvents for button routes matching this button event */\n private dispatchButtonKeys(event: ButtonEvent): void {\n if (typeof document === \"undefined\") return;\n\n // Collect all button routes from all device configs + global\n const allRoutes = this.collectButtonRoutes();\n for (const route of allRoutes) {\n if (route.button === event.button) {\n document.dispatchEvent(new KeyboardEvent(\n event.pressed ? \"keydown\" : \"keyup\",\n { key: route.key, code: route.code ?? \"\", bubbles: true },\n ));\n }\n }\n }\n\n /** Gather all button routes from global config + all device configs */\n private collectButtonRoutes(): import(\"./config.js\").ButtonRoute[] {\n const routes = [...this._config.buttonRoutes];\n for (const devCfg of Object.values(this._config.devices)) {\n if (devCfg.buttonRoutes) routes.push(...devCfg.buttonRoutes);\n }\n return routes;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/config.ts","../../src/utils/persistence.ts","../../src/utils/input-manager.ts"],"names":["DEFAULT_ROUTES","TypedEmitter","applyRoutes","buildRoutes"],"mappings":"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","file":"index.cjs","sourcesContent":["import { DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\n/** Maps a device button to a keyboard key */\nexport interface ButtonRoute {\n /** Device button index */\n button: number;\n /** Keyboard key value (KeyboardEvent.key, e.g., \"a\", \"Shift\", \"ArrowUp\") */\n key: string;\n /** Keyboard code (KeyboardEvent.code, e.g., \"KeyA\", \"ShiftLeft\"). Optional. */\n code?: string;\n}\n\n/** Per-device configuration */\nexport interface DeviceConfig {\n /** Axis routing — each entry maps a device input to an output with optional flip */\n routes?: AxisRoute[];\n /** Button-to-key mappings */\n buttonRoutes?: ButtonRoute[];\n /** Scale multiplier for translation axes (tx, ty, tz) */\n translateScale?: number;\n /** Scale multiplier for rotation axes (rx, ry, rz) */\n rotateScale?: number;\n /** Scale multiplier for W axis */\n wScale?: number;\n /** Dead zone threshold (0-1). Values below this are zeroed. */\n deadZone?: number;\n /** Only pass the strongest axis, zero all others */\n dominant?: boolean;\n}\n\n/** Global configuration */\nexport interface InputConfig {\n /** Default axis routes (used when device has no override) */\n routes: AxisRoute[];\n /** Default button-to-key mappings */\n buttonRoutes: ButtonRoute[];\n /** Scale multiplier for translation axes */\n translateScale: number;\n /** Scale multiplier for rotation axes */\n rotateScale: number;\n /** Scale multiplier for W axis */\n wScale: number;\n /** Dead zone threshold */\n deadZone: number;\n /** Dominant axis mode */\n dominant: boolean;\n /** Lock translation to zero */\n lockPosition: boolean;\n /** Lock rotation to zero */\n lockRotation: boolean;\n /** Per-device overrides keyed by device ID or pattern (e.g., \"cnx-*\") */\n devices: Record<string, DeviceConfig>;\n}\n\nexport const DEFAULT_CONFIG: InputConfig = {\n routes: DEFAULT_ROUTES,\n buttonRoutes: [],\n translateScale: 0.001,\n rotateScale: 0.001,\n wScale: 0.001,\n deadZone: 0,\n dominant: false,\n lockPosition: false,\n lockRotation: false,\n devices: {\n \"cnx-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"ty\", target: \"ty\", flip: true },\n { source: \"tz\", target: \"tz\", flip: true },\n { source: \"rx\", target: \"rx\" },\n { source: \"ry\", target: \"ry\", flip: true },\n { source: \"rz\", target: \"rz\", flip: true },\n ],\n },\n // PlayStation: L2 (ty) → TY, R2 (ry) → TY flipped (push-pull)\n \"hid-54c-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"tz\", target: \"tz\" },\n { source: \"rz\", target: \"rz\" },\n { source: \"rx\", target: \"rx\" },\n { source: \"ty\", target: \"ty\" },\n { source: \"ry\", target: \"ty\", flip: true },\n ],\n },\n },\n};\n\nexport function mergeConfig(base: InputConfig, partial: Partial<InputConfig>): InputConfig {\n const merged = {\n ...base,\n ...partial,\n routes: partial.routes ?? [...base.routes],\n buttonRoutes: partial.buttonRoutes ?? [...base.buttonRoutes],\n devices: { ...base.devices },\n };\n\n if (partial.devices) {\n for (const [key, devCfg] of Object.entries(partial.devices)) {\n merged.devices[key] = { ...merged.devices[key], ...devCfg };\n }\n }\n\n return merged;\n}\n\n/** Resolve the effective config for a specific device */\nexport function resolveDeviceConfig(config: InputConfig, deviceId: string): InputConfig {\n let deviceOverride: DeviceConfig | undefined;\n\n if (config.devices[deviceId]) {\n deviceOverride = config.devices[deviceId];\n } else {\n for (const [pattern, cfg] of Object.entries(config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n deviceOverride = cfg;\n break;\n }\n }\n }\n\n if (!deviceOverride) return config;\n\n return {\n ...config,\n routes: deviceOverride.routes ?? config.routes,\n buttonRoutes: deviceOverride.buttonRoutes ?? config.buttonRoutes,\n translateScale: deviceOverride.translateScale ?? config.translateScale,\n rotateScale: deviceOverride.rotateScale ?? config.rotateScale,\n wScale: deviceOverride.wScale ?? config.wScale,\n deadZone: deviceOverride.deadZone ?? config.deadZone,\n dominant: deviceOverride.dominant ?? config.dominant,\n };\n}\n","import type { InputConfig } from \"./config.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\nconst STORAGE_KEY = \"satmouse:settings\";\n\nfunction getStorage(storage?: StorageAdapter): StorageAdapter | null {\n if (storage) return storage;\n try {\n return globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nexport function saveSettings(config: InputConfig, storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, JSON.stringify(config));\n}\n\nexport function clearSettings(storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, \"{}\");\n}\n\nexport function loadSettings(storage?: StorageAdapter): Partial<InputConfig> | null {\n const s = getStorage(storage);\n if (!s) return null;\n const raw = s.getItem(STORAGE_KEY);\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as any;\n // Migrate old single \"scale\" to separate translate/rotate/w scales\n if (parsed.scale != null && parsed.translateScale == null) {\n parsed.translateScale = parsed.scale;\n parsed.rotateScale = parsed.scale;\n parsed.wScale = parsed.scale;\n delete parsed.scale;\n }\n return parsed as Partial<InputConfig>;\n } catch {\n return null;\n }\n}\n","import { TypedEmitter } from \"../core/emitter.js\";\nimport type { SatMouseConnection } from \"../core/connection.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo, ConnectionState, TransportProtocol } from \"../core/types.js\";\nimport type { InputConfig, DeviceConfig } from \"./config.js\";\nimport { DEFAULT_CONFIG, mergeConfig, resolveDeviceConfig } from \"./config.js\";\nimport { loadSettings, saveSettings, clearSettings, type StorageAdapter } from \"./persistence.js\";\nimport { applyRoutes, buildRoutes, DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\nexport interface InputManagerEvents {\n spatialData: (data: SpatialData) => void;\n rawSpatialData: (data: SpatialData) => void;\n buttonEvent: (data: ButtonEvent) => void;\n stateChange: (state: ConnectionState, protocol: TransportProtocol) => void;\n deviceStatus: (event: \"connected\" | \"disconnected\", device: DeviceInfo) => void;\n configChange: (config: InputConfig) => void;\n}\n\nexport interface DeviceWithConfig {\n device: DeviceInfo;\n config: DeviceConfig;\n}\n\nexport class InputManager extends TypedEmitter<InputManagerEvents> {\n private connections: SatMouseConnection[] = [];\n private storage?: StorageAdapter;\n private knownDevices = new Map<string, DeviceInfo>();\n\n private deviceAccumulators = new Map<string, { tx: number; ty: number; tz: number; rx: number; ry: number; rz: number; w: number }>();\n private accDirty = false;\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n\n private _config: InputConfig;\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get config(): InputConfig {\n return this._config;\n }\n\n get state(): ConnectionState {\n return this._state;\n }\n\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(config?: Partial<InputConfig>, storage?: StorageAdapter) {\n super();\n this.storage = storage;\n const persisted = loadSettings(storage);\n this._config = mergeConfig(DEFAULT_CONFIG, { ...config, ...persisted });\n this.flushTimer = setInterval(() => this.flushAccumulator(), 16);\n }\n\n addConnection(connection: SatMouseConnection): void {\n this.connections.push(connection);\n this.wireConnection(connection);\n }\n\n /** Reset retry count and reconnect all failed connections. */\n retry(): void {\n for (const c of this.connections) c.retry();\n }\n\n removeConnection(connection: SatMouseConnection): void {\n const idx = this.connections.indexOf(connection);\n if (idx !== -1) this.connections.splice(idx, 1);\n connection.removeAllListeners();\n }\n\n async connect(): Promise<void> {\n await Promise.all(this.connections.map((c) => c.connect()));\n }\n\n disconnect(): void {\n for (const c of this.connections) c.disconnect();\n if (this.flushTimer) { clearInterval(this.flushTimer); this.flushTimer = null; }\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));\n const devices = results.flat();\n for (const d of devices) this.knownDevices.set(d.id, d);\n return devices;\n }\n\n getDevicesWithConfig(): DeviceWithConfig[] {\n return Array.from(this.knownDevices.values()).map((device) => ({\n device,\n config: this.getDeviceConfig(device.id),\n }));\n }\n\n getDeviceConfig(deviceId: string): DeviceConfig {\n const resolved = resolveDeviceConfig(this._config, deviceId);\n return {\n routes: resolved.routes,\n buttonRoutes: resolved.buttonRoutes,\n translateScale: resolved.translateScale,\n rotateScale: resolved.rotateScale,\n wScale: resolved.wScale,\n deadZone: resolved.deadZone,\n dominant: resolved.dominant,\n };\n }\n\n updateConfig(partial: Partial<InputConfig>, persist = true): void {\n this._config = mergeConfig(this._config, partial);\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n updateDeviceConfig(deviceId: string, partial: DeviceConfig, persist = true): void {\n const existing = this._config.devices[deviceId] ?? {};\n this._config = mergeConfig(this._config, {\n devices: { [deviceId]: { ...existing, ...partial } },\n });\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetDeviceConfig(deviceId: string, persist = true): void {\n const { [deviceId]: _, ...rest } = this._config.devices;\n this._config = { ...this._config, devices: rest };\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetAllConfig(): void {\n clearSettings(this.storage);\n this._config = { ...DEFAULT_CONFIG };\n this.emit(\"configChange\", this._config);\n }\n\n onSpatialData(callback: (data: SpatialData) => void): () => void {\n this.on(\"spatialData\", callback);\n return () => this.off(\"spatialData\", callback);\n }\n\n onButtonEvent(callback: (data: ButtonEvent) => void): () => void {\n this.on(\"buttonEvent\", callback);\n return () => this.off(\"buttonEvent\", callback);\n }\n\n private wireConnection(connection: SatMouseConnection): void {\n connection.on(\"spatialData\", (raw) => {\n this.emit(\"rawSpatialData\", raw);\n\n const id = raw.deviceId ?? \"_default\";\n const processed = this.processPerDevice(raw, id);\n\n this.deviceAccumulators.set(id, {\n tx: processed.translation.x,\n ty: processed.translation.y,\n tz: processed.translation.z,\n rx: processed.rotation.x,\n ry: processed.rotation.y,\n rz: processed.rotation.z,\n w: processed.w ?? 0,\n });\n this.accDirty = true;\n });\n\n connection.on(\"buttonEvent\", (event) => {\n // Check all device configs for matching button routes\n this.dispatchButtonKeys(event);\n this.emit(\"buttonEvent\", event);\n });\n connection.on(\"stateChange\", (state, proto) => {\n this._state = state;\n this._protocol = proto;\n this.emit(\"stateChange\", state, proto);\n });\n connection.on(\"deviceStatus\", (event, device) => {\n if (event === \"connected\") this.knownDevices.set(device.id, device);\n else this.knownDevices.delete(device.id);\n this.emit(\"deviceStatus\", event, device);\n });\n }\n\n private flushAccumulator(): void {\n if (!this.accDirty) return;\n\n const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0, w: 0 };\n for (const acc of this.deviceAccumulators.values()) {\n merged.tx += acc.tx;\n merged.ty += acc.ty;\n merged.tz += acc.tz;\n merged.rx += acc.rx;\n merged.ry += acc.ry;\n merged.rz += acc.rz;\n merged.w += acc.w;\n }\n\n this.deviceAccumulators.clear();\n this.accDirty = false;\n\n let data: SpatialData = {\n translation: { x: merged.tx, y: merged.ty, z: merged.tz },\n rotation: { x: merged.rx, y: merged.ry, z: merged.rz },\n w: merged.w || undefined,\n timestamp: performance.now() * 1000,\n };\n\n if (this._config.lockPosition) {\n data = { ...data, translation: { x: 0, y: 0, z: 0 } };\n }\n if (this._config.lockRotation) {\n data = { ...data, rotation: { x: 0, y: 0, z: 0 } };\n }\n\n this.emit(\"spatialData\", data);\n }\n\n /** Per-device: deadZone → dominant → routes (flip + scale + remap in one pass) */\n private processPerDevice(raw: SpatialData, deviceId: string): SpatialData {\n const cfg = resolveDeviceConfig(this._config, deviceId);\n let data = raw;\n\n // Dead zone\n if (cfg.deadZone > 0) {\n const dz = (v: number) => (Math.abs(v) < cfg.deadZone ? 0 : v);\n data = {\n ...data,\n translation: { x: dz(data.translation.x), y: dz(data.translation.y), z: dz(data.translation.z) },\n rotation: { x: dz(data.rotation.x), y: dz(data.rotation.y), z: dz(data.rotation.z) },\n };\n }\n\n // Dominant axis\n if (cfg.dominant) {\n const axes = [\n { g: \"t\" as const, k: \"x\" as const, v: Math.abs(data.translation.x) },\n { g: \"t\" as const, k: \"y\" as const, v: Math.abs(data.translation.y) },\n { g: \"t\" as const, k: \"z\" as const, v: Math.abs(data.translation.z) },\n { g: \"r\" as const, k: \"x\" as const, v: Math.abs(data.rotation.x) },\n { g: \"r\" as const, k: \"y\" as const, v: Math.abs(data.rotation.y) },\n { g: \"r\" as const, k: \"z\" as const, v: Math.abs(data.rotation.z) },\n ];\n const max = axes.reduce((a, b) => (b.v > a.v ? b : a));\n const t = { x: 0, y: 0, z: 0 };\n const r = { x: 0, y: 0, z: 0 };\n if (max.g === \"t\") t[max.k] = data.translation[max.k];\n else r[max.k] = data.rotation[max.k];\n data = { ...data, translation: t, rotation: r };\n }\n\n // Routes: flip + scale + remap in one pass\n // Use device-specific routes if configured, otherwise build from device axes metadata\n const device = this.knownDevices.get(deviceId);\n const deviceRoutes = this.resolveRoutes(deviceId, device);\n data = applyRoutes(data, deviceRoutes, cfg.translateScale, cfg.rotateScale, cfg.wScale);\n\n return data;\n }\n\n /** Get the effective routes for a device: device config override > device axes metadata > global default */\n private resolveRoutes(deviceId: string, device?: DeviceInfo): AxisRoute[] {\n // Check for explicit device config (exact match or pattern)\n const devCfg = this._config.devices[deviceId];\n if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;\n\n // Check pattern matches\n for (const [pattern, cfg] of Object.entries(this._config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;\n }\n }\n\n // Build from device axes metadata\n if (device?.axes) return buildRoutes(device.axes);\n\n // Global fallback\n return DEFAULT_ROUTES;\n }\n\n /** Dispatch KeyboardEvents for button routes matching this button event */\n private dispatchButtonKeys(event: ButtonEvent): void {\n if (typeof document === \"undefined\") return;\n\n // Collect all button routes from all device configs + global\n const allRoutes = this.collectButtonRoutes();\n for (const route of allRoutes) {\n if (route.button === event.button) {\n document.dispatchEvent(new KeyboardEvent(\n event.pressed ? \"keydown\" : \"keyup\",\n { key: route.key, code: route.code ?? \"\", bubbles: true },\n ));\n }\n }\n }\n\n /** Gather all button routes from global config + all device configs */\n private collectButtonRoutes(): import(\"./config.js\").ButtonRoute[] {\n const routes = [...this._config.buttonRoutes];\n for (const devCfg of Object.values(this._config.devices)) {\n if (devCfg.buttonRoutes) routes.push(...devCfg.buttonRoutes);\n }\n return routes;\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-C7xJRLzQ.cjs';
1
+ import { S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-iUlge6Er.cjs';
2
2
 
3
3
  /** Axis identifier — full or half */
4
4
  type InputAxis = "tx" | "ty" | "tz" | "rx" | "ry" | "rz" | "w" | "tx+" | "ty+" | "tz+" | "rx+" | "ry+" | "rz+" | "w+" | "tx-" | "ty-" | "tz-" | "rx-" | "ry-" | "rz-" | "w-";
@@ -1,4 +1,4 @@
1
- import { S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-C7xJRLzQ.js';
1
+ import { S as SpatialData, D as DeviceInfo, e as TypedEmitter, B as ButtonEvent, a as ConnectionState, d as TransportProtocol, b as SatMouseConnection } from '../connection-iUlge6Er.js';
2
2
 
3
3
  /** Axis identifier — full or half */
4
4
  type InputAxis = "tx" | "ty" | "tz" | "rx" | "ry" | "rz" | "w" | "tx+" | "ty+" | "tz+" | "rx+" | "ry+" | "rz+" | "w+" | "tx-" | "ty-" | "tz-" | "rx-" | "ry-" | "rz-" | "w-";
@@ -103,7 +103,14 @@ function loadSettings(storage) {
103
103
  const raw = s.getItem(STORAGE_KEY);
104
104
  if (!raw) return null;
105
105
  try {
106
- return JSON.parse(raw);
106
+ const parsed = JSON.parse(raw);
107
+ if (parsed.scale != null && parsed.translateScale == null) {
108
+ parsed.translateScale = parsed.scale;
109
+ parsed.rotateScale = parsed.scale;
110
+ parsed.wScale = parsed.scale;
111
+ delete parsed.scale;
112
+ }
113
+ return parsed;
107
114
  } catch {
108
115
  return null;
109
116
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/config.ts","../../src/utils/persistence.ts","../../src/utils/input-manager.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\n/** Maps a device button to a keyboard key */\nexport interface ButtonRoute {\n /** Device button index */\n button: number;\n /** Keyboard key value (KeyboardEvent.key, e.g., \"a\", \"Shift\", \"ArrowUp\") */\n key: string;\n /** Keyboard code (KeyboardEvent.code, e.g., \"KeyA\", \"ShiftLeft\"). Optional. */\n code?: string;\n}\n\n/** Per-device configuration */\nexport interface DeviceConfig {\n /** Axis routing — each entry maps a device input to an output with optional flip */\n routes?: AxisRoute[];\n /** Button-to-key mappings */\n buttonRoutes?: ButtonRoute[];\n /** Scale multiplier for translation axes (tx, ty, tz) */\n translateScale?: number;\n /** Scale multiplier for rotation axes (rx, ry, rz) */\n rotateScale?: number;\n /** Scale multiplier for W axis */\n wScale?: number;\n /** Dead zone threshold (0-1). Values below this are zeroed. */\n deadZone?: number;\n /** Only pass the strongest axis, zero all others */\n dominant?: boolean;\n}\n\n/** Global configuration */\nexport interface InputConfig {\n /** Default axis routes (used when device has no override) */\n routes: AxisRoute[];\n /** Default button-to-key mappings */\n buttonRoutes: ButtonRoute[];\n /** Scale multiplier for translation axes */\n translateScale: number;\n /** Scale multiplier for rotation axes */\n rotateScale: number;\n /** Scale multiplier for W axis */\n wScale: number;\n /** Dead zone threshold */\n deadZone: number;\n /** Dominant axis mode */\n dominant: boolean;\n /** Lock translation to zero */\n lockPosition: boolean;\n /** Lock rotation to zero */\n lockRotation: boolean;\n /** Per-device overrides keyed by device ID or pattern (e.g., \"cnx-*\") */\n devices: Record<string, DeviceConfig>;\n}\n\nexport const DEFAULT_CONFIG: InputConfig = {\n routes: DEFAULT_ROUTES,\n buttonRoutes: [],\n translateScale: 0.001,\n rotateScale: 0.001,\n wScale: 0.001,\n deadZone: 0,\n dominant: false,\n lockPosition: false,\n lockRotation: false,\n devices: {\n \"cnx-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"ty\", target: \"ty\", flip: true },\n { source: \"tz\", target: \"tz\", flip: true },\n { source: \"rx\", target: \"rx\" },\n { source: \"ry\", target: \"ry\", flip: true },\n { source: \"rz\", target: \"rz\", flip: true },\n ],\n },\n // PlayStation: L2 (ty) → TY, R2 (ry) → TY flipped (push-pull)\n \"hid-54c-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"tz\", target: \"tz\" },\n { source: \"rz\", target: \"rz\" },\n { source: \"rx\", target: \"rx\" },\n { source: \"ty\", target: \"ty\" },\n { source: \"ry\", target: \"ty\", flip: true },\n ],\n },\n },\n};\n\nexport function mergeConfig(base: InputConfig, partial: Partial<InputConfig>): InputConfig {\n const merged = {\n ...base,\n ...partial,\n routes: partial.routes ?? [...base.routes],\n buttonRoutes: partial.buttonRoutes ?? [...base.buttonRoutes],\n devices: { ...base.devices },\n };\n\n if (partial.devices) {\n for (const [key, devCfg] of Object.entries(partial.devices)) {\n merged.devices[key] = { ...merged.devices[key], ...devCfg };\n }\n }\n\n return merged;\n}\n\n/** Resolve the effective config for a specific device */\nexport function resolveDeviceConfig(config: InputConfig, deviceId: string): InputConfig {\n let deviceOverride: DeviceConfig | undefined;\n\n if (config.devices[deviceId]) {\n deviceOverride = config.devices[deviceId];\n } else {\n for (const [pattern, cfg] of Object.entries(config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n deviceOverride = cfg;\n break;\n }\n }\n }\n\n if (!deviceOverride) return config;\n\n return {\n ...config,\n routes: deviceOverride.routes ?? config.routes,\n buttonRoutes: deviceOverride.buttonRoutes ?? config.buttonRoutes,\n translateScale: deviceOverride.translateScale ?? config.translateScale,\n rotateScale: deviceOverride.rotateScale ?? config.rotateScale,\n wScale: deviceOverride.wScale ?? config.wScale,\n deadZone: deviceOverride.deadZone ?? config.deadZone,\n dominant: deviceOverride.dominant ?? config.dominant,\n };\n}\n","import type { InputConfig } from \"./config.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\nconst STORAGE_KEY = \"satmouse:settings\";\n\nfunction getStorage(storage?: StorageAdapter): StorageAdapter | null {\n if (storage) return storage;\n try {\n return globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nexport function saveSettings(config: InputConfig, storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, JSON.stringify(config));\n}\n\nexport function clearSettings(storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, \"{}\");\n}\n\nexport function loadSettings(storage?: StorageAdapter): Partial<InputConfig> | null {\n const s = getStorage(storage);\n if (!s) return null;\n const raw = s.getItem(STORAGE_KEY);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as Partial<InputConfig>;\n } catch {\n return null;\n }\n}\n","import { TypedEmitter } from \"../core/emitter.js\";\nimport type { SatMouseConnection } from \"../core/connection.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo, ConnectionState, TransportProtocol } from \"../core/types.js\";\nimport type { InputConfig, DeviceConfig } from \"./config.js\";\nimport { DEFAULT_CONFIG, mergeConfig, resolveDeviceConfig } from \"./config.js\";\nimport { loadSettings, saveSettings, clearSettings, type StorageAdapter } from \"./persistence.js\";\nimport { applyRoutes, buildRoutes, DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\nexport interface InputManagerEvents {\n spatialData: (data: SpatialData) => void;\n rawSpatialData: (data: SpatialData) => void;\n buttonEvent: (data: ButtonEvent) => void;\n stateChange: (state: ConnectionState, protocol: TransportProtocol) => void;\n deviceStatus: (event: \"connected\" | \"disconnected\", device: DeviceInfo) => void;\n configChange: (config: InputConfig) => void;\n}\n\nexport interface DeviceWithConfig {\n device: DeviceInfo;\n config: DeviceConfig;\n}\n\nexport class InputManager extends TypedEmitter<InputManagerEvents> {\n private connections: SatMouseConnection[] = [];\n private storage?: StorageAdapter;\n private knownDevices = new Map<string, DeviceInfo>();\n\n private deviceAccumulators = new Map<string, { tx: number; ty: number; tz: number; rx: number; ry: number; rz: number; w: number }>();\n private accDirty = false;\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n\n private _config: InputConfig;\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get config(): InputConfig {\n return this._config;\n }\n\n get state(): ConnectionState {\n return this._state;\n }\n\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(config?: Partial<InputConfig>, storage?: StorageAdapter) {\n super();\n this.storage = storage;\n const persisted = loadSettings(storage);\n this._config = mergeConfig(DEFAULT_CONFIG, { ...config, ...persisted });\n this.flushTimer = setInterval(() => this.flushAccumulator(), 16);\n }\n\n addConnection(connection: SatMouseConnection): void {\n this.connections.push(connection);\n this.wireConnection(connection);\n }\n\n /** Reset retry count and reconnect all failed connections. */\n retry(): void {\n for (const c of this.connections) c.retry();\n }\n\n removeConnection(connection: SatMouseConnection): void {\n const idx = this.connections.indexOf(connection);\n if (idx !== -1) this.connections.splice(idx, 1);\n connection.removeAllListeners();\n }\n\n async connect(): Promise<void> {\n await Promise.all(this.connections.map((c) => c.connect()));\n }\n\n disconnect(): void {\n for (const c of this.connections) c.disconnect();\n if (this.flushTimer) { clearInterval(this.flushTimer); this.flushTimer = null; }\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));\n const devices = results.flat();\n for (const d of devices) this.knownDevices.set(d.id, d);\n return devices;\n }\n\n getDevicesWithConfig(): DeviceWithConfig[] {\n return Array.from(this.knownDevices.values()).map((device) => ({\n device,\n config: this.getDeviceConfig(device.id),\n }));\n }\n\n getDeviceConfig(deviceId: string): DeviceConfig {\n const resolved = resolveDeviceConfig(this._config, deviceId);\n return {\n routes: resolved.routes,\n buttonRoutes: resolved.buttonRoutes,\n translateScale: resolved.translateScale,\n rotateScale: resolved.rotateScale,\n wScale: resolved.wScale,\n deadZone: resolved.deadZone,\n dominant: resolved.dominant,\n };\n }\n\n updateConfig(partial: Partial<InputConfig>, persist = true): void {\n this._config = mergeConfig(this._config, partial);\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n updateDeviceConfig(deviceId: string, partial: DeviceConfig, persist = true): void {\n const existing = this._config.devices[deviceId] ?? {};\n this._config = mergeConfig(this._config, {\n devices: { [deviceId]: { ...existing, ...partial } },\n });\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetDeviceConfig(deviceId: string, persist = true): void {\n const { [deviceId]: _, ...rest } = this._config.devices;\n this._config = { ...this._config, devices: rest };\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetAllConfig(): void {\n clearSettings(this.storage);\n this._config = { ...DEFAULT_CONFIG };\n this.emit(\"configChange\", this._config);\n }\n\n onSpatialData(callback: (data: SpatialData) => void): () => void {\n this.on(\"spatialData\", callback);\n return () => this.off(\"spatialData\", callback);\n }\n\n onButtonEvent(callback: (data: ButtonEvent) => void): () => void {\n this.on(\"buttonEvent\", callback);\n return () => this.off(\"buttonEvent\", callback);\n }\n\n private wireConnection(connection: SatMouseConnection): void {\n connection.on(\"spatialData\", (raw) => {\n this.emit(\"rawSpatialData\", raw);\n\n const id = raw.deviceId ?? \"_default\";\n const processed = this.processPerDevice(raw, id);\n\n this.deviceAccumulators.set(id, {\n tx: processed.translation.x,\n ty: processed.translation.y,\n tz: processed.translation.z,\n rx: processed.rotation.x,\n ry: processed.rotation.y,\n rz: processed.rotation.z,\n w: processed.w ?? 0,\n });\n this.accDirty = true;\n });\n\n connection.on(\"buttonEvent\", (event) => {\n // Check all device configs for matching button routes\n this.dispatchButtonKeys(event);\n this.emit(\"buttonEvent\", event);\n });\n connection.on(\"stateChange\", (state, proto) => {\n this._state = state;\n this._protocol = proto;\n this.emit(\"stateChange\", state, proto);\n });\n connection.on(\"deviceStatus\", (event, device) => {\n if (event === \"connected\") this.knownDevices.set(device.id, device);\n else this.knownDevices.delete(device.id);\n this.emit(\"deviceStatus\", event, device);\n });\n }\n\n private flushAccumulator(): void {\n if (!this.accDirty) return;\n\n const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0, w: 0 };\n for (const acc of this.deviceAccumulators.values()) {\n merged.tx += acc.tx;\n merged.ty += acc.ty;\n merged.tz += acc.tz;\n merged.rx += acc.rx;\n merged.ry += acc.ry;\n merged.rz += acc.rz;\n merged.w += acc.w;\n }\n\n this.deviceAccumulators.clear();\n this.accDirty = false;\n\n let data: SpatialData = {\n translation: { x: merged.tx, y: merged.ty, z: merged.tz },\n rotation: { x: merged.rx, y: merged.ry, z: merged.rz },\n w: merged.w || undefined,\n timestamp: performance.now() * 1000,\n };\n\n if (this._config.lockPosition) {\n data = { ...data, translation: { x: 0, y: 0, z: 0 } };\n }\n if (this._config.lockRotation) {\n data = { ...data, rotation: { x: 0, y: 0, z: 0 } };\n }\n\n this.emit(\"spatialData\", data);\n }\n\n /** Per-device: deadZone → dominant → routes (flip + scale + remap in one pass) */\n private processPerDevice(raw: SpatialData, deviceId: string): SpatialData {\n const cfg = resolveDeviceConfig(this._config, deviceId);\n let data = raw;\n\n // Dead zone\n if (cfg.deadZone > 0) {\n const dz = (v: number) => (Math.abs(v) < cfg.deadZone ? 0 : v);\n data = {\n ...data,\n translation: { x: dz(data.translation.x), y: dz(data.translation.y), z: dz(data.translation.z) },\n rotation: { x: dz(data.rotation.x), y: dz(data.rotation.y), z: dz(data.rotation.z) },\n };\n }\n\n // Dominant axis\n if (cfg.dominant) {\n const axes = [\n { g: \"t\" as const, k: \"x\" as const, v: Math.abs(data.translation.x) },\n { g: \"t\" as const, k: \"y\" as const, v: Math.abs(data.translation.y) },\n { g: \"t\" as const, k: \"z\" as const, v: Math.abs(data.translation.z) },\n { g: \"r\" as const, k: \"x\" as const, v: Math.abs(data.rotation.x) },\n { g: \"r\" as const, k: \"y\" as const, v: Math.abs(data.rotation.y) },\n { g: \"r\" as const, k: \"z\" as const, v: Math.abs(data.rotation.z) },\n ];\n const max = axes.reduce((a, b) => (b.v > a.v ? b : a));\n const t = { x: 0, y: 0, z: 0 };\n const r = { x: 0, y: 0, z: 0 };\n if (max.g === \"t\") t[max.k] = data.translation[max.k];\n else r[max.k] = data.rotation[max.k];\n data = { ...data, translation: t, rotation: r };\n }\n\n // Routes: flip + scale + remap in one pass\n // Use device-specific routes if configured, otherwise build from device axes metadata\n const device = this.knownDevices.get(deviceId);\n const deviceRoutes = this.resolveRoutes(deviceId, device);\n data = applyRoutes(data, deviceRoutes, cfg.translateScale, cfg.rotateScale, cfg.wScale);\n\n return data;\n }\n\n /** Get the effective routes for a device: device config override > device axes metadata > global default */\n private resolveRoutes(deviceId: string, device?: DeviceInfo): AxisRoute[] {\n // Check for explicit device config (exact match or pattern)\n const devCfg = this._config.devices[deviceId];\n if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;\n\n // Check pattern matches\n for (const [pattern, cfg] of Object.entries(this._config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;\n }\n }\n\n // Build from device axes metadata\n if (device?.axes) return buildRoutes(device.axes);\n\n // Global fallback\n return DEFAULT_ROUTES;\n }\n\n /** Dispatch KeyboardEvents for button routes matching this button event */\n private dispatchButtonKeys(event: ButtonEvent): void {\n if (typeof document === \"undefined\") return;\n\n // Collect all button routes from all device configs + global\n const allRoutes = this.collectButtonRoutes();\n for (const route of allRoutes) {\n if (route.button === event.button) {\n document.dispatchEvent(new KeyboardEvent(\n event.pressed ? \"keydown\" : \"keyup\",\n { key: route.key, code: route.code ?? \"\", bubbles: true },\n ));\n }\n }\n }\n\n /** Gather all button routes from global config + all device configs */\n private collectButtonRoutes(): import(\"./config.js\").ButtonRoute[] {\n const routes = [...this._config.buttonRoutes];\n for (const devCfg of Object.values(this._config.devices)) {\n if (devCfg.buttonRoutes) routes.push(...devCfg.buttonRoutes);\n }\n return routes;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/config.ts","../../src/utils/persistence.ts","../../src/utils/input-manager.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\n/** Maps a device button to a keyboard key */\nexport interface ButtonRoute {\n /** Device button index */\n button: number;\n /** Keyboard key value (KeyboardEvent.key, e.g., \"a\", \"Shift\", \"ArrowUp\") */\n key: string;\n /** Keyboard code (KeyboardEvent.code, e.g., \"KeyA\", \"ShiftLeft\"). Optional. */\n code?: string;\n}\n\n/** Per-device configuration */\nexport interface DeviceConfig {\n /** Axis routing — each entry maps a device input to an output with optional flip */\n routes?: AxisRoute[];\n /** Button-to-key mappings */\n buttonRoutes?: ButtonRoute[];\n /** Scale multiplier for translation axes (tx, ty, tz) */\n translateScale?: number;\n /** Scale multiplier for rotation axes (rx, ry, rz) */\n rotateScale?: number;\n /** Scale multiplier for W axis */\n wScale?: number;\n /** Dead zone threshold (0-1). Values below this are zeroed. */\n deadZone?: number;\n /** Only pass the strongest axis, zero all others */\n dominant?: boolean;\n}\n\n/** Global configuration */\nexport interface InputConfig {\n /** Default axis routes (used when device has no override) */\n routes: AxisRoute[];\n /** Default button-to-key mappings */\n buttonRoutes: ButtonRoute[];\n /** Scale multiplier for translation axes */\n translateScale: number;\n /** Scale multiplier for rotation axes */\n rotateScale: number;\n /** Scale multiplier for W axis */\n wScale: number;\n /** Dead zone threshold */\n deadZone: number;\n /** Dominant axis mode */\n dominant: boolean;\n /** Lock translation to zero */\n lockPosition: boolean;\n /** Lock rotation to zero */\n lockRotation: boolean;\n /** Per-device overrides keyed by device ID or pattern (e.g., \"cnx-*\") */\n devices: Record<string, DeviceConfig>;\n}\n\nexport const DEFAULT_CONFIG: InputConfig = {\n routes: DEFAULT_ROUTES,\n buttonRoutes: [],\n translateScale: 0.001,\n rotateScale: 0.001,\n wScale: 0.001,\n deadZone: 0,\n dominant: false,\n lockPosition: false,\n lockRotation: false,\n devices: {\n \"cnx-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"ty\", target: \"ty\", flip: true },\n { source: \"tz\", target: \"tz\", flip: true },\n { source: \"rx\", target: \"rx\" },\n { source: \"ry\", target: \"ry\", flip: true },\n { source: \"rz\", target: \"rz\", flip: true },\n ],\n },\n // PlayStation: L2 (ty) → TY, R2 (ry) → TY flipped (push-pull)\n \"hid-54c-*\": {\n routes: [\n { source: \"tx\", target: \"tx\" },\n { source: \"tz\", target: \"tz\" },\n { source: \"rz\", target: \"rz\" },\n { source: \"rx\", target: \"rx\" },\n { source: \"ty\", target: \"ty\" },\n { source: \"ry\", target: \"ty\", flip: true },\n ],\n },\n },\n};\n\nexport function mergeConfig(base: InputConfig, partial: Partial<InputConfig>): InputConfig {\n const merged = {\n ...base,\n ...partial,\n routes: partial.routes ?? [...base.routes],\n buttonRoutes: partial.buttonRoutes ?? [...base.buttonRoutes],\n devices: { ...base.devices },\n };\n\n if (partial.devices) {\n for (const [key, devCfg] of Object.entries(partial.devices)) {\n merged.devices[key] = { ...merged.devices[key], ...devCfg };\n }\n }\n\n return merged;\n}\n\n/** Resolve the effective config for a specific device */\nexport function resolveDeviceConfig(config: InputConfig, deviceId: string): InputConfig {\n let deviceOverride: DeviceConfig | undefined;\n\n if (config.devices[deviceId]) {\n deviceOverride = config.devices[deviceId];\n } else {\n for (const [pattern, cfg] of Object.entries(config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n deviceOverride = cfg;\n break;\n }\n }\n }\n\n if (!deviceOverride) return config;\n\n return {\n ...config,\n routes: deviceOverride.routes ?? config.routes,\n buttonRoutes: deviceOverride.buttonRoutes ?? config.buttonRoutes,\n translateScale: deviceOverride.translateScale ?? config.translateScale,\n rotateScale: deviceOverride.rotateScale ?? config.rotateScale,\n wScale: deviceOverride.wScale ?? config.wScale,\n deadZone: deviceOverride.deadZone ?? config.deadZone,\n dominant: deviceOverride.dominant ?? config.dominant,\n };\n}\n","import type { InputConfig } from \"./config.js\";\n\nexport interface StorageAdapter {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\nconst STORAGE_KEY = \"satmouse:settings\";\n\nfunction getStorage(storage?: StorageAdapter): StorageAdapter | null {\n if (storage) return storage;\n try {\n return globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n}\n\nexport function saveSettings(config: InputConfig, storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, JSON.stringify(config));\n}\n\nexport function clearSettings(storage?: StorageAdapter): void {\n const s = getStorage(storage);\n if (!s) return;\n s.setItem(STORAGE_KEY, \"{}\");\n}\n\nexport function loadSettings(storage?: StorageAdapter): Partial<InputConfig> | null {\n const s = getStorage(storage);\n if (!s) return null;\n const raw = s.getItem(STORAGE_KEY);\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as any;\n // Migrate old single \"scale\" to separate translate/rotate/w scales\n if (parsed.scale != null && parsed.translateScale == null) {\n parsed.translateScale = parsed.scale;\n parsed.rotateScale = parsed.scale;\n parsed.wScale = parsed.scale;\n delete parsed.scale;\n }\n return parsed as Partial<InputConfig>;\n } catch {\n return null;\n }\n}\n","import { TypedEmitter } from \"../core/emitter.js\";\nimport type { SatMouseConnection } from \"../core/connection.js\";\nimport type { SpatialData, ButtonEvent, DeviceInfo, ConnectionState, TransportProtocol } from \"../core/types.js\";\nimport type { InputConfig, DeviceConfig } from \"./config.js\";\nimport { DEFAULT_CONFIG, mergeConfig, resolveDeviceConfig } from \"./config.js\";\nimport { loadSettings, saveSettings, clearSettings, type StorageAdapter } from \"./persistence.js\";\nimport { applyRoutes, buildRoutes, DEFAULT_ROUTES, type AxisRoute } from \"./action-map.js\";\n\nexport interface InputManagerEvents {\n spatialData: (data: SpatialData) => void;\n rawSpatialData: (data: SpatialData) => void;\n buttonEvent: (data: ButtonEvent) => void;\n stateChange: (state: ConnectionState, protocol: TransportProtocol) => void;\n deviceStatus: (event: \"connected\" | \"disconnected\", device: DeviceInfo) => void;\n configChange: (config: InputConfig) => void;\n}\n\nexport interface DeviceWithConfig {\n device: DeviceInfo;\n config: DeviceConfig;\n}\n\nexport class InputManager extends TypedEmitter<InputManagerEvents> {\n private connections: SatMouseConnection[] = [];\n private storage?: StorageAdapter;\n private knownDevices = new Map<string, DeviceInfo>();\n\n private deviceAccumulators = new Map<string, { tx: number; ty: number; tz: number; rx: number; ry: number; rz: number; w: number }>();\n private accDirty = false;\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n\n private _config: InputConfig;\n private _state: ConnectionState = \"disconnected\";\n private _protocol: TransportProtocol = \"none\";\n\n get config(): InputConfig {\n return this._config;\n }\n\n get state(): ConnectionState {\n return this._state;\n }\n\n get protocol(): TransportProtocol {\n return this._protocol;\n }\n\n constructor(config?: Partial<InputConfig>, storage?: StorageAdapter) {\n super();\n this.storage = storage;\n const persisted = loadSettings(storage);\n this._config = mergeConfig(DEFAULT_CONFIG, { ...config, ...persisted });\n this.flushTimer = setInterval(() => this.flushAccumulator(), 16);\n }\n\n addConnection(connection: SatMouseConnection): void {\n this.connections.push(connection);\n this.wireConnection(connection);\n }\n\n /** Reset retry count and reconnect all failed connections. */\n retry(): void {\n for (const c of this.connections) c.retry();\n }\n\n removeConnection(connection: SatMouseConnection): void {\n const idx = this.connections.indexOf(connection);\n if (idx !== -1) this.connections.splice(idx, 1);\n connection.removeAllListeners();\n }\n\n async connect(): Promise<void> {\n await Promise.all(this.connections.map((c) => c.connect()));\n }\n\n disconnect(): void {\n for (const c of this.connections) c.disconnect();\n if (this.flushTimer) { clearInterval(this.flushTimer); this.flushTimer = null; }\n }\n\n async fetchDeviceInfo(): Promise<DeviceInfo[]> {\n const results = await Promise.all(this.connections.map((c) => c.fetchDeviceInfo()));\n const devices = results.flat();\n for (const d of devices) this.knownDevices.set(d.id, d);\n return devices;\n }\n\n getDevicesWithConfig(): DeviceWithConfig[] {\n return Array.from(this.knownDevices.values()).map((device) => ({\n device,\n config: this.getDeviceConfig(device.id),\n }));\n }\n\n getDeviceConfig(deviceId: string): DeviceConfig {\n const resolved = resolveDeviceConfig(this._config, deviceId);\n return {\n routes: resolved.routes,\n buttonRoutes: resolved.buttonRoutes,\n translateScale: resolved.translateScale,\n rotateScale: resolved.rotateScale,\n wScale: resolved.wScale,\n deadZone: resolved.deadZone,\n dominant: resolved.dominant,\n };\n }\n\n updateConfig(partial: Partial<InputConfig>, persist = true): void {\n this._config = mergeConfig(this._config, partial);\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n updateDeviceConfig(deviceId: string, partial: DeviceConfig, persist = true): void {\n const existing = this._config.devices[deviceId] ?? {};\n this._config = mergeConfig(this._config, {\n devices: { [deviceId]: { ...existing, ...partial } },\n });\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetDeviceConfig(deviceId: string, persist = true): void {\n const { [deviceId]: _, ...rest } = this._config.devices;\n this._config = { ...this._config, devices: rest };\n if (persist) saveSettings(this._config, this.storage);\n this.emit(\"configChange\", this._config);\n }\n\n resetAllConfig(): void {\n clearSettings(this.storage);\n this._config = { ...DEFAULT_CONFIG };\n this.emit(\"configChange\", this._config);\n }\n\n onSpatialData(callback: (data: SpatialData) => void): () => void {\n this.on(\"spatialData\", callback);\n return () => this.off(\"spatialData\", callback);\n }\n\n onButtonEvent(callback: (data: ButtonEvent) => void): () => void {\n this.on(\"buttonEvent\", callback);\n return () => this.off(\"buttonEvent\", callback);\n }\n\n private wireConnection(connection: SatMouseConnection): void {\n connection.on(\"spatialData\", (raw) => {\n this.emit(\"rawSpatialData\", raw);\n\n const id = raw.deviceId ?? \"_default\";\n const processed = this.processPerDevice(raw, id);\n\n this.deviceAccumulators.set(id, {\n tx: processed.translation.x,\n ty: processed.translation.y,\n tz: processed.translation.z,\n rx: processed.rotation.x,\n ry: processed.rotation.y,\n rz: processed.rotation.z,\n w: processed.w ?? 0,\n });\n this.accDirty = true;\n });\n\n connection.on(\"buttonEvent\", (event) => {\n // Check all device configs for matching button routes\n this.dispatchButtonKeys(event);\n this.emit(\"buttonEvent\", event);\n });\n connection.on(\"stateChange\", (state, proto) => {\n this._state = state;\n this._protocol = proto;\n this.emit(\"stateChange\", state, proto);\n });\n connection.on(\"deviceStatus\", (event, device) => {\n if (event === \"connected\") this.knownDevices.set(device.id, device);\n else this.knownDevices.delete(device.id);\n this.emit(\"deviceStatus\", event, device);\n });\n }\n\n private flushAccumulator(): void {\n if (!this.accDirty) return;\n\n const merged = { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0, w: 0 };\n for (const acc of this.deviceAccumulators.values()) {\n merged.tx += acc.tx;\n merged.ty += acc.ty;\n merged.tz += acc.tz;\n merged.rx += acc.rx;\n merged.ry += acc.ry;\n merged.rz += acc.rz;\n merged.w += acc.w;\n }\n\n this.deviceAccumulators.clear();\n this.accDirty = false;\n\n let data: SpatialData = {\n translation: { x: merged.tx, y: merged.ty, z: merged.tz },\n rotation: { x: merged.rx, y: merged.ry, z: merged.rz },\n w: merged.w || undefined,\n timestamp: performance.now() * 1000,\n };\n\n if (this._config.lockPosition) {\n data = { ...data, translation: { x: 0, y: 0, z: 0 } };\n }\n if (this._config.lockRotation) {\n data = { ...data, rotation: { x: 0, y: 0, z: 0 } };\n }\n\n this.emit(\"spatialData\", data);\n }\n\n /** Per-device: deadZone → dominant → routes (flip + scale + remap in one pass) */\n private processPerDevice(raw: SpatialData, deviceId: string): SpatialData {\n const cfg = resolveDeviceConfig(this._config, deviceId);\n let data = raw;\n\n // Dead zone\n if (cfg.deadZone > 0) {\n const dz = (v: number) => (Math.abs(v) < cfg.deadZone ? 0 : v);\n data = {\n ...data,\n translation: { x: dz(data.translation.x), y: dz(data.translation.y), z: dz(data.translation.z) },\n rotation: { x: dz(data.rotation.x), y: dz(data.rotation.y), z: dz(data.rotation.z) },\n };\n }\n\n // Dominant axis\n if (cfg.dominant) {\n const axes = [\n { g: \"t\" as const, k: \"x\" as const, v: Math.abs(data.translation.x) },\n { g: \"t\" as const, k: \"y\" as const, v: Math.abs(data.translation.y) },\n { g: \"t\" as const, k: \"z\" as const, v: Math.abs(data.translation.z) },\n { g: \"r\" as const, k: \"x\" as const, v: Math.abs(data.rotation.x) },\n { g: \"r\" as const, k: \"y\" as const, v: Math.abs(data.rotation.y) },\n { g: \"r\" as const, k: \"z\" as const, v: Math.abs(data.rotation.z) },\n ];\n const max = axes.reduce((a, b) => (b.v > a.v ? b : a));\n const t = { x: 0, y: 0, z: 0 };\n const r = { x: 0, y: 0, z: 0 };\n if (max.g === \"t\") t[max.k] = data.translation[max.k];\n else r[max.k] = data.rotation[max.k];\n data = { ...data, translation: t, rotation: r };\n }\n\n // Routes: flip + scale + remap in one pass\n // Use device-specific routes if configured, otherwise build from device axes metadata\n const device = this.knownDevices.get(deviceId);\n const deviceRoutes = this.resolveRoutes(deviceId, device);\n data = applyRoutes(data, deviceRoutes, cfg.translateScale, cfg.rotateScale, cfg.wScale);\n\n return data;\n }\n\n /** Get the effective routes for a device: device config override > device axes metadata > global default */\n private resolveRoutes(deviceId: string, device?: DeviceInfo): AxisRoute[] {\n // Check for explicit device config (exact match or pattern)\n const devCfg = this._config.devices[deviceId];\n if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;\n\n // Check pattern matches\n for (const [pattern, cfg] of Object.entries(this._config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;\n }\n }\n\n // Build from device axes metadata\n if (device?.axes) return buildRoutes(device.axes);\n\n // Global fallback\n return DEFAULT_ROUTES;\n }\n\n /** Dispatch KeyboardEvents for button routes matching this button event */\n private dispatchButtonKeys(event: ButtonEvent): void {\n if (typeof document === \"undefined\") return;\n\n // Collect all button routes from all device configs + global\n const allRoutes = this.collectButtonRoutes();\n for (const route of allRoutes) {\n if (route.button === event.button) {\n document.dispatchEvent(new KeyboardEvent(\n event.pressed ? \"keydown\" : \"keyup\",\n { key: route.key, code: route.code ?? \"\", bubbles: true },\n ));\n }\n }\n }\n\n /** Gather all button routes from global config + all device configs */\n private collectButtonRoutes(): import(\"./config.js\").ButtonRoute[] {\n const routes = [...this._config.buttonRoutes];\n for (const devCfg of Object.values(this._config.devices)) {\n if (devCfg.buttonRoutes) routes.push(...devCfg.buttonRoutes);\n }\n return routes;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kelnishi/satmouse-client",
3
- "version": "0.12.0",
3
+ "version": "0.12.4",
4
4
  "description": "Client SDK for SatMouse 6DOF spatial input bridge",
5
5
  "type": "module",
6
6
  "sideEffects": ["./src/elements/*.ts", "./dist/elements/*"],