@mywallpaper/addon-sdk 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.mts +147 -2
- package/dist/index.d.ts +147 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/manifest.d.mts +147 -2
- package/dist/manifest.d.ts +147 -2
- package/dist/manifest.js.map +1 -1
- package/dist/manifest.mjs.map +1 -1
- package/package.json +1 -1
- package/src/runtime/addon-client.js +138 -0
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/manifest.ts","../src/utils.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @mywallpaper/addon-sdk - Manifest Schema & Validation\n *\n * Defines the addon manifest format (manifest.json) and provides\n * Zod-based validation for type safety at runtime.\n *\n * @example\n * ```typescript\n * import { validateManifest, type AddonManifest } from '@mywallpaper/addon-sdk/manifest'\n *\n * const manifest: AddonManifest = {\n * name: 'My Addon',\n * version: '1.0.0',\n * sdkVersion: '2.3.0',\n * description: 'A cool addon',\n * settings: {\n * primaryColor: { type: 'color', default: '#ffffff', label: 'Primary Color' }\n * }\n * }\n *\n * // Validate at runtime\n * const result = validateManifest(manifest)\n * if (!result.success) {\n * console.error('Invalid manifest:', result.errors)\n * }\n * ```\n */\n\nimport type { SystemEventType, PermissionType, OAuthProvider } from './types'\n\n// =============================================================================\n// SETTING TYPES\n// =============================================================================\n\n/**\n * Available setting types for addon configuration.\n */\nexport type SettingType =\n | 'string' // Text input\n | 'number' // Numeric input\n | 'boolean' // Checkbox/toggle\n | 'color' // Color picker\n | 'select' // Dropdown selection\n | 'range' // Slider\n | 'image' // Image upload\n | 'video' // Video upload\n | 'audio' // Audio upload (mp3, wav, ogg, etc.)\n | 'file' // Generic file upload (images + videos + audio)\n | 'section' // Visual grouping (no value)\n | 'textarea' // Multi-line text\n | 'radio' // Radio buttons\n | 'gradient' // Gradient picker\n | 'vector2' // 2D vector (x, y)\n | 'button' // Action button (no value)\n | 'multi-select' // Multiple selection\n\n/**\n * Definition for a single addon setting.\n *\n * @example\n * ```typescript\n * const colorSetting: SettingDefinition = {\n * type: 'color',\n * label: 'Background Color',\n * description: 'Choose a background color',\n * default: '#000000'\n * }\n *\n * const speedSetting: SettingDefinition = {\n * type: 'range',\n * label: 'Animation Speed',\n * min: 0.1,\n * max: 10,\n * step: 0.1,\n * default: 1\n * }\n * ```\n */\nexport interface SettingDefinition {\n /** Setting type determines the UI control */\n type: SettingType\n\n /** Human-readable label */\n label?: string\n\n /** Help text shown below the control */\n description?: string\n\n /** Default value (type depends on setting type) */\n default?: unknown\n\n // Select/Radio/Multi-select options\n /** Options for select, radio, multi-select types */\n options?: Array<{ value: string; label: string }>\n\n // Range-specific\n /** Minimum value for range type */\n min?: number\n /** Maximum value for range type */\n max?: number\n /** Step increment for range type */\n step?: number\n\n // Button-specific\n /** Label text on button */\n buttonLabel?: string\n\n // Vector-specific\n /** Axis labels for vector types, e.g., ['X', 'Y'] */\n axisLabels?: [string, string] | [string, string, string]\n\n // Multi-select specific\n /** Maximum number of selections */\n maxItems?: number\n\n // Conditional visibility\n /** Only show if another setting has a specific value */\n showIf?: {\n setting: string\n equals: unknown\n }\n}\n\n// =============================================================================\n// MANIFEST SCHEMA\n// =============================================================================\n\n/**\n * Default layout configuration for addon positioning.\n */\nexport interface AddonDefaultLayout {\n /** X position as percentage of viewport width (0-100) */\n xPercent?: number\n /** Y position as percentage of viewport height (0-100) */\n yPercent?: number\n /** Width as percentage of viewport width (0-100) */\n widthPercent?: number\n /** Height as percentage of viewport height (0-100) */\n heightPercent?: number\n /** Rotation in degrees */\n rotation?: number\n}\n\n/**\n * The complete addon manifest schema.\n * This defines your addon's identity, settings, and capabilities.\n *\n * @example\n * ```json\n * {\n * \"name\": \"Weather Widget\",\n * \"version\": \"1.2.0\",\n * \"description\": \"Displays current weather conditions\",\n * \"author\": \"Jane Developer\",\n * \"categories\": [\"utilities\", \"weather\"],\n * \"capabilities\": {\n * \"hotReload\": true,\n * \"systemEvents\": [\"viewport:resize\", \"theme:change\"]\n * },\n * \"permissions\": {\n * \"storage\": { \"quota\": 512 },\n * \"network\": { \"domains\": [\"api.openweathermap.org\"] }\n * },\n * \"settings\": {\n * \"apiKey\": {\n * \"type\": \"string\",\n * \"label\": \"API Key\",\n * \"description\": \"Get your key at openweathermap.org\"\n * },\n * \"unit\": {\n * \"type\": \"select\",\n * \"label\": \"Temperature Unit\",\n * \"default\": \"celsius\",\n * \"options\": [\n * { \"value\": \"celsius\", \"label\": \"Celsius\" },\n * { \"value\": \"fahrenheit\", \"label\": \"Fahrenheit\" }\n * ]\n * }\n * }\n * }\n * ```\n */\nexport interface AddonManifest {\n // ---------------------------------------------------------------------------\n // REQUIRED FIELDS\n // ---------------------------------------------------------------------------\n\n /** Addon name (displayed in UI) */\n name: string\n\n /** Semantic version (e.g., \"1.0.0\") */\n version: string\n\n /**\n * SDK version this addon was built for.\n * Must be a valid semver (e.g., \"2.3.0\").\n * Host uses this to inject the correct client-side SDK.\n */\n sdkVersion: string\n\n // ---------------------------------------------------------------------------\n // OPTIONAL METADATA\n // ---------------------------------------------------------------------------\n\n /** Short description of the addon */\n description?: string\n\n /** Author name or organization */\n author?: string\n\n /** Addon type/category for filtering */\n type?: string\n\n /** Categories for discoverability */\n categories?: string[]\n\n /** License (e.g., \"MIT\", \"Apache-2.0\") */\n license?: string\n\n /** Homepage or documentation URL */\n homepage?: string\n\n /** Repository URL */\n repository?: string\n\n // ---------------------------------------------------------------------------\n // SETTINGS\n // ---------------------------------------------------------------------------\n\n /**\n * User-configurable settings.\n * Key is the setting ID, value is the definition.\n */\n settings?: Record<string, SettingDefinition>\n\n // ---------------------------------------------------------------------------\n // CAPABILITIES\n // ---------------------------------------------------------------------------\n\n /**\n * Addon capabilities and event subscriptions.\n */\n capabilities?: {\n /** Supports settings changes without full reload */\n hotReload?: boolean\n /** System events the addon wants to receive */\n systemEvents?: SystemEventType[]\n }\n\n // ---------------------------------------------------------------------------\n // PERMISSIONS\n // ---------------------------------------------------------------------------\n\n /**\n * Permissions the addon will request.\n * Declaring them here improves UX by showing upfront.\n */\n permissions?: {\n /** Storage permission with quota in KB */\n storage?: { quota: number }\n /** CPU usage limit */\n cpu?: { limit: 'low' | 'medium' | 'high' }\n /** Network access with allowed domains */\n network?: { domains: string[] }\n /** Audio playback permission */\n audio?: boolean\n /** Notification permission */\n notifications?: boolean\n /**\n * File access permission for uploaded media files.\n * When enabled, the addon can receive uploaded files (video, audio, images)\n * via secure blob transfer for playback.\n *\n * This is required for addons that play user-uploaded media content.\n */\n fileAccess?: {\n /** User-friendly reason why this permission is needed */\n reason: string\n }\n /**\n * Same-origin permission for blob URL support.\n * Required for addons that handle large local files (videos, audio).\n *\n * ⚠️ SECURITY WARNING: This allows the addon to access:\n * - localStorage/sessionStorage of the parent origin\n * - Cookies of the parent domain\n * - IndexedDB of the parent origin\n *\n * Only grant to trusted addons!\n */\n sameOrigin?: {\n /** User-friendly reason why this permission is needed */\n reason: string\n }\n }\n\n // ---------------------------------------------------------------------------\n // LAYOUT\n // ---------------------------------------------------------------------------\n\n /**\n * Default layout for automatic positioning.\n * Used when addon is first added to a wallpaper.\n */\n defaultLayout?: AddonDefaultLayout\n\n // ---------------------------------------------------------------------------\n // FUTURE FIELDS\n // ---------------------------------------------------------------------------\n\n /**\n * OAuth providers and scopes for authenticated addons.\n *\n * Declare the OAuth providers your addon needs and the scopes it requires.\n * Scopes are requested incrementally - users can connect with basic scopes\n * first, and your addon can request additional scopes when needed.\n *\n * @example\n * ```json\n * {\n * \"permissions\": {\n * \"oauth\": {\n * \"required\": [\n * { \"provider\": \"github\", \"scopes\": [\"read:user\"] }\n * ],\n * \"optional\": [\n * { \"provider\": \"github\", \"scopes\": [\"repo\"] }\n * ]\n * }\n * }\n * }\n * ```\n */\n oauth?: {\n /** OAuth providers required for the addon to function */\n required?: Array<{\n provider: OAuthProvider\n scopes: string[]\n /** Reason shown to user when requesting this permission */\n reason?: string\n }>\n /** OAuth providers that enhance functionality but aren't required */\n optional?: Array<{\n provider: OAuthProvider\n scopes: string[]\n /** Reason shown to user when requesting this permission */\n reason?: string\n }>\n }\n}\n\n// =============================================================================\n// VALIDATION\n// =============================================================================\n\n/**\n * Validation result type.\n */\nexport interface ValidationResult {\n success: boolean\n errors?: string[]\n manifest?: AddonManifest\n}\n\n/**\n * Validates an addon manifest object.\n *\n * @param input - The manifest object to validate\n * @returns ValidationResult with success status and any errors\n *\n * @example\n * ```typescript\n * const result = validateManifest(myManifest)\n * if (!result.success) {\n * result.errors?.forEach(err => console.error(err))\n * }\n * ```\n */\nexport function validateManifest(input: unknown): ValidationResult {\n const errors: string[] = []\n\n if (!input || typeof input !== 'object') {\n return { success: false, errors: ['Manifest must be an object'] }\n }\n\n const manifest = input as Record<string, unknown>\n\n // Required fields\n if (typeof manifest.name !== 'string' || manifest.name.trim() === '') {\n errors.push('name: Required and must be a non-empty string')\n }\n\n if (typeof manifest.version !== 'string' || !/^\\d+\\.\\d+\\.\\d+/.test(manifest.version)) {\n errors.push('version: Required and must be a valid semver (e.g., \"1.0.0\")')\n }\n\n if (typeof manifest.sdkVersion !== 'string' || !/^\\d+\\.\\d+\\.\\d+/.test(manifest.sdkVersion)) {\n errors.push('sdkVersion: Required and must be a valid semver (e.g., \"2.2.0\")')\n }\n\n // Optional string fields\n const optionalStrings = ['description', 'author', 'type', 'license', 'homepage', 'repository']\n for (const field of optionalStrings) {\n if (manifest[field] !== undefined && typeof manifest[field] !== 'string') {\n errors.push(`${field}: Must be a string`)\n }\n }\n\n // Categories\n if (manifest.categories !== undefined) {\n if (!Array.isArray(manifest.categories)) {\n errors.push('categories: Must be an array of strings')\n } else if (!manifest.categories.every(c => typeof c === 'string')) {\n errors.push('categories: All items must be strings')\n }\n }\n\n // Settings validation\n if (manifest.settings !== undefined) {\n if (typeof manifest.settings !== 'object' || manifest.settings === null) {\n errors.push('settings: Must be an object')\n } else {\n const settings = manifest.settings as Record<string, unknown>\n for (const [key, value] of Object.entries(settings)) {\n if (typeof value !== 'object' || value === null) {\n errors.push(`settings.${key}: Must be an object`)\n continue\n }\n\n const setting = value as Record<string, unknown>\n const validTypes: SettingType[] = [\n 'string', 'number', 'boolean', 'color', 'select', 'range',\n 'image', 'video', 'audio', 'file', 'section', 'textarea', 'radio', 'gradient', 'vector2',\n 'button', 'multi-select'\n ]\n\n if (!validTypes.includes(setting.type as SettingType)) {\n errors.push(`settings.${key}.type: Must be one of: ${validTypes.join(', ')}`)\n }\n\n // Type-specific validation\n if (['select', 'radio', 'multi-select'].includes(setting.type as string)) {\n if (!Array.isArray(setting.options) || setting.options.length === 0) {\n errors.push(`settings.${key}.options: Required for ${setting.type} type`)\n }\n }\n\n if (setting.type === 'range') {\n if (typeof setting.min !== 'number' || typeof setting.max !== 'number') {\n errors.push(`settings.${key}: range type requires min and max`)\n }\n }\n }\n }\n }\n\n // Capabilities validation\n if (manifest.capabilities !== undefined) {\n if (typeof manifest.capabilities !== 'object' || manifest.capabilities === null) {\n errors.push('capabilities: Must be an object')\n } else {\n const caps = manifest.capabilities as Record<string, unknown>\n\n if (caps.hotReload !== undefined && typeof caps.hotReload !== 'boolean') {\n errors.push('capabilities.hotReload: Must be a boolean')\n }\n\n if (caps.systemEvents !== undefined) {\n const validEvents: SystemEventType[] = [\n 'viewport:resize', 'theme:change', 'visibility:change',\n 'layer:focus', 'layer:blur', 'app:idle', 'app:active'\n ]\n\n if (!Array.isArray(caps.systemEvents)) {\n errors.push('capabilities.systemEvents: Must be an array')\n } else {\n for (const event of caps.systemEvents) {\n if (!validEvents.includes(event)) {\n errors.push(`capabilities.systemEvents: Invalid event \"${event}\"`)\n }\n }\n }\n }\n }\n }\n\n // Permissions validation\n if (manifest.permissions !== undefined) {\n if (typeof manifest.permissions !== 'object' || manifest.permissions === null) {\n errors.push('permissions: Must be an object')\n } else {\n const perms = manifest.permissions as Record<string, unknown>\n\n if (perms.storage !== undefined) {\n const storage = perms.storage as Record<string, unknown>\n if (typeof storage?.quota !== 'number' || storage.quota <= 0) {\n errors.push('permissions.storage.quota: Must be a positive number')\n }\n }\n\n if (perms.cpu !== undefined) {\n const cpu = perms.cpu as Record<string, unknown>\n if (!['low', 'medium', 'high'].includes(cpu?.limit as string)) {\n errors.push('permissions.cpu.limit: Must be low, medium, or high')\n }\n }\n\n if (perms.network !== undefined) {\n const network = perms.network as Record<string, unknown>\n if (!Array.isArray(network?.domains)) {\n errors.push('permissions.network.domains: Must be an array of domain strings')\n }\n }\n }\n }\n\n // Default layout validation\n if (manifest.defaultLayout !== undefined) {\n if (typeof manifest.defaultLayout !== 'object' || manifest.defaultLayout === null) {\n errors.push('defaultLayout: Must be an object')\n } else {\n const layout = manifest.defaultLayout as Record<string, unknown>\n const numFields = ['xPercent', 'yPercent', 'widthPercent', 'heightPercent', 'rotation']\n for (const field of numFields) {\n if (layout[field] !== undefined && typeof layout[field] !== 'number') {\n errors.push(`defaultLayout.${field}: Must be a number`)\n }\n }\n }\n }\n\n if (errors.length > 0) {\n return { success: false, errors }\n }\n\n return { success: true, manifest: manifest as unknown as AddonManifest }\n}\n\n/**\n * Type guard to check if an object is a valid AddonManifest.\n *\n * @param input - Object to check\n * @returns True if input is a valid AddonManifest\n */\nexport function isValidManifest(input: unknown): input is AddonManifest {\n return validateManifest(input).success\n}\n\n// =============================================================================\n// UTILITY FUNCTIONS\n// =============================================================================\n\n/**\n * Check if manifest declares hot-reload capability.\n */\nexport function supportsHotReload(manifest: AddonManifest): boolean {\n return manifest.capabilities?.hotReload === true\n}\n\n/**\n * Get system events the addon subscribes to.\n */\nexport function getSubscribedEvents(manifest: AddonManifest): SystemEventType[] {\n return manifest.capabilities?.systemEvents ?? []\n}\n\n/**\n * Get required permissions from manifest.\n */\nexport function getRequiredPermissions(manifest: AddonManifest): PermissionType[] {\n const permissions: PermissionType[] = []\n\n if (manifest.permissions?.storage) permissions.push('storage')\n if (manifest.permissions?.cpu) permissions.push('cpu-high')\n if (manifest.permissions?.network) permissions.push('network')\n if (manifest.permissions?.audio) permissions.push('audio')\n if (manifest.permissions?.notifications) permissions.push('notifications')\n\n return permissions\n}\n","/**\n * @mywallpaper/addon-sdk - Utility Functions\n *\n * Helper utilities for addon development.\n */\n\nimport type { AddonManifest, SettingDefinition } from './manifest'\n\n// =============================================================================\n// CONFIG UTILITIES\n// =============================================================================\n\n/**\n * Creates a default configuration object from manifest settings.\n *\n * @param manifest - Addon manifest with settings definitions\n * @returns Object with all setting keys and their default values\n *\n * @example\n * ```typescript\n * const manifest = {\n * name: 'My Addon',\n * version: '1.0.0',\n * settings: {\n * color: { type: 'color', default: '#ff0000' },\n * speed: { type: 'range', default: 1, min: 0, max: 10 }\n * }\n * }\n *\n * const defaults = createDefaultConfig(manifest)\n * // { color: '#ff0000', speed: 1 }\n * ```\n */\nexport function createDefaultConfig(manifest: AddonManifest): Record<string, unknown> {\n const config: Record<string, unknown> = {}\n\n if (!manifest.settings) return config\n\n for (const [key, setting] of Object.entries(manifest.settings)) {\n if (setting.type === 'section' || setting.type === 'button') {\n // Skip non-value settings\n continue\n }\n config[key] = setting.default ?? getTypeDefault(setting)\n }\n\n return config\n}\n\n/**\n * Get type-appropriate default value when none specified.\n */\nfunction getTypeDefault(setting: SettingDefinition): unknown {\n switch (setting.type) {\n case 'string':\n case 'textarea':\n return ''\n case 'number':\n return 0\n case 'boolean':\n return false\n case 'color':\n return '#000000'\n case 'select':\n case 'radio':\n return setting.options?.[0]?.value ?? ''\n case 'range':\n return setting.min ?? 0\n case 'image':\n return null\n case 'gradient':\n return { stops: [{ color: '#000000', position: 0 }, { color: '#ffffff', position: 100 }] }\n case 'vector2':\n return { x: 0, y: 0 }\n case 'multi-select':\n return []\n default:\n return null\n }\n}\n\n/**\n * Merges user config with defaults, ensuring all keys exist.\n *\n * @param defaults - Default configuration\n * @param userConfig - User-provided configuration (may be partial)\n * @returns Complete configuration with user values taking precedence\n *\n * @example\n * ```typescript\n * const defaults = { color: '#ff0000', speed: 1 }\n * const user = { color: '#00ff00' }\n *\n * const config = mergeConfigs(defaults, user)\n * // { color: '#00ff00', speed: 1 }\n * ```\n */\nexport function mergeConfigs(\n defaults: Record<string, unknown>,\n userConfig: Record<string, unknown>\n): Record<string, unknown> {\n return { ...defaults, ...userConfig }\n}\n\n// =============================================================================\n// VERSION UTILITIES\n// =============================================================================\n\n/**\n * Semantic version comparison result.\n */\nexport type VersionComparison = -1 | 0 | 1\n\n/**\n * Compare two semantic versions.\n *\n * @param a - First version string\n * @param b - Second version string\n * @returns -1 if a < b, 0 if a === b, 1 if a > b\n *\n * @example\n * ```typescript\n * compareVersions('1.0.0', '1.0.1') // -1\n * compareVersions('2.0.0', '1.9.9') // 1\n * compareVersions('1.0.0', '1.0.0') // 0\n * ```\n */\nexport function compareVersions(a: string, b: string): VersionComparison {\n const parseVersion = (v: string): number[] => {\n return v.split('.').map(n => parseInt(n, 10) || 0)\n }\n\n const partsA = parseVersion(a)\n const partsB = parseVersion(b)\n\n for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {\n const numA = partsA[i] ?? 0\n const numB = partsB[i] ?? 0\n\n if (numA < numB) return -1\n if (numA > numB) return 1\n }\n\n return 0\n}\n\n/**\n * Check if version satisfies a minimum requirement.\n *\n * @param version - Version to check\n * @param minimum - Minimum required version\n * @returns True if version >= minimum\n */\nexport function satisfiesMinVersion(version: string, minimum: string): boolean {\n return compareVersions(version, minimum) >= 0\n}\n\n// =============================================================================\n// STORAGE UTILITIES\n// =============================================================================\n\n/**\n * Calculate the byte size of a value when JSON serialized.\n * Useful for quota tracking.\n *\n * @param value - Value to measure\n * @returns Size in bytes\n */\nexport function getStorageSize(value: unknown): number {\n try {\n return new Blob([JSON.stringify(value)]).size\n } catch {\n return 0\n }\n}\n\n/**\n * Format bytes as human-readable string.\n *\n * @param bytes - Number of bytes\n * @returns Formatted string (e.g., \"1.5 KB\", \"2.3 MB\")\n */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B'\n\n const units = ['B', 'KB', 'MB', 'GB']\n const k = 1024\n const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k))\n\n return `${(bytes / Math.pow(k, i)).toFixed(i > 0 ? 1 : 0)} ${units[i]}`\n}\n\n// =============================================================================\n// TYPE GUARDS\n// =============================================================================\n\n/**\n * Check if a value is a plain object.\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/**\n * Check if a value is a valid color hex string.\n */\nexport function isValidColor(value: unknown): value is string {\n if (typeof value !== 'string') return false\n return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(value)\n}\n\n// =============================================================================\n// DEBOUNCE/THROTTLE\n// =============================================================================\n\n/**\n * Debounce a function - only call after delay with no new calls.\n *\n * @param fn - Function to debounce\n * @param delayMs - Delay in milliseconds\n * @returns Debounced function\n *\n * @example\n * ```typescript\n * const save = debounce((data) => {\n * localStorage.setItem('data', JSON.stringify(data))\n * }, 1000)\n *\n * // Rapid calls only trigger one save after 1s\n * save({ a: 1 })\n * save({ a: 2 })\n * save({ a: 3 }) // Only this one runs (after 1s)\n * ```\n */\nexport function debounce<T extends (...args: unknown[]) => void>(\n fn: T,\n delayMs: number\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n\n return (...args: Parameters<T>) => {\n if (timeoutId) clearTimeout(timeoutId)\n timeoutId = setTimeout(() => fn(...args), delayMs)\n }\n}\n\n/**\n * Throttle a function - call at most once per interval.\n *\n * @param fn - Function to throttle\n * @param intervalMs - Minimum interval between calls\n * @returns Throttled function\n */\nexport function throttle<T extends (...args: unknown[]) => void>(\n fn: T,\n intervalMs: number\n): (...args: Parameters<T>) => void {\n let lastCall = 0\n\n return (...args: Parameters<T>) => {\n const now = Date.now()\n if (now - lastCall >= intervalMs) {\n lastCall = now\n fn(...args)\n }\n }\n}\n\n// =============================================================================\n// EVENT HELPERS\n// =============================================================================\n\n/**\n * Create a one-time event listener that auto-removes after first call.\n *\n * @param element - DOM element or window\n * @param event - Event name\n * @param handler - Event handler\n */\nexport function once(\n element: EventTarget,\n event: string,\n handler: EventListener\n): void {\n const wrappedHandler: EventListener = (e) => {\n element.removeEventListener(event, wrappedHandler)\n handler(e)\n }\n element.addEventListener(event, wrappedHandler)\n}\n","/**\n * @mywallpaper/addon-sdk\n *\n * Official SDK for building MyWallpaper addons.\n *\n * @packageDocumentation\n *\n * ## Installation\n *\n * ```bash\n * npm install @mywallpaper/addon-sdk\n * ```\n *\n * ## Quick Start\n *\n * ```typescript\n * // Your addon's main file\n * import type { MyWallpaperAPI } from '@mywallpaper/addon-sdk'\n *\n * // The API is automatically available on window.MyWallpaper\n * const api = window.MyWallpaper\n *\n * // Access configuration\n * const { backgroundColor, animationSpeed } = api.config\n *\n * // React to setting changes (hot-reload)\n * api.onSettingsChange((settings, changedKeys) => {\n * if (changedKeys.includes('backgroundColor')) {\n * document.body.style.background = settings.backgroundColor as string\n * }\n * })\n *\n * // Subscribe to system events\n * api.onEvent('viewport:resize', ({ width, height }) => {\n * canvas.width = width\n * canvas.height = height\n * })\n *\n * // Signal addon is ready\n * api.ready({\n * capabilities: ['hot-reload'],\n * subscribedEvents: ['viewport:resize']\n * })\n *\n * // After visual rendering is complete\n * await loadImages()\n * render()\n * api.renderComplete()\n * ```\n *\n * ## Manifest Validation\n *\n * ```typescript\n * import { validateManifest, type AddonManifest } from '@mywallpaper/addon-sdk/manifest'\n *\n * const manifest: AddonManifest = {\n * name: 'My Addon',\n * version: '1.0.0',\n * settings: {\n * color: { type: 'color', default: '#ffffff' }\n * }\n * }\n *\n * const result = validateManifest(manifest)\n * if (!result.success) {\n * console.error(result.errors)\n * }\n * ```\n *\n * @module\n */\n\n// =============================================================================\n// TYPE EXPORTS\n// =============================================================================\n\nexport type {\n // Main API\n MyWallpaperAPI,\n StorageAPI,\n NetworkAPI,\n NetworkResponse,\n\n // OAuth API\n OAuthAPI,\n OAuthResponse,\n OAuthScopesError,\n OAuthProvider,\n OAuthPermissionType,\n\n // File Access API\n FileAccessAPI,\n FileReference,\n FileAccessResult,\n\n // Events\n SystemEventType,\n SystemEventData,\n\n // Capabilities & Permissions\n AddonCapability,\n PermissionType,\n PermissionConstraints,\n\n // Callbacks\n SettingsCallback,\n EventCallback,\n ReadyOptions,\n\n // Lifecycle\n LifecycleEvent,\n\n // Utility types\n AddonValues,\n} from './types'\n\n// =============================================================================\n// MANIFEST EXPORTS\n// =============================================================================\n\nexport type {\n // Manifest types\n AddonManifest,\n SettingDefinition,\n SettingType,\n AddonDefaultLayout,\n ValidationResult,\n} from './manifest'\n\nexport {\n // Validation\n validateManifest,\n isValidManifest,\n\n // Manifest utilities\n supportsHotReload,\n getSubscribedEvents,\n getRequiredPermissions,\n} from './manifest'\n\n// =============================================================================\n// UTILITY EXPORTS\n// =============================================================================\n\nexport {\n // Config utilities\n createDefaultConfig,\n mergeConfigs,\n\n // Version utilities\n compareVersions,\n satisfiesMinVersion,\n\n // Storage utilities\n getStorageSize,\n formatBytes,\n\n // Type guards\n isPlainObject,\n isValidColor,\n\n // Function utilities\n debounce,\n throttle,\n once,\n} from './utils'\n\nexport type { VersionComparison } from './utils'\n\n// =============================================================================\n// SDK VERSION\n// =============================================================================\n\n/**\n * Current SDK version.\n */\nexport const SDK_VERSION = '2.3.0'\n\n/**\n * Minimum compatible host version.\n */\nexport const MIN_HOST_VERSION = '2.0.0'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/manifest.ts","../src/utils.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @mywallpaper/addon-sdk - Manifest Schema & Validation\n *\n * Defines the addon manifest format (manifest.json) and provides\n * Zod-based validation for type safety at runtime.\n *\n * @example\n * ```typescript\n * import { validateManifest, type AddonManifest } from '@mywallpaper/addon-sdk/manifest'\n *\n * const manifest: AddonManifest = {\n * name: 'My Addon',\n * version: '1.0.0',\n * sdkVersion: '2.7.0',\n * description: 'A cool addon',\n * settings: {\n * primaryColor: { type: 'color', default: '#ffffff', label: 'Primary Color' }\n * }\n * }\n *\n * // Validate at runtime\n * const result = validateManifest(manifest)\n * if (!result.success) {\n * console.error('Invalid manifest:', result.errors)\n * }\n * ```\n */\n\nimport type { SystemEventType, PermissionType, OAuthProvider } from './types'\n\n// =============================================================================\n// SETTING TYPES\n// =============================================================================\n\n/**\n * Available setting types for addon configuration.\n */\nexport type SettingType =\n | 'string' // Text input\n | 'number' // Numeric input\n | 'boolean' // Checkbox/toggle\n | 'color' // Color picker\n | 'select' // Dropdown selection\n | 'range' // Slider\n | 'image' // Image upload\n | 'video' // Video upload\n | 'audio' // Audio upload (mp3, wav, ogg, etc.)\n | 'file' // Generic file upload (images + videos + audio)\n | 'section' // Visual grouping (no value)\n | 'textarea' // Multi-line text\n | 'radio' // Radio buttons\n | 'gradient' // Gradient picker\n | 'vector2' // 2D vector (x, y)\n | 'button' // Action button (no value)\n | 'multi-select' // Multiple selection\n\n/**\n * Definition for a single addon setting.\n *\n * @example\n * ```typescript\n * const colorSetting: SettingDefinition = {\n * type: 'color',\n * label: 'Background Color',\n * description: 'Choose a background color',\n * default: '#000000'\n * }\n *\n * const speedSetting: SettingDefinition = {\n * type: 'range',\n * label: 'Animation Speed',\n * min: 0.1,\n * max: 10,\n * step: 0.1,\n * default: 1\n * }\n * ```\n */\nexport interface SettingDefinition {\n /** Setting type determines the UI control */\n type: SettingType\n\n /** Human-readable label */\n label?: string\n\n /** Help text shown below the control */\n description?: string\n\n /** Default value (type depends on setting type) */\n default?: unknown\n\n // Select/Radio/Multi-select options\n /** Options for select, radio, multi-select types */\n options?: Array<{ value: string; label: string }>\n\n // Range-specific\n /** Minimum value for range type */\n min?: number\n /** Maximum value for range type */\n max?: number\n /** Step increment for range type */\n step?: number\n\n // Button-specific\n /** Label text on button */\n buttonLabel?: string\n\n // Vector-specific\n /** Axis labels for vector types, e.g., ['X', 'Y'] */\n axisLabels?: [string, string] | [string, string, string]\n\n // Multi-select specific\n /** Maximum number of selections */\n maxItems?: number\n\n // Conditional visibility\n /** Only show if another setting has a specific value */\n showIf?: {\n setting: string\n equals: unknown\n }\n}\n\n// =============================================================================\n// MANIFEST SCHEMA\n// =============================================================================\n\n/**\n * Default layout configuration for addon positioning.\n */\nexport interface AddonDefaultLayout {\n /** X position as percentage of viewport width (0-100) */\n xPercent?: number\n /** Y position as percentage of viewport height (0-100) */\n yPercent?: number\n /** Width as percentage of viewport width (0-100) */\n widthPercent?: number\n /** Height as percentage of viewport height (0-100) */\n heightPercent?: number\n /** Rotation in degrees */\n rotation?: number\n}\n\n/**\n * The complete addon manifest schema.\n * This defines your addon's identity, settings, and capabilities.\n *\n * @example\n * ```json\n * {\n * \"name\": \"Weather Widget\",\n * \"version\": \"1.2.0\",\n * \"description\": \"Displays current weather conditions\",\n * \"author\": \"Jane Developer\",\n * \"categories\": [\"utilities\", \"weather\"],\n * \"capabilities\": {\n * \"hotReload\": true,\n * \"systemEvents\": [\"viewport:resize\", \"theme:change\"]\n * },\n * \"permissions\": {\n * \"storage\": { \"quota\": 512 },\n * \"network\": { \"domains\": [\"api.openweathermap.org\"] }\n * },\n * \"settings\": {\n * \"apiKey\": {\n * \"type\": \"string\",\n * \"label\": \"API Key\",\n * \"description\": \"Get your key at openweathermap.org\"\n * },\n * \"unit\": {\n * \"type\": \"select\",\n * \"label\": \"Temperature Unit\",\n * \"default\": \"celsius\",\n * \"options\": [\n * { \"value\": \"celsius\", \"label\": \"Celsius\" },\n * { \"value\": \"fahrenheit\", \"label\": \"Fahrenheit\" }\n * ]\n * }\n * }\n * }\n * ```\n */\nexport interface AddonManifest {\n // ---------------------------------------------------------------------------\n // REQUIRED FIELDS\n // ---------------------------------------------------------------------------\n\n /** Addon name (displayed in UI) */\n name: string\n\n /** Semantic version (e.g., \"1.0.0\") */\n version: string\n\n /**\n * SDK version this addon was built for.\n * Must be a valid semver (e.g., \"2.3.0\").\n * Host uses this to inject the correct client-side SDK.\n */\n sdkVersion: string\n\n // ---------------------------------------------------------------------------\n // OPTIONAL METADATA\n // ---------------------------------------------------------------------------\n\n /** Short description of the addon */\n description?: string\n\n /** Author name or organization */\n author?: string\n\n /** Addon type/category for filtering */\n type?: string\n\n /** Categories for discoverability */\n categories?: string[]\n\n /** License (e.g., \"MIT\", \"Apache-2.0\") */\n license?: string\n\n /** Homepage or documentation URL */\n homepage?: string\n\n /** Repository URL */\n repository?: string\n\n // ---------------------------------------------------------------------------\n // SETTINGS\n // ---------------------------------------------------------------------------\n\n /**\n * User-configurable settings.\n * Key is the setting ID, value is the definition.\n */\n settings?: Record<string, SettingDefinition>\n\n // ---------------------------------------------------------------------------\n // CAPABILITIES\n // ---------------------------------------------------------------------------\n\n /**\n * Addon capabilities and event subscriptions.\n */\n capabilities?: {\n /** Supports settings changes without full reload */\n hotReload?: boolean\n /** System events the addon wants to receive */\n systemEvents?: SystemEventType[]\n }\n\n // ---------------------------------------------------------------------------\n // PERMISSIONS\n // ---------------------------------------------------------------------------\n\n /**\n * Permissions the addon will request.\n * Declaring them here improves UX by showing upfront.\n */\n permissions?: {\n /** Storage permission with quota in KB */\n storage?: { quota: number }\n /** CPU usage limit */\n cpu?: { limit: 'low' | 'medium' | 'high' }\n /** Network access with allowed domains */\n network?: { domains: string[] }\n /** Audio playback permission */\n audio?: boolean\n /** Notification permission */\n notifications?: boolean\n /**\n * File access permission for uploaded media files.\n * When enabled, the addon can receive uploaded files (video, audio, images)\n * via secure blob transfer for playback.\n *\n * This is required for addons that play user-uploaded media content.\n */\n fileAccess?: {\n /** User-friendly reason why this permission is needed */\n reason: string\n }\n /**\n * Same-origin permission for blob URL support.\n * Required for addons that handle large local files (videos, audio).\n *\n * ⚠️ SECURITY WARNING: This allows the addon to access:\n * - localStorage/sessionStorage of the parent origin\n * - Cookies of the parent domain\n * - IndexedDB of the parent origin\n *\n * Only grant to trusted addons!\n */\n sameOrigin?: {\n /** User-friendly reason why this permission is needed */\n reason: string\n }\n }\n\n // ---------------------------------------------------------------------------\n // LAYOUT\n // ---------------------------------------------------------------------------\n\n /**\n * Default layout for automatic positioning.\n * Used when addon is first added to a wallpaper.\n */\n defaultLayout?: AddonDefaultLayout\n\n // ---------------------------------------------------------------------------\n // FUTURE FIELDS\n // ---------------------------------------------------------------------------\n\n /**\n * OAuth providers and scopes for authenticated addons.\n *\n * Declare the OAuth providers your addon needs and the scopes it requires.\n * Scopes are requested incrementally - users can connect with basic scopes\n * first, and your addon can request additional scopes when needed.\n *\n * @example\n * ```json\n * {\n * \"permissions\": {\n * \"oauth\": {\n * \"required\": [\n * { \"provider\": \"github\", \"scopes\": [\"read:user\"] }\n * ],\n * \"optional\": [\n * { \"provider\": \"github\", \"scopes\": [\"repo\"] }\n * ]\n * }\n * }\n * }\n * ```\n */\n oauth?: {\n /** OAuth providers required for the addon to function */\n required?: Array<{\n provider: OAuthProvider\n scopes: string[]\n /** Reason shown to user when requesting this permission */\n reason?: string\n }>\n /** OAuth providers that enhance functionality but aren't required */\n optional?: Array<{\n provider: OAuthProvider\n scopes: string[]\n /** Reason shown to user when requesting this permission */\n reason?: string\n }>\n }\n}\n\n// =============================================================================\n// VALIDATION\n// =============================================================================\n\n/**\n * Validation result type.\n */\nexport interface ValidationResult {\n success: boolean\n errors?: string[]\n manifest?: AddonManifest\n}\n\n/**\n * Validates an addon manifest object.\n *\n * @param input - The manifest object to validate\n * @returns ValidationResult with success status and any errors\n *\n * @example\n * ```typescript\n * const result = validateManifest(myManifest)\n * if (!result.success) {\n * result.errors?.forEach(err => console.error(err))\n * }\n * ```\n */\nexport function validateManifest(input: unknown): ValidationResult {\n const errors: string[] = []\n\n if (!input || typeof input !== 'object') {\n return { success: false, errors: ['Manifest must be an object'] }\n }\n\n const manifest = input as Record<string, unknown>\n\n // Required fields\n if (typeof manifest.name !== 'string' || manifest.name.trim() === '') {\n errors.push('name: Required and must be a non-empty string')\n }\n\n if (typeof manifest.version !== 'string' || !/^\\d+\\.\\d+\\.\\d+/.test(manifest.version)) {\n errors.push('version: Required and must be a valid semver (e.g., \"1.0.0\")')\n }\n\n if (typeof manifest.sdkVersion !== 'string' || !/^\\d+\\.\\d+\\.\\d+/.test(manifest.sdkVersion)) {\n errors.push('sdkVersion: Required and must be a valid semver (e.g., \"2.2.0\")')\n }\n\n // Optional string fields\n const optionalStrings = ['description', 'author', 'type', 'license', 'homepage', 'repository']\n for (const field of optionalStrings) {\n if (manifest[field] !== undefined && typeof manifest[field] !== 'string') {\n errors.push(`${field}: Must be a string`)\n }\n }\n\n // Categories\n if (manifest.categories !== undefined) {\n if (!Array.isArray(manifest.categories)) {\n errors.push('categories: Must be an array of strings')\n } else if (!manifest.categories.every(c => typeof c === 'string')) {\n errors.push('categories: All items must be strings')\n }\n }\n\n // Settings validation\n if (manifest.settings !== undefined) {\n if (typeof manifest.settings !== 'object' || manifest.settings === null) {\n errors.push('settings: Must be an object')\n } else {\n const settings = manifest.settings as Record<string, unknown>\n for (const [key, value] of Object.entries(settings)) {\n if (typeof value !== 'object' || value === null) {\n errors.push(`settings.${key}: Must be an object`)\n continue\n }\n\n const setting = value as Record<string, unknown>\n const validTypes: SettingType[] = [\n 'string', 'number', 'boolean', 'color', 'select', 'range',\n 'image', 'video', 'audio', 'file', 'section', 'textarea', 'radio', 'gradient', 'vector2',\n 'button', 'multi-select'\n ]\n\n if (!validTypes.includes(setting.type as SettingType)) {\n errors.push(`settings.${key}.type: Must be one of: ${validTypes.join(', ')}`)\n }\n\n // Type-specific validation\n if (['select', 'radio', 'multi-select'].includes(setting.type as string)) {\n if (!Array.isArray(setting.options) || setting.options.length === 0) {\n errors.push(`settings.${key}.options: Required for ${setting.type} type`)\n }\n }\n\n if (setting.type === 'range') {\n if (typeof setting.min !== 'number' || typeof setting.max !== 'number') {\n errors.push(`settings.${key}: range type requires min and max`)\n }\n }\n }\n }\n }\n\n // Capabilities validation\n if (manifest.capabilities !== undefined) {\n if (typeof manifest.capabilities !== 'object' || manifest.capabilities === null) {\n errors.push('capabilities: Must be an object')\n } else {\n const caps = manifest.capabilities as Record<string, unknown>\n\n if (caps.hotReload !== undefined && typeof caps.hotReload !== 'boolean') {\n errors.push('capabilities.hotReload: Must be a boolean')\n }\n\n if (caps.systemEvents !== undefined) {\n const validEvents: SystemEventType[] = [\n 'viewport:resize', 'theme:change', 'visibility:change',\n 'layer:focus', 'layer:blur', 'app:idle', 'app:active'\n ]\n\n if (!Array.isArray(caps.systemEvents)) {\n errors.push('capabilities.systemEvents: Must be an array')\n } else {\n for (const event of caps.systemEvents) {\n if (!validEvents.includes(event)) {\n errors.push(`capabilities.systemEvents: Invalid event \"${event}\"`)\n }\n }\n }\n }\n }\n }\n\n // Permissions validation\n if (manifest.permissions !== undefined) {\n if (typeof manifest.permissions !== 'object' || manifest.permissions === null) {\n errors.push('permissions: Must be an object')\n } else {\n const perms = manifest.permissions as Record<string, unknown>\n\n if (perms.storage !== undefined) {\n const storage = perms.storage as Record<string, unknown>\n if (typeof storage?.quota !== 'number' || storage.quota <= 0) {\n errors.push('permissions.storage.quota: Must be a positive number')\n }\n }\n\n if (perms.cpu !== undefined) {\n const cpu = perms.cpu as Record<string, unknown>\n if (!['low', 'medium', 'high'].includes(cpu?.limit as string)) {\n errors.push('permissions.cpu.limit: Must be low, medium, or high')\n }\n }\n\n if (perms.network !== undefined) {\n const network = perms.network as Record<string, unknown>\n if (!Array.isArray(network?.domains)) {\n errors.push('permissions.network.domains: Must be an array of domain strings')\n }\n }\n }\n }\n\n // Default layout validation\n if (manifest.defaultLayout !== undefined) {\n if (typeof manifest.defaultLayout !== 'object' || manifest.defaultLayout === null) {\n errors.push('defaultLayout: Must be an object')\n } else {\n const layout = manifest.defaultLayout as Record<string, unknown>\n const numFields = ['xPercent', 'yPercent', 'widthPercent', 'heightPercent', 'rotation']\n for (const field of numFields) {\n if (layout[field] !== undefined && typeof layout[field] !== 'number') {\n errors.push(`defaultLayout.${field}: Must be a number`)\n }\n }\n }\n }\n\n if (errors.length > 0) {\n return { success: false, errors }\n }\n\n return { success: true, manifest: manifest as unknown as AddonManifest }\n}\n\n/**\n * Type guard to check if an object is a valid AddonManifest.\n *\n * @param input - Object to check\n * @returns True if input is a valid AddonManifest\n */\nexport function isValidManifest(input: unknown): input is AddonManifest {\n return validateManifest(input).success\n}\n\n// =============================================================================\n// UTILITY FUNCTIONS\n// =============================================================================\n\n/**\n * Check if manifest declares hot-reload capability.\n */\nexport function supportsHotReload(manifest: AddonManifest): boolean {\n return manifest.capabilities?.hotReload === true\n}\n\n/**\n * Get system events the addon subscribes to.\n */\nexport function getSubscribedEvents(manifest: AddonManifest): SystemEventType[] {\n return manifest.capabilities?.systemEvents ?? []\n}\n\n/**\n * Get required permissions from manifest.\n */\nexport function getRequiredPermissions(manifest: AddonManifest): PermissionType[] {\n const permissions: PermissionType[] = []\n\n if (manifest.permissions?.storage) permissions.push('storage')\n if (manifest.permissions?.cpu) permissions.push('cpu-high')\n if (manifest.permissions?.network) permissions.push('network')\n if (manifest.permissions?.audio) permissions.push('audio')\n if (manifest.permissions?.notifications) permissions.push('notifications')\n\n return permissions\n}\n","/**\n * @mywallpaper/addon-sdk - Utility Functions\n *\n * Helper utilities for addon development.\n */\n\nimport type { AddonManifest, SettingDefinition } from './manifest'\n\n// =============================================================================\n// CONFIG UTILITIES\n// =============================================================================\n\n/**\n * Creates a default configuration object from manifest settings.\n *\n * @param manifest - Addon manifest with settings definitions\n * @returns Object with all setting keys and their default values\n *\n * @example\n * ```typescript\n * const manifest = {\n * name: 'My Addon',\n * version: '1.0.0',\n * settings: {\n * color: { type: 'color', default: '#ff0000' },\n * speed: { type: 'range', default: 1, min: 0, max: 10 }\n * }\n * }\n *\n * const defaults = createDefaultConfig(manifest)\n * // { color: '#ff0000', speed: 1 }\n * ```\n */\nexport function createDefaultConfig(manifest: AddonManifest): Record<string, unknown> {\n const config: Record<string, unknown> = {}\n\n if (!manifest.settings) return config\n\n for (const [key, setting] of Object.entries(manifest.settings)) {\n if (setting.type === 'section' || setting.type === 'button') {\n // Skip non-value settings\n continue\n }\n config[key] = setting.default ?? getTypeDefault(setting)\n }\n\n return config\n}\n\n/**\n * Get type-appropriate default value when none specified.\n */\nfunction getTypeDefault(setting: SettingDefinition): unknown {\n switch (setting.type) {\n case 'string':\n case 'textarea':\n return ''\n case 'number':\n return 0\n case 'boolean':\n return false\n case 'color':\n return '#000000'\n case 'select':\n case 'radio':\n return setting.options?.[0]?.value ?? ''\n case 'range':\n return setting.min ?? 0\n case 'image':\n return null\n case 'gradient':\n return { stops: [{ color: '#000000', position: 0 }, { color: '#ffffff', position: 100 }] }\n case 'vector2':\n return { x: 0, y: 0 }\n case 'multi-select':\n return []\n default:\n return null\n }\n}\n\n/**\n * Merges user config with defaults, ensuring all keys exist.\n *\n * @param defaults - Default configuration\n * @param userConfig - User-provided configuration (may be partial)\n * @returns Complete configuration with user values taking precedence\n *\n * @example\n * ```typescript\n * const defaults = { color: '#ff0000', speed: 1 }\n * const user = { color: '#00ff00' }\n *\n * const config = mergeConfigs(defaults, user)\n * // { color: '#00ff00', speed: 1 }\n * ```\n */\nexport function mergeConfigs(\n defaults: Record<string, unknown>,\n userConfig: Record<string, unknown>\n): Record<string, unknown> {\n return { ...defaults, ...userConfig }\n}\n\n// =============================================================================\n// VERSION UTILITIES\n// =============================================================================\n\n/**\n * Semantic version comparison result.\n */\nexport type VersionComparison = -1 | 0 | 1\n\n/**\n * Compare two semantic versions.\n *\n * @param a - First version string\n * @param b - Second version string\n * @returns -1 if a < b, 0 if a === b, 1 if a > b\n *\n * @example\n * ```typescript\n * compareVersions('1.0.0', '1.0.1') // -1\n * compareVersions('2.0.0', '1.9.9') // 1\n * compareVersions('1.0.0', '1.0.0') // 0\n * ```\n */\nexport function compareVersions(a: string, b: string): VersionComparison {\n const parseVersion = (v: string): number[] => {\n return v.split('.').map(n => parseInt(n, 10) || 0)\n }\n\n const partsA = parseVersion(a)\n const partsB = parseVersion(b)\n\n for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {\n const numA = partsA[i] ?? 0\n const numB = partsB[i] ?? 0\n\n if (numA < numB) return -1\n if (numA > numB) return 1\n }\n\n return 0\n}\n\n/**\n * Check if version satisfies a minimum requirement.\n *\n * @param version - Version to check\n * @param minimum - Minimum required version\n * @returns True if version >= minimum\n */\nexport function satisfiesMinVersion(version: string, minimum: string): boolean {\n return compareVersions(version, minimum) >= 0\n}\n\n// =============================================================================\n// STORAGE UTILITIES\n// =============================================================================\n\n/**\n * Calculate the byte size of a value when JSON serialized.\n * Useful for quota tracking.\n *\n * @param value - Value to measure\n * @returns Size in bytes\n */\nexport function getStorageSize(value: unknown): number {\n try {\n return new Blob([JSON.stringify(value)]).size\n } catch {\n return 0\n }\n}\n\n/**\n * Format bytes as human-readable string.\n *\n * @param bytes - Number of bytes\n * @returns Formatted string (e.g., \"1.5 KB\", \"2.3 MB\")\n */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B'\n\n const units = ['B', 'KB', 'MB', 'GB']\n const k = 1024\n const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k))\n\n return `${(bytes / Math.pow(k, i)).toFixed(i > 0 ? 1 : 0)} ${units[i]}`\n}\n\n// =============================================================================\n// TYPE GUARDS\n// =============================================================================\n\n/**\n * Check if a value is a plain object.\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/**\n * Check if a value is a valid color hex string.\n */\nexport function isValidColor(value: unknown): value is string {\n if (typeof value !== 'string') return false\n return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(value)\n}\n\n// =============================================================================\n// DEBOUNCE/THROTTLE\n// =============================================================================\n\n/**\n * Debounce a function - only call after delay with no new calls.\n *\n * @param fn - Function to debounce\n * @param delayMs - Delay in milliseconds\n * @returns Debounced function\n *\n * @example\n * ```typescript\n * const save = debounce((data) => {\n * localStorage.setItem('data', JSON.stringify(data))\n * }, 1000)\n *\n * // Rapid calls only trigger one save after 1s\n * save({ a: 1 })\n * save({ a: 2 })\n * save({ a: 3 }) // Only this one runs (after 1s)\n * ```\n */\nexport function debounce<T extends (...args: unknown[]) => void>(\n fn: T,\n delayMs: number\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n\n return (...args: Parameters<T>) => {\n if (timeoutId) clearTimeout(timeoutId)\n timeoutId = setTimeout(() => fn(...args), delayMs)\n }\n}\n\n/**\n * Throttle a function - call at most once per interval.\n *\n * @param fn - Function to throttle\n * @param intervalMs - Minimum interval between calls\n * @returns Throttled function\n */\nexport function throttle<T extends (...args: unknown[]) => void>(\n fn: T,\n intervalMs: number\n): (...args: Parameters<T>) => void {\n let lastCall = 0\n\n return (...args: Parameters<T>) => {\n const now = Date.now()\n if (now - lastCall >= intervalMs) {\n lastCall = now\n fn(...args)\n }\n }\n}\n\n// =============================================================================\n// EVENT HELPERS\n// =============================================================================\n\n/**\n * Create a one-time event listener that auto-removes after first call.\n *\n * @param element - DOM element or window\n * @param event - Event name\n * @param handler - Event handler\n */\nexport function once(\n element: EventTarget,\n event: string,\n handler: EventListener\n): void {\n const wrappedHandler: EventListener = (e) => {\n element.removeEventListener(event, wrappedHandler)\n handler(e)\n }\n element.addEventListener(event, wrappedHandler)\n}\n","/**\n * @mywallpaper/addon-sdk\n *\n * Official SDK for building MyWallpaper addons.\n *\n * @packageDocumentation\n *\n * ## Installation\n *\n * ```bash\n * npm install @mywallpaper/addon-sdk\n * ```\n *\n * ## Quick Start\n *\n * ```typescript\n * // Your addon's main file\n * import type { MyWallpaperAPI } from '@mywallpaper/addon-sdk'\n *\n * // The API is automatically available on window.MyWallpaper\n * const api = window.MyWallpaper\n *\n * // Access configuration\n * const { backgroundColor, animationSpeed } = api.config\n *\n * // React to setting changes (hot-reload)\n * api.onSettingsChange((settings, changedKeys) => {\n * if (changedKeys.includes('backgroundColor')) {\n * document.body.style.background = settings.backgroundColor as string\n * }\n * })\n *\n * // Subscribe to system events\n * api.onEvent('viewport:resize', ({ width, height }) => {\n * canvas.width = width\n * canvas.height = height\n * })\n *\n * // Signal addon is ready\n * api.ready({\n * capabilities: ['hot-reload'],\n * subscribedEvents: ['viewport:resize']\n * })\n *\n * // After visual rendering is complete\n * await loadImages()\n * render()\n * api.renderComplete()\n * ```\n *\n * ## Manifest Validation\n *\n * ```typescript\n * import { validateManifest, type AddonManifest } from '@mywallpaper/addon-sdk/manifest'\n *\n * const manifest: AddonManifest = {\n * name: 'My Addon',\n * version: '1.0.0',\n * settings: {\n * color: { type: 'color', default: '#ffffff' }\n * }\n * }\n *\n * const result = validateManifest(manifest)\n * if (!result.success) {\n * console.error(result.errors)\n * }\n * ```\n *\n * @module\n */\n\n// =============================================================================\n// TYPE EXPORTS\n// =============================================================================\n\nexport type {\n // Main API\n MyWallpaperAPI,\n StorageAPI,\n NetworkAPI,\n NetworkResponse,\n\n // OAuth API\n OAuthAPI,\n OAuthResponse,\n OAuthScopesError,\n OAuthProvider,\n OAuthPermissionType,\n\n // File Access API\n FileAccessAPI,\n FileReference,\n FileAccessResult,\n\n // Events\n SystemEventType,\n SystemEventData,\n\n // Capabilities & Permissions\n AddonCapability,\n PermissionType,\n PermissionConstraints,\n\n // Callbacks\n SettingsCallback,\n EventCallback,\n ReadyOptions,\n\n // Lifecycle\n LifecycleEvent,\n\n // Utility types\n AddonValues,\n} from './types'\n\n// =============================================================================\n// MANIFEST EXPORTS\n// =============================================================================\n\nexport type {\n // Manifest types\n AddonManifest,\n SettingDefinition,\n SettingType,\n AddonDefaultLayout,\n ValidationResult,\n} from './manifest'\n\nexport {\n // Validation\n validateManifest,\n isValidManifest,\n\n // Manifest utilities\n supportsHotReload,\n getSubscribedEvents,\n getRequiredPermissions,\n} from './manifest'\n\n// =============================================================================\n// UTILITY EXPORTS\n// =============================================================================\n\nexport {\n // Config utilities\n createDefaultConfig,\n mergeConfigs,\n\n // Version utilities\n compareVersions,\n satisfiesMinVersion,\n\n // Storage utilities\n getStorageSize,\n formatBytes,\n\n // Type guards\n isPlainObject,\n isValidColor,\n\n // Function utilities\n debounce,\n throttle,\n once,\n} from './utils'\n\nexport type { VersionComparison } from './utils'\n\n// =============================================================================\n// SDK VERSION\n// =============================================================================\n\n/**\n * Current SDK version.\n */\nexport const SDK_VERSION = '2.3.0'\n\n/**\n * Minimum compatible host version.\n */\nexport const MIN_HOST_VERSION = '2.0.0'\n"]}
|
package/dist/manifest.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @mywallpaper/addon-sdk - TypeScript Types v2.
|
|
2
|
+
* @mywallpaper/addon-sdk - TypeScript Types v2.5
|
|
3
3
|
*
|
|
4
4
|
* Complete type definitions for building MyWallpaper addons.
|
|
5
5
|
* These types describe the runtime API available via window.MyWallpaper
|
|
@@ -526,6 +526,22 @@ interface MyWallpaperAPI {
|
|
|
526
526
|
* OAuth API for making authenticated requests to provider APIs.
|
|
527
527
|
*/
|
|
528
528
|
oauth: OAuthAPI;
|
|
529
|
+
/**
|
|
530
|
+
* Audio API for playing audio through the host (parent).
|
|
531
|
+
* Required because sandboxed iframes cannot autoplay audio.
|
|
532
|
+
*
|
|
533
|
+
* @example
|
|
534
|
+
* ```typescript
|
|
535
|
+
* // Play audio from a file setting
|
|
536
|
+
* api.audio.play('mediaFile', { volume: 0.8, loop: true })
|
|
537
|
+
*
|
|
538
|
+
* // Control playback
|
|
539
|
+
* api.audio.pause()
|
|
540
|
+
* api.audio.seek(30)
|
|
541
|
+
* api.audio.resume()
|
|
542
|
+
* ```
|
|
543
|
+
*/
|
|
544
|
+
audio: AudioAPI;
|
|
529
545
|
/**
|
|
530
546
|
* File Access API for requesting access to user-uploaded files.
|
|
531
547
|
* Files are not sent automatically - the addon must request access.
|
|
@@ -660,6 +676,135 @@ interface FileAccessAPI {
|
|
|
660
676
|
*/
|
|
661
677
|
revoke(settingKey: string): void;
|
|
662
678
|
}
|
|
679
|
+
/**
|
|
680
|
+
* Options for audio playback.
|
|
681
|
+
*/
|
|
682
|
+
interface AudioOptions {
|
|
683
|
+
/** Initial volume (0.0 to 1.0). Default: 1.0 */
|
|
684
|
+
volume?: number;
|
|
685
|
+
/** Whether to loop playback. Default: false */
|
|
686
|
+
loop?: boolean;
|
|
687
|
+
/** Playback speed (0.25 to 4.0). Default: 1.0 */
|
|
688
|
+
playbackRate?: number;
|
|
689
|
+
/** Start position in seconds. Default: 0 */
|
|
690
|
+
startTime?: number;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Current audio playback state.
|
|
694
|
+
* Synced from host to addon via AUDIO_STATE messages.
|
|
695
|
+
*/
|
|
696
|
+
interface AudioState {
|
|
697
|
+
/** Current playback status */
|
|
698
|
+
status: 'none' | 'loading' | 'playing' | 'paused' | 'ended' | 'error';
|
|
699
|
+
/** Current playback position in seconds */
|
|
700
|
+
currentTime: number;
|
|
701
|
+
/** Total duration in seconds */
|
|
702
|
+
duration: number;
|
|
703
|
+
/** Current volume (0.0 to 1.0) */
|
|
704
|
+
volume: number;
|
|
705
|
+
/** Whether loop is enabled */
|
|
706
|
+
loop: boolean;
|
|
707
|
+
/** Current playback speed */
|
|
708
|
+
playbackRate: number;
|
|
709
|
+
/** Error message if status is 'error' */
|
|
710
|
+
error?: string;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Audio API for playing audio through the host (parent).
|
|
714
|
+
* Access via `window.MyWallpaper.audio`
|
|
715
|
+
*
|
|
716
|
+
* **Why this exists:**
|
|
717
|
+
* Sandboxed iframes (without allow-same-origin) cannot autoplay audio
|
|
718
|
+
* due to browser security policies. This API allows addons to play
|
|
719
|
+
* audio by delegating playback to the host application.
|
|
720
|
+
*
|
|
721
|
+
* **How it works:**
|
|
722
|
+
* 1. Addon calls `audio.play(source)` with a URL or file reference
|
|
723
|
+
* 2. Host creates an `<audio>` element in its own context
|
|
724
|
+
* 3. Host syncs playback state back to addon via AUDIO_STATE messages
|
|
725
|
+
* 4. Addon can control playback with pause/resume/seek/etc.
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* ```typescript
|
|
729
|
+
* const api = window.MyWallpaper
|
|
730
|
+
*
|
|
731
|
+
* // Play audio from a setting file reference
|
|
732
|
+
* api.audio.play('backgroundMusic', {
|
|
733
|
+
* volume: 0.8,
|
|
734
|
+
* loop: true
|
|
735
|
+
* })
|
|
736
|
+
*
|
|
737
|
+
* // Or play from URL
|
|
738
|
+
* api.audio.play('https://example.com/audio.mp3')
|
|
739
|
+
*
|
|
740
|
+
* // Listen for state changes
|
|
741
|
+
* api.audio.onStateChange((state) => {
|
|
742
|
+
* console.log(`Audio is ${state.status} at ${state.currentTime}s`)
|
|
743
|
+
* })
|
|
744
|
+
*
|
|
745
|
+
* // Control playback
|
|
746
|
+
* api.audio.pause()
|
|
747
|
+
* api.audio.seek(30) // Jump to 30 seconds
|
|
748
|
+
* api.audio.resume()
|
|
749
|
+
* ```
|
|
750
|
+
*/
|
|
751
|
+
interface AudioAPI {
|
|
752
|
+
/**
|
|
753
|
+
* Play audio from a source.
|
|
754
|
+
* Source can be a URL, a setting key name, or a FileReference.
|
|
755
|
+
*
|
|
756
|
+
* @param source - URL string, setting key, or FileReference
|
|
757
|
+
* @param options - Playback options (volume, loop, etc.)
|
|
758
|
+
*/
|
|
759
|
+
play(source: string | FileReference | {
|
|
760
|
+
settingKey: string;
|
|
761
|
+
}, options?: AudioOptions): void;
|
|
762
|
+
/**
|
|
763
|
+
* Pause playback.
|
|
764
|
+
*/
|
|
765
|
+
pause(): void;
|
|
766
|
+
/**
|
|
767
|
+
* Resume playback from current position.
|
|
768
|
+
*/
|
|
769
|
+
resume(): void;
|
|
770
|
+
/**
|
|
771
|
+
* Stop playback and reset to beginning.
|
|
772
|
+
*/
|
|
773
|
+
stop(): void;
|
|
774
|
+
/**
|
|
775
|
+
* Seek to a specific position.
|
|
776
|
+
* @param seconds - Position in seconds
|
|
777
|
+
*/
|
|
778
|
+
seek(seconds: number): void;
|
|
779
|
+
/**
|
|
780
|
+
* Set the volume.
|
|
781
|
+
* @param volume - Volume level (0.0 to 1.0)
|
|
782
|
+
*/
|
|
783
|
+
setVolume(volume: number): void;
|
|
784
|
+
/**
|
|
785
|
+
* Enable or disable loop.
|
|
786
|
+
* @param loop - Whether to loop
|
|
787
|
+
*/
|
|
788
|
+
setLoop(loop: boolean): void;
|
|
789
|
+
/**
|
|
790
|
+
* Set the playback speed.
|
|
791
|
+
* @param rate - Speed multiplier (0.25 to 4.0)
|
|
792
|
+
*/
|
|
793
|
+
setPlaybackRate(rate: number): void;
|
|
794
|
+
/**
|
|
795
|
+
* Get the current audio state.
|
|
796
|
+
* @returns Current AudioState
|
|
797
|
+
*/
|
|
798
|
+
getState(): AudioState;
|
|
799
|
+
/**
|
|
800
|
+
* Subscribe to audio state changes.
|
|
801
|
+
* Callback is called immediately with current state, then on each change.
|
|
802
|
+
*
|
|
803
|
+
* @param callback - Function called with new state
|
|
804
|
+
* @returns Unsubscribe function
|
|
805
|
+
*/
|
|
806
|
+
onStateChange(callback: (state: AudioState) => void): () => void;
|
|
807
|
+
}
|
|
663
808
|
|
|
664
809
|
/**
|
|
665
810
|
* @mywallpaper/addon-sdk - Manifest Schema & Validation
|
|
@@ -674,7 +819,7 @@ interface FileAccessAPI {
|
|
|
674
819
|
* const manifest: AddonManifest = {
|
|
675
820
|
* name: 'My Addon',
|
|
676
821
|
* version: '1.0.0',
|
|
677
|
-
* sdkVersion: '2.
|
|
822
|
+
* sdkVersion: '2.7.0',
|
|
678
823
|
* description: 'A cool addon',
|
|
679
824
|
* settings: {
|
|
680
825
|
* primaryColor: { type: 'color', default: '#ffffff', label: 'Primary Color' }
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @mywallpaper/addon-sdk - TypeScript Types v2.
|
|
2
|
+
* @mywallpaper/addon-sdk - TypeScript Types v2.5
|
|
3
3
|
*
|
|
4
4
|
* Complete type definitions for building MyWallpaper addons.
|
|
5
5
|
* These types describe the runtime API available via window.MyWallpaper
|
|
@@ -526,6 +526,22 @@ interface MyWallpaperAPI {
|
|
|
526
526
|
* OAuth API for making authenticated requests to provider APIs.
|
|
527
527
|
*/
|
|
528
528
|
oauth: OAuthAPI;
|
|
529
|
+
/**
|
|
530
|
+
* Audio API for playing audio through the host (parent).
|
|
531
|
+
* Required because sandboxed iframes cannot autoplay audio.
|
|
532
|
+
*
|
|
533
|
+
* @example
|
|
534
|
+
* ```typescript
|
|
535
|
+
* // Play audio from a file setting
|
|
536
|
+
* api.audio.play('mediaFile', { volume: 0.8, loop: true })
|
|
537
|
+
*
|
|
538
|
+
* // Control playback
|
|
539
|
+
* api.audio.pause()
|
|
540
|
+
* api.audio.seek(30)
|
|
541
|
+
* api.audio.resume()
|
|
542
|
+
* ```
|
|
543
|
+
*/
|
|
544
|
+
audio: AudioAPI;
|
|
529
545
|
/**
|
|
530
546
|
* File Access API for requesting access to user-uploaded files.
|
|
531
547
|
* Files are not sent automatically - the addon must request access.
|
|
@@ -660,6 +676,135 @@ interface FileAccessAPI {
|
|
|
660
676
|
*/
|
|
661
677
|
revoke(settingKey: string): void;
|
|
662
678
|
}
|
|
679
|
+
/**
|
|
680
|
+
* Options for audio playback.
|
|
681
|
+
*/
|
|
682
|
+
interface AudioOptions {
|
|
683
|
+
/** Initial volume (0.0 to 1.0). Default: 1.0 */
|
|
684
|
+
volume?: number;
|
|
685
|
+
/** Whether to loop playback. Default: false */
|
|
686
|
+
loop?: boolean;
|
|
687
|
+
/** Playback speed (0.25 to 4.0). Default: 1.0 */
|
|
688
|
+
playbackRate?: number;
|
|
689
|
+
/** Start position in seconds. Default: 0 */
|
|
690
|
+
startTime?: number;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Current audio playback state.
|
|
694
|
+
* Synced from host to addon via AUDIO_STATE messages.
|
|
695
|
+
*/
|
|
696
|
+
interface AudioState {
|
|
697
|
+
/** Current playback status */
|
|
698
|
+
status: 'none' | 'loading' | 'playing' | 'paused' | 'ended' | 'error';
|
|
699
|
+
/** Current playback position in seconds */
|
|
700
|
+
currentTime: number;
|
|
701
|
+
/** Total duration in seconds */
|
|
702
|
+
duration: number;
|
|
703
|
+
/** Current volume (0.0 to 1.0) */
|
|
704
|
+
volume: number;
|
|
705
|
+
/** Whether loop is enabled */
|
|
706
|
+
loop: boolean;
|
|
707
|
+
/** Current playback speed */
|
|
708
|
+
playbackRate: number;
|
|
709
|
+
/** Error message if status is 'error' */
|
|
710
|
+
error?: string;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Audio API for playing audio through the host (parent).
|
|
714
|
+
* Access via `window.MyWallpaper.audio`
|
|
715
|
+
*
|
|
716
|
+
* **Why this exists:**
|
|
717
|
+
* Sandboxed iframes (without allow-same-origin) cannot autoplay audio
|
|
718
|
+
* due to browser security policies. This API allows addons to play
|
|
719
|
+
* audio by delegating playback to the host application.
|
|
720
|
+
*
|
|
721
|
+
* **How it works:**
|
|
722
|
+
* 1. Addon calls `audio.play(source)` with a URL or file reference
|
|
723
|
+
* 2. Host creates an `<audio>` element in its own context
|
|
724
|
+
* 3. Host syncs playback state back to addon via AUDIO_STATE messages
|
|
725
|
+
* 4. Addon can control playback with pause/resume/seek/etc.
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* ```typescript
|
|
729
|
+
* const api = window.MyWallpaper
|
|
730
|
+
*
|
|
731
|
+
* // Play audio from a setting file reference
|
|
732
|
+
* api.audio.play('backgroundMusic', {
|
|
733
|
+
* volume: 0.8,
|
|
734
|
+
* loop: true
|
|
735
|
+
* })
|
|
736
|
+
*
|
|
737
|
+
* // Or play from URL
|
|
738
|
+
* api.audio.play('https://example.com/audio.mp3')
|
|
739
|
+
*
|
|
740
|
+
* // Listen for state changes
|
|
741
|
+
* api.audio.onStateChange((state) => {
|
|
742
|
+
* console.log(`Audio is ${state.status} at ${state.currentTime}s`)
|
|
743
|
+
* })
|
|
744
|
+
*
|
|
745
|
+
* // Control playback
|
|
746
|
+
* api.audio.pause()
|
|
747
|
+
* api.audio.seek(30) // Jump to 30 seconds
|
|
748
|
+
* api.audio.resume()
|
|
749
|
+
* ```
|
|
750
|
+
*/
|
|
751
|
+
interface AudioAPI {
|
|
752
|
+
/**
|
|
753
|
+
* Play audio from a source.
|
|
754
|
+
* Source can be a URL, a setting key name, or a FileReference.
|
|
755
|
+
*
|
|
756
|
+
* @param source - URL string, setting key, or FileReference
|
|
757
|
+
* @param options - Playback options (volume, loop, etc.)
|
|
758
|
+
*/
|
|
759
|
+
play(source: string | FileReference | {
|
|
760
|
+
settingKey: string;
|
|
761
|
+
}, options?: AudioOptions): void;
|
|
762
|
+
/**
|
|
763
|
+
* Pause playback.
|
|
764
|
+
*/
|
|
765
|
+
pause(): void;
|
|
766
|
+
/**
|
|
767
|
+
* Resume playback from current position.
|
|
768
|
+
*/
|
|
769
|
+
resume(): void;
|
|
770
|
+
/**
|
|
771
|
+
* Stop playback and reset to beginning.
|
|
772
|
+
*/
|
|
773
|
+
stop(): void;
|
|
774
|
+
/**
|
|
775
|
+
* Seek to a specific position.
|
|
776
|
+
* @param seconds - Position in seconds
|
|
777
|
+
*/
|
|
778
|
+
seek(seconds: number): void;
|
|
779
|
+
/**
|
|
780
|
+
* Set the volume.
|
|
781
|
+
* @param volume - Volume level (0.0 to 1.0)
|
|
782
|
+
*/
|
|
783
|
+
setVolume(volume: number): void;
|
|
784
|
+
/**
|
|
785
|
+
* Enable or disable loop.
|
|
786
|
+
* @param loop - Whether to loop
|
|
787
|
+
*/
|
|
788
|
+
setLoop(loop: boolean): void;
|
|
789
|
+
/**
|
|
790
|
+
* Set the playback speed.
|
|
791
|
+
* @param rate - Speed multiplier (0.25 to 4.0)
|
|
792
|
+
*/
|
|
793
|
+
setPlaybackRate(rate: number): void;
|
|
794
|
+
/**
|
|
795
|
+
* Get the current audio state.
|
|
796
|
+
* @returns Current AudioState
|
|
797
|
+
*/
|
|
798
|
+
getState(): AudioState;
|
|
799
|
+
/**
|
|
800
|
+
* Subscribe to audio state changes.
|
|
801
|
+
* Callback is called immediately with current state, then on each change.
|
|
802
|
+
*
|
|
803
|
+
* @param callback - Function called with new state
|
|
804
|
+
* @returns Unsubscribe function
|
|
805
|
+
*/
|
|
806
|
+
onStateChange(callback: (state: AudioState) => void): () => void;
|
|
807
|
+
}
|
|
663
808
|
|
|
664
809
|
/**
|
|
665
810
|
* @mywallpaper/addon-sdk - Manifest Schema & Validation
|
|
@@ -674,7 +819,7 @@ interface FileAccessAPI {
|
|
|
674
819
|
* const manifest: AddonManifest = {
|
|
675
820
|
* name: 'My Addon',
|
|
676
821
|
* version: '1.0.0',
|
|
677
|
-
* sdkVersion: '2.
|
|
822
|
+
* sdkVersion: '2.7.0',
|
|
678
823
|
* description: 'A cool addon',
|
|
679
824
|
* settings: {
|
|
680
825
|
* primaryColor: { type: 'color', default: '#ffffff', label: 'Primary Color' }
|