craft-native 0.0.37 → 0.0.49
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/dist/android/src/index.js +268 -0
- package/dist/android/src/index.js.map +10 -0
- package/dist/android/templates/AndroidManifest.xml.template +69 -0
- package/dist/android/templates/CraftBridge.kt.template +3748 -0
- package/dist/android/templates/CraftBridgeExtensions.kt.template +383 -0
- package/dist/android/templates/CraftWidgetProvider.kt.template +246 -0
- package/dist/android/templates/MainActivity.kt.template +109 -0
- package/dist/android/templates/build.gradle.kts.app.template +80 -0
- package/dist/android/templates/build.gradle.kts.project.template +5 -0
- package/dist/android/templates/fastlane/Appfile +25 -0
- package/dist/android/templates/fastlane/Fastfile +192 -0
- package/dist/android/templates/fastlane/Gemfile +7 -0
- package/dist/android/templates/github-workflow-android.yml +248 -0
- package/dist/android/templates/github-workflow-test.yml +329 -0
- package/dist/android/templates/settings.gradle.kts.template +18 -0
- package/dist/android/templates/test-bridges.html +1463 -0
- package/dist/api/window.d.ts +18 -0
- package/dist/api/window.d.ts.map +1 -1
- package/dist/assets/index.d.ts.map +1 -1
- package/dist/bridge/core.d.ts +2 -0
- package/dist/bridge/core.d.ts.map +1 -1
- package/dist/cli.js +4168 -0
- package/dist/components/sidebar.d.ts +5 -1
- package/dist/components/sidebar.d.ts.map +1 -1
- package/dist/dev/devtools.d.ts +1 -1
- package/dist/dev/devtools.d.ts.map +1 -1
- package/dist/dev/hot-reload.d.ts +12 -3
- package/dist/dev/hot-reload.d.ts.map +1 -1
- package/dist/index.cjs +573 -208
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +585 -216
- package/dist/index.js.map +45 -0
- package/dist/ios/src/index.js +186 -0
- package/dist/ios/src/index.js.map +10 -0
- package/dist/ios/templates/CraftApp.swift +4241 -0
- package/dist/ios/templates/CraftAppExtensions.swift +361 -0
- package/dist/ios/templates/CraftWidget.swift +247 -0
- package/dist/ios/templates/Info.plist.template +65 -0
- package/dist/ios/templates/fastlane/Appfile +45 -0
- package/dist/ios/templates/fastlane/Fastfile +189 -0
- package/dist/ios/templates/fastlane/Gemfile +7 -0
- package/dist/ios/templates/fastlane/Matchfile +58 -0
- package/dist/ios/templates/github-workflow-ios.yml +192 -0
- package/dist/ios/templates/github-workflow-release.yml +175 -0
- package/dist/ios/templates/github-workflow-test.yml +272 -0
- package/dist/ios/templates/project.yml.template +25 -0
- package/dist/ios/templates/test-bridges.html +1463 -0
- package/dist/package.d.ts +106 -2
- package/dist/package.d.ts.map +1 -1
- package/dist/package.test.d.ts +2 -0
- package/dist/package.test.d.ts.map +1 -0
- package/dist/styles/sidebar-templates.d.ts.map +1 -1
- package/dist/styles/sidebars.d.ts +12 -8
- package/dist/styles/sidebars.d.ts.map +1 -1
- package/dist/templates/projects/blank/craft.config.ts +19 -0
- package/dist/templates/projects/blank/index.html +27 -0
- package/dist/templates/projects/blank/package.json +19 -0
- package/dist/templates/projects/blank/src/main.ts +26 -0
- package/dist/templates/projects/dashboard/craft.config.ts +42 -0
- package/dist/templates/projects/dashboard/index.html +13 -0
- package/dist/templates/projects/dashboard/package.json +20 -0
- package/dist/templates/projects/dashboard/src/main.ts +163 -0
- package/dist/templates/projects/dashboard/src/styles.css +280 -0
- package/dist/templates/projects/drawer/craft.config.ts +47 -0
- package/dist/templates/projects/drawer/index.html +13 -0
- package/dist/templates/projects/drawer/package.json +21 -0
- package/dist/templates/projects/drawer/src/main.ts +406 -0
- package/dist/templates/projects/drawer/src/styles.css +468 -0
- package/dist/templates/projects/ecommerce/craft.config.ts +32 -0
- package/dist/templates/projects/ecommerce/index.html +13 -0
- package/dist/templates/projects/ecommerce/package.json +19 -0
- package/dist/templates/projects/ecommerce/src/main.ts +194 -0
- package/dist/templates/projects/ecommerce/src/styles.css +169 -0
- package/dist/templates/projects/social/craft.config.ts +32 -0
- package/dist/templates/projects/social/index.html +13 -0
- package/dist/templates/projects/social/package.json +19 -0
- package/dist/templates/projects/social/src/main.ts +270 -0
- package/dist/templates/projects/social/src/styles.css +216 -0
- package/dist/templates/projects/tabs/craft.config.ts +47 -0
- package/dist/templates/projects/tabs/index.html +13 -0
- package/dist/templates/projects/tabs/package.json +21 -0
- package/dist/templates/projects/tabs/src/main.ts +177 -0
- package/dist/templates/projects/tabs/src/styles.css +163 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/updater/index.d.ts +1 -0
- package/dist/updater/index.d.ts.map +1 -1
- package/package.json +5 -12
- package/bin/cli.ts +0 -937
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts", "../src/binary-resolver.ts", "../src/package.ts", "../src/utils/audio.ts", "../src/utils/native.ts", "../src/utils/storage.ts", "../src/utils/timer.ts", "../src/bridge/core.ts", "../src/bridge/ids.ts", "../src/bridge/webkit-pending.ts", "../src/api/window.ts", "../src/api/tray.ts", "../src/api/app.ts", "../src/api/fs.ts", "../src/api/db.ts", "../src/api/http.ts", "../src/api/crypto.ts", "../src/api/process.ts", "../src/api/mobile.ts", "../src/api/ios-advanced.ts", "../src/api/android-advanced.ts", "../src/api/macos-advanced.ts", "../src/api/windows-advanced.ts", "../src/api/dialog.ts", "../src/api/clipboard.ts", "../src/api/media.ts", "../src/api/sidebar.ts", "../src/components/sidebar.ts", "../src/components/native.ts", "../src/components/index.ts", "../src/styles/headwind.ts", "../src/styles/sidebars.ts", "../src/styles/sidebar-templates.ts", "../src/styles/index.ts", "../src/optimizations/index.ts", "../src/updater/index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Craft - Build desktop apps with web languages\n * TypeScript SDK powered by Bun\n */\n\nimport { execFile, spawn, type ChildProcess } from 'node:child_process'\nimport { mkdtempSync, readFileSync, writeFileSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport { promisify } from 'node:util'\nimport { craftBinaryNotFoundMessage, resolveCraftBinary } from './binary-resolver'\nimport type { AppConfig, WindowOptions } from './types'\n\nconst execFileAsync = promisify(execFile)\n\n/** Tracks whether we've already warned about a binary/SDK version mismatch so each process logs once. */\nlet versionMismatchWarned = false\n\n/**\n * Read the SDK's own version from `package.json`. Falls back to `'unknown'`\n * when not running from the source tree (the import-meta.dir path may not\n * resolve in some bundler edge cases).\n */\nfunction getSdkVersion(): string {\n try {\n const pkgPath = join(import.meta.dir, '..', 'package.json')\n return JSON.parse(readFileSync(pkgPath, 'utf-8')).version ?? 'unknown'\n }\n catch {\n return 'unknown'\n }\n}\n\n/**\n * Probe the native binary for its `--version`, compare it to the SDK\n * version, and warn (once) when they don't match. Best-effort: a binary\n * that doesn't support `--version` is silently ignored.\n */\nasync function probeBinaryVersion(craftPath: string): Promise<void> {\n if (versionMismatchWarned) return\n try {\n const { stdout } = await execFileAsync(craftPath, ['--version'], { timeout: 2000 })\n const nativeVersion = stdout.trim().replace(/^v/, '')\n const sdkVersion = getSdkVersion()\n if (sdkVersion !== 'unknown' && nativeVersion && nativeVersion !== sdkVersion) {\n versionMismatchWarned = true\n console.warn(\n `⚠️ Craft binary/SDK version mismatch: SDK=${sdkVersion}, native=${nativeVersion}.\\n`\n + ' This is usually fine across patch releases but may produce surprising behavior across minors.',\n )\n }\n }\n catch {\n // Binary may not implement --version, or may be slow; don't block startup.\n }\n}\n\n// Export packaging API\nexport { packageApp, pack, type PackageConfig, type PackageResult } from './package'\n\n// Export utilities\nexport * from './utils'\n\n// Export API modules\nexport * from './api'\n\n// Namespace export so consumers can also do `import { components } from '...'`\n// and reach every symbol from `./components` without name clashes against the\n// API surface. The flat (selective) re-exports below are kept for backwards\n// compatibility, but new code should prefer `components.X` to avoid surprises\n// when new exports are added on either side.\nexport * as components from './components'\n\n// Export component abstractions (React Native-style primitives)\n// Use explicit exports to avoid conflicts with names from './api':\n// Excluded duplicates: Sidebar, createSidebar, SidebarItem, SidebarSection,\n// SidebarConfig, TouchBarItem, TableColumn, Platform\nexport {\n // Sidebar (component variants, aliased to avoid conflict with api/sidebar)\n createTahoeSidebar,\n createArcSidebar,\n createOrbStackSidebar,\n sidebarItem,\n sidebarSection,\n sidebarSeparator,\n tahoeStyle,\n arcStyle,\n orbstackStyle,\n\n // Native UI Components\n createSplitView,\n SplitViewInstance,\n createFileBrowser,\n FileBrowserInstance,\n createOutlineView,\n OutlineViewInstance,\n createTableView,\n TableViewInstance,\n showQuickLook,\n hideQuickLook,\n canQuickLook,\n showColorPicker,\n showFontPicker,\n showDatePicker,\n createProgress,\n ProgressInstance,\n setToolbar,\n updateToolbarItem,\n setToolbarVisible,\n setTouchBar,\n updateTouchBarItem,\n\n // Animated & StyleSheet\n StyleSheet,\n Animated,\n} from './components'\nexport type {\n // Sidebar types (excluding duplicates with api)\n ContextMenuItem,\n SidebarStyle,\n SidebarPosition,\n SidebarHeaderConfig,\n SidebarFooterConfig,\n SidebarEventType,\n SidebarEventMap,\n SidebarEventHandler,\n\n // Native component types (excluding duplicates with api)\n ComponentProps,\n ComponentInstance,\n SplitViewOrientation,\n SplitViewDividerStyle,\n SplitViewConfig,\n FileBrowserConfig,\n FileBrowserSelection,\n OutlineItem,\n OutlineViewConfig,\n TableRow,\n TableViewConfig,\n QuickLookConfig,\n ColorPickerConfig,\n FontPickerConfig,\n FontResult,\n DatePickerConfig,\n ProgressConfig,\n ToolbarItem,\n ToolbarConfig,\n TouchBarConfig,\n\n // Style types\n FlexStyle,\n LayoutStyle,\n SpacingStyle,\n BorderStyle,\n ColorStyle,\n ShadowStyle,\n TransformStyle,\n ViewStyle,\n TextStyleProps,\n TextStyle,\n ImageStyleProps,\n ImageStyle,\n\n // Component props\n BaseProps,\n ViewProps,\n TextProps,\n ImageSource,\n ImageProps,\n ScrollViewProps,\n PressableProps,\n TextInputProps,\n FlatListProps,\n\n // Events\n LayoutEvent,\n ScrollEvent,\n} from './components'\n\n// Export styling utilities (Headwind CSS integration + Sidebar styles)\nexport * from './styles/headwind'\nexport * from './styles'\n\n// Export framework-specific optimizations\nexport * from './optimizations'\n\n// Export auto-updater (delta/differential update support)\nexport * as updater from './updater'\n\n/**\n * Decide whether to enable dev defaults (hot-reload + devtools). The\n * previous default keyed exclusively off `NODE_ENV === 'development'`,\n * which Bun scripts and packaged CLIs almost never set; the result was\n * that you had to opt into devtools manually even when running from\n * source. The order of precedence is:\n *\n * 1. `CRAFT_ENV` env var, if set (`development`/`production` win).\n * 2. `NODE_ENV` env var, if set.\n * 3. Heuristic: enabled when not running inside a packaged binary\n * (i.e. `process.pkg` / `import.meta.main` are absent or true).\n * Keeps \"just clone and run\" working out of the box.\n */\nfunction detectDevMode(): boolean {\n if (typeof process === 'undefined') return false\n const craftEnv = (process.env.CRAFT_ENV || '').toLowerCase()\n if (craftEnv === 'development' || craftEnv === 'dev') return true\n if (craftEnv === 'production' || craftEnv === 'prod') return false\n const nodeEnv = (process.env.NODE_ENV || '').toLowerCase()\n if (nodeEnv === 'development' || nodeEnv === 'dev') return true\n if (nodeEnv === 'production' || nodeEnv === 'prod') return false\n // Packaged-binary heuristic. `process.pkg` (pkg/Bun-compile),\n // `process.isPackaged` (Electron) → not dev. Otherwise default to dev.\n const proc = process as unknown as { pkg?: unknown; isPackaged?: boolean }\n if (proc.pkg || proc.isPackaged) return false\n return true\n}\n\nexport class CraftApp {\n private process?: ChildProcess\n private config: AppConfig\n\n constructor(config: AppConfig = {}) {\n // Validate window dimensions\n if (config.window?.width !== undefined && (config.window.width < 100 || config.window.width > 10000)) {\n throw new Error(`Invalid window width: ${config.window.width}. Must be between 100 and 10000 pixels.`)\n }\n if (config.window?.height !== undefined && (config.window.height < 100 || config.window.height > 10000)) {\n throw new Error(`Invalid window height: ${config.window.height}. Must be between 100 and 10000 pixels.`)\n }\n\n // Validate that either html or url is provided, not both\n if (config.html && config.url) {\n console.warn('⚠️ Both html and url provided. URL will take precedence.')\n }\n\n this.config = {\n ...config,\n window: {\n title: 'Craft App',\n width: 800,\n height: 600,\n resizable: true,\n frameless: false,\n transparent: false,\n alwaysOnTop: false,\n fullscreen: false,\n hotReload: detectDevMode(),\n devTools: detectDevMode(),\n systemTray: false,\n ...config.window,\n },\n }\n }\n\n /**\n * Create and show a window with HTML content\n */\n async show(html?: string): Promise<void> {\n if (html) {\n this.config.html = html\n }\n\n // Validate that we have something to show (unless it's menubar-only mode)\n if (!this.config.window?.menubarOnly && !this.config.html && !this.config.url) {\n throw new Error(\n 'No content to display. Provide either html or url:\\n' +\n ' show(html, options) or loadURL(url, options)'\n )\n }\n\n const args = this.buildArgs()\n const craftPath = await this.findCraftBinary()\n\n // Probe the binary's reported version and warn if the SDK and native\n // halves drift. Fire-and-forget — the warning isn't load-bearing and\n // shouldn't gate startup.\n void probeBinaryVersion(craftPath)\n\n this.process = spawn(craftPath, args, {\n stdio: this.config.quiet ? 'ignore' : 'inherit',\n })\n\n return new Promise((resolve, reject) => {\n this.process?.on('error', (error: Error & { code?: string }) => {\n if (error.code === 'ENOENT') {\n // Single canonical message — we no longer probe a matrix of\n // \"we tried these locations\" since pantry is the install\n // surface of record.\n reject(new Error(craftBinaryNotFoundMessage(craftPath)))\n return\n }\n if (error.code === 'EACCES') {\n reject(new Error(\n `❌ Failed to start Craft process: ${error.message}\\n\\n`\n + `Permission denied on the binary at ${craftPath}.\\n`\n + 'Re-run `pantry install craft` to restore correct permissions, '\n + `or chmod +x the file directly.`,\n ))\n return\n }\n reject(new Error(\n `❌ Failed to start Craft process: ${error.message}\\n\\n`\n + 'For troubleshooting, visit:\\n'\n + ' https://github.com/home-lang/craft/issues',\n ))\n })\n\n this.process?.on('exit', (code) => {\n if (code === 0 || code === null) {\n resolve()\n }\n else {\n reject(new Error(\n `❌ Craft process exited with code ${code}\\n\\n` +\n 'This may indicate:\\n' +\n ' • Invalid window configuration\\n' +\n ' • Malformed HTML content\\n' +\n ' • System resource constraints\\n\\n' +\n 'Check the console output above for more details.'\n ))\n }\n })\n })\n }\n\n /**\n * Load a URL in the window\n */\n async loadURL(url: string): Promise<void> {\n this.config.url = url\n return this.show()\n }\n\n /**\n * Close the window\n */\n close(): void {\n if (this.process) {\n this.process.kill()\n }\n }\n\n private buildArgs(): string[] {\n const args: string[] = []\n const { window, html, url } = this.config\n\n // Menubar-only mode doesn't need content\n if (!window?.menubarOnly) {\n // URL takes precedence over HTML\n if (url) {\n args.push('--url', url)\n }\n else if (html) {\n args.push('--html', html)\n }\n }\n\n // Window options\n if (window?.title)\n args.push('--title', window.title)\n if (window?.width)\n args.push('--width', String(window.width))\n if (window?.height)\n args.push('--height', String(window.height))\n if (window?.x !== undefined)\n args.push('--x', String(window.x))\n if (window?.y !== undefined)\n args.push('--y', String(window.y))\n\n // Boolean flags\n if (window?.frameless)\n args.push('--frameless')\n if (window?.transparent)\n args.push('--transparent')\n if (window?.alwaysOnTop)\n args.push('--always-on-top')\n if (window?.fullscreen)\n args.push('--fullscreen')\n if (!window?.resizable)\n args.push('--no-resize')\n if (window?.darkMode)\n args.push('--dark')\n if (window?.hotReload)\n args.push('--hot-reload')\n if (window?.devTools === false)\n args.push('--no-devtools')\n if (window?.systemTray)\n args.push('--system-tray')\n if (window?.hideDockIcon)\n args.push('--hide-dock-icon')\n if (window?.menubarOnly)\n args.push('--menubar-only')\n if (window?.titlebarHidden)\n args.push('--titlebar-hidden')\n if (window?.webSidebarMaterial) {\n args.push('--web-sidebar-material')\n if (window?.webSidebarWidth)\n args.push('--web-sidebar-width', String(window.webSidebarWidth))\n if (window?.webSidebarMaterialOpacity !== undefined)\n args.push('--web-sidebar-material-opacity', String(window.webSidebarMaterialOpacity))\n }\n if (window?.icon)\n args.push('--icon', window.icon)\n\n if (window?.nativeSidebar) {\n args.push('--native-sidebar')\n if (window?.sidebarWidth)\n args.push('--sidebar-width', String(window.sidebarWidth))\n const sidebarConfig = window?.sidebarConfig\n ? {\n ...window.sidebarConfig,\n variant: window.sidebarConfig.variant ?? window.sidebarVariant,\n material: window.sidebarConfig.material ?? window.sidebarMaterial,\n backgroundEffect: window.sidebarConfig.backgroundEffect ?? window.sidebarBackgroundEffect,\n allowsVibrancy: window.sidebarConfig.allowsVibrancy ?? window.sidebarAllowsVibrancy,\n }\n : undefined\n if (sidebarConfig?.variant === 'desktop') {\n sidebarConfig.material = sidebarConfig.material ?? 'sidebar'\n sidebarConfig.backgroundEffect = sidebarConfig.backgroundEffect ?? 'vibrancy'\n sidebarConfig.allowsVibrancy = sidebarConfig.allowsVibrancy ?? true\n }\n if (sidebarConfig) {\n // sidebarConfig used to be JSON-stringified onto argv directly,\n // which (a) hits OS argv length limits on macOS/Linux, (b) breaks\n // on cmd.exe when the config contains newlines, and (c) leaks the\n // entire config to anyone running `ps`. Inline tiny configs that\n // are clearly safe (≤ 4 KiB, no newlines) and spill larger ones\n // into a temp file via `--sidebar-config-file <path>`.\n let json: string\n try {\n json = JSON.stringify(sidebarConfig)\n }\n catch (e) {\n throw new Error(`Failed to serialize sidebarConfig: ${(e as Error).message}`)\n }\n // macOS ARG_MAX is 1 MiB; Linux is 128 KiB+ on every modern kernel.\n // The native craft binary only implements the inline `--sidebar-config`\n // flag (it does NOT recognise `--sidebar-config-file`), so falling\n // back to a file write makes Craft drop our config and render its\n // built-in Finder placeholder instead. Bumping the inline ceiling\n // to 256 KiB lets every realistic dashboard config (~10–20 KiB)\n // round-trip; only a config with embedded newlines (which the OS\n // chokes on for argv) drops to the file path.\n const inlineLimit = 256 * 1024\n const safeForArgv = json.length <= inlineLimit && !json.includes('\\n') && !json.includes('\\r')\n if (safeForArgv) {\n args.push('--sidebar-config', json)\n }\n else {\n const dir = mkdtempSync(join(tmpdir(), 'craft-sidebar-'))\n const path = join(dir, 'sidebar-config.json')\n writeFileSync(path, json, 'utf-8')\n args.push('--sidebar-config-file', path)\n }\n }\n }\n\n if (this.config.quiet)\n args.push('--quiet')\n\n return args\n }\n\n /**\n * Resolve the `craft` binary to spawn.\n *\n * Craft ships through the pantry registry (`pantry install craft`),\n * so once pantry is set up the binary is on PATH and we just spawn\n * `'craft'`. The two escape hatches are `config.craftPath` (per-app\n * pin) and the `CRAFT_BIN` env var (test/dev override). Anything\n * else is delegated to PATH lookup; the error path on the spawn\n * itself surfaces a pantry-pointing message via\n * {@link craftBinaryNotFoundMessage}.\n */\n private async findCraftBinary(): Promise<string> {\n return resolveCraftBinary(this.config.craftPath)\n }\n}\n\n/**\n * Create a new Craft app instance\n */\nexport function createApp(config?: AppConfig): CraftApp {\n return new CraftApp(config)\n}\n\n/**\n * Quick helper to show a window with HTML\n */\nexport async function show(html: string, options?: WindowOptions): Promise<void> {\n const app = new CraftApp({ html, window: options })\n return app.show()\n}\n\n/**\n * Quick helper to load a URL\n */\nexport async function loadURL(url: string, options?: WindowOptions): Promise<void> {\n const app = new CraftApp({ url, window: options })\n return app.show()\n}\n\n// Export types explicitly, excluding names already exported by './api'\n// Excluded duplicates: SidebarItem, SidebarSection, SidebarConfig, SidebarSelectEvent,\n// TrayClickEvent, MenuItem, AppInfo, NotificationOptions, DeviceInfo,\n// PermissionStatus, ShareOptions, DisplayInfo\nexport type {\n WindowOptions,\n CraftSidebarAPI,\n AppConfig,\n CraftTrayAPI,\n CraftWindowAPI,\n CraftAppAPI,\n CraftBridgeAPI,\n Permission,\n HapticType,\n CameraOptions,\n PhotoPickerOptions,\n CraftMobileAPI,\n CraftFileSystemAPI,\n CraftDatabaseAPI,\n CraftHttpAPI,\n CraftCryptoAPI,\n CraftEventType,\n CraftEventMap,\n CraftEventHandler,\n CraftEventEmitter,\n IOSConfig,\n AndroidConfig,\n MacOSConfig,\n WindowsConfig,\n LinuxConfig,\n CraftAppConfig,\n} from './types'\n",
|
|
6
|
+
"/**\n * Locate the `craft` native binary.\n *\n * The shipping contract is: **Craft is distributed via the pantry\n * registry**. `pantry install craft` (or any pantry-managed environment\n * that includes craft) puts the binary on PATH; the SDK and CLI then\n * just spawn `'craft'` directly. The previous \"look in zig-out, then\n * fall back to PATH\" probing is gone — it was load-bearing in the\n * monorepo dev loop, but consumers of the SDK / CLI should never see it.\n *\n * Two escape hatches remain, in order of precedence:\n *\n * 1. `config.craftPath` (SDK only): an explicit absolute path the\n * caller pinned. Validated to exist; otherwise we throw.\n * 2. `CRAFT_BIN` env var: same idea, useful for tests and for the\n * monorepo dev loop where the binary lives at\n * `packages/zig/zig-out/bin/craft` and isn't yet a registry build.\n *\n * Everything else delegates to `'craft'` and lets the OS resolve PATH.\n * If the spawn produces ENOENT we surface a single, deterministic error\n * pointing at pantry — no path probing, no matrix of \"we tried these\n * locations\" output, just one canonical answer.\n */\n\nimport { existsSync } from 'node:fs'\n\n/**\n * Resolve a `craft` binary path.\n *\n * @param explicit Optional caller-supplied absolute path (e.g. SDK\n * `AppConfig.craftPath`). Required to exist when present.\n * @returns The string to pass to `spawn(...)`. Either `explicit`,\n * `process.env.CRAFT_BIN`, or the bare `'craft'` for PATH lookup.\n */\nexport function resolveCraftBinary(explicit?: string): string {\n if (explicit) {\n if (!existsSync(explicit)) {\n throw new Error(`Custom Craft binary path not found: ${explicit}`)\n }\n return explicit\n }\n const fromEnv = typeof process !== 'undefined' ? process.env.CRAFT_BIN : undefined\n if (fromEnv) {\n if (!existsSync(fromEnv)) {\n throw new Error(`CRAFT_BIN points to ${fromEnv}, which does not exist`)\n }\n return fromEnv\n }\n // PATH lookup. The OS resolves `'craft'` to whatever pantry installed.\n return 'craft'\n}\n\n/**\n * Build a deterministic, pantry-aware error for the case where the\n * spawn errored with ENOENT (binary not found on PATH). Used as the\n * `process.on('error', …)` handler in both the SDK and the CLI.\n */\nexport function craftBinaryNotFoundMessage(triedPath: string): string {\n return [\n `Craft native binary not found (tried \"${triedPath}\").`,\n '',\n 'Craft ships through the pantry package registry. Install it with:',\n '',\n ' pantry install craft',\n '',\n 'or, in a project, declare it in deps.yaml / pantry.jsonc and run',\n ' pantry install',\n '',\n 'See https://pantry.dev/quickstart for pantry installation instructions.',\n 'For monorepo development you can also point CRAFT_BIN at a local build.',\n ].join('\\n')\n}\n",
|
|
7
|
+
"/**\n * Craft Packaging API\n *\n * Enables users to create installers for their Craft applications\n * across all platforms (macOS, Windows, Linux)\n */\n\nimport { spawn } from 'child_process'\nimport { createHash } from 'crypto'\nimport {\n chmodSync,\n copyFileSync,\n cpSync,\n existsSync,\n lstatSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n readdirSync,\n rmSync,\n writeFileSync,\n} from 'fs'\nimport { homedir, tmpdir } from 'os'\nimport { basename, join } from 'path'\nimport { deflateRawSync } from 'zlib'\n\n// Dependency-free ZIP writer. Craft used to pull `archiver` (→ archiver-utils →\n// lazystream → readable-stream) solely to zip a single Windows binary; that\n// transitive tree is heavy and broke downstream installs (lazystream requires\n// the removed `readable-stream/passthrough` subpath). Bun/Node ship raw DEFLATE\n// via node:zlib, so we assemble the ZIP container ourselves.\nconst CRC32_TABLE: Uint32Array = (() => {\n const table = new Uint32Array(256)\n for (let n = 0; n < 256; n++) {\n let c = n\n for (let k = 0; k < 8; k++)\n c = c & 1 ? 0xEDB88320 ^ (c >>> 1) : c >>> 1\n table[n] = c >>> 0\n }\n return table\n})()\n\nfunction crc32(data: Uint8Array): number {\n let c = 0xFFFFFFFF\n for (let i = 0; i < data.length; i++)\n c = CRC32_TABLE[(c ^ data[i]) & 0xFF] ^ (c >>> 8)\n return (c ^ 0xFFFFFFFF) >>> 0\n}\n\n/** DOS-format date/time for ZIP local/central headers. */\nfunction dosDateTime(d: Date): { time: number; date: number } {\n const time = (d.getHours() << 11) | (d.getMinutes() << 5) | (d.getSeconds() >> 1)\n const date = ((d.getFullYear() - 1980) << 9) | ((d.getMonth() + 1) << 5) | d.getDate()\n return { time: time & 0xFFFF, date: date & 0xFFFF }\n}\n\n/**\n * Build a ZIP archive (DEFLATE, level 9) from in-memory entries. Emits the\n * standard container: one local-file-header + data record per entry, a central\n * directory, and the end-of-central-directory record. No external dependencies.\n */\nfunction buildZip(entries: Array<{ name: string; data: Uint8Array }>): Buffer {\n const { time, date } = dosDateTime(new Date())\n const locals: Buffer[] = []\n const central: Buffer[] = []\n let offset = 0\n\n for (const entry of entries) {\n const nameBytes = Buffer.from(entry.name, 'utf8')\n const compressed = deflateRawSync(entry.data, { level: 9 })\n const crc = crc32(entry.data)\n\n const lfh = Buffer.alloc(30)\n lfh.writeUInt32LE(0x04034B50, 0) // local file header signature\n lfh.writeUInt16LE(20, 4) // version needed to extract\n lfh.writeUInt16LE(0, 6) // general-purpose bit flag\n lfh.writeUInt16LE(8, 8) // compression method: deflate\n lfh.writeUInt16LE(time, 10)\n lfh.writeUInt16LE(date, 12)\n lfh.writeUInt32LE(crc, 14)\n lfh.writeUInt32LE(compressed.length, 18)\n lfh.writeUInt32LE(entry.data.length, 22)\n lfh.writeUInt16LE(nameBytes.length, 26)\n lfh.writeUInt16LE(0, 28) // extra field length\n locals.push(lfh, nameBytes, compressed)\n\n const cdh = Buffer.alloc(46)\n cdh.writeUInt32LE(0x02014B50, 0) // central directory header signature\n cdh.writeUInt16LE(20, 4) // version made by\n cdh.writeUInt16LE(20, 6) // version needed to extract\n cdh.writeUInt16LE(0, 8) // general-purpose bit flag\n cdh.writeUInt16LE(8, 10) // compression method\n cdh.writeUInt16LE(time, 12)\n cdh.writeUInt16LE(date, 14)\n cdh.writeUInt32LE(crc, 16)\n cdh.writeUInt32LE(compressed.length, 20)\n cdh.writeUInt32LE(entry.data.length, 24)\n cdh.writeUInt16LE(nameBytes.length, 28)\n cdh.writeUInt16LE(0, 30) // extra field length\n cdh.writeUInt16LE(0, 32) // file comment length\n cdh.writeUInt16LE(0, 34) // disk number start\n cdh.writeUInt16LE(0, 36) // internal file attributes\n cdh.writeUInt32LE(0, 38) // external file attributes\n cdh.writeUInt32LE(offset, 42) // relative offset of local header\n central.push(cdh, nameBytes)\n\n offset += lfh.length + nameBytes.length + compressed.length\n }\n\n const centralBuf = Buffer.concat(central)\n const eocd = Buffer.alloc(22)\n eocd.writeUInt32LE(0x06054B50, 0) // end of central directory signature\n eocd.writeUInt16LE(0, 4) // number of this disk\n eocd.writeUInt16LE(0, 6) // disk where central directory starts\n eocd.writeUInt16LE(entries.length, 8) // central directory records on this disk\n eocd.writeUInt16LE(entries.length, 10) // total central directory records\n eocd.writeUInt32LE(centralBuf.length, 12) // size of central directory\n eocd.writeUInt32LE(offset, 16) // offset of central directory\n eocd.writeUInt16LE(0, 20) // comment length\n return Buffer.concat([...locals, centralBuf, eocd])\n}\n\nexport interface PackageConfig {\n /** Application name */\n name: string\n\n /** Application version (semver) */\n version: string\n\n /** Application description */\n description?: string\n\n /** Author/Maintainer */\n author?: string\n\n /** Homepage URL */\n homepage?: string\n\n /** Path to application binary */\n binaryPath: string\n\n /** Path to application icon (platform-specific formats) */\n iconPath?: string\n\n /** Output directory for installers */\n outDir?: string\n\n /** Bundle identifier (macOS/iOS) */\n bundleId?: string\n\n /** Platforms to build for */\n platforms?: Array<'macos' | 'windows' | 'linux'>\n\n /** macOS-specific options */\n macos?: {\n /** Create DMG installer */\n dmg?: boolean\n\n /** Create PKG installer */\n pkg?: boolean\n\n /**\n * Build the PKG as a Mac App Store submission with `productbuild` instead\n * of a plain `pkgbuild` installer. Requires `installerIdentity`, and the\n * app itself must be signed with a `3rd Party Mac Developer Application`\n * identity plus a `.provisionprofile`.\n */\n appStore?: boolean\n\n /** Application code signing identity, e.g. \"Developer ID Application: Acme (TEAMID)\" */\n signIdentity?: string\n\n /** Installer code signing identity, e.g. \"3rd Party Mac Developer Installer: Acme (TEAMID)\" */\n installerIdentity?: string\n\n /** Path to the entitlements plist applied when signing the app */\n entitlements?: string\n\n /** Path to a `.provisionprofile` embedded as `Contents/embedded.provisionprofile` */\n provisioningProfile?: string\n\n /** Build number (`CFBundleVersion`). Defaults to `version`. */\n buildNumber?: string\n\n /** `LSApplicationCategoryType`, e.g. \"public.app-category.utilities\" — required by the App Store */\n category?: string\n\n /** `LSMinimumSystemVersion`, e.g. \"13.0\" */\n minimumSystemVersion?: string\n\n /**\n * Menu bar app: sets `LSUIElement` so the app has no Dock icon and never\n * appears in the app switcher.\n */\n menuBarOnly?: boolean\n\n /** Notarize the app. Direct distribution only — App Store builds are notarized by Apple. */\n notarize?: boolean\n\n /** Apple ID for notarization */\n appleId?: string\n\n /** App-specific password */\n applePassword?: string\n\n /** Team ID for notarization. Required by `notarytool` alongside `appleId`. */\n teamId?: string\n\n /**\n * Extra executables copied into `Contents/MacOS/` beside the app binary.\n *\n * A server-backed app (a Bun program driving a Craft webview, say) spawns a\n * helper at runtime; bundle it here so the installed `.app` is\n * self-contained. Resolve it relative to the running executable — on macOS\n * the helper lands next to `process.execPath`.\n */\n additionalExecutables?: string[]\n }\n\n /** Windows-specific options */\n windows?: {\n /** Create MSI installer */\n msi?: boolean\n\n /** Create ZIP archive */\n zip?: boolean\n\n /** Architecture encoded in MSI metadata (defaults to the native host) */\n architecture?: 'x86' | 'x64' | 'arm64'\n\n /** Code signing certificate */\n certificatePath?: string\n\n /** Certificate password */\n certificatePassword?: string\n }\n\n /** Linux-specific options */\n linux?: {\n /** Create DEB package */\n deb?: boolean\n\n /** Create RPM package */\n rpm?: boolean\n\n /** Create AppImage */\n appImage?: boolean\n\n /** Desktop categories */\n categories?: string[]\n\n /** Dependencies (Debian) */\n debDependencies?: string[]\n\n /** Dependencies (RPM) */\n rpmDependencies?: string[]\n }\n}\n\ninterface MSIOptions {\n name: string\n version: string\n binaryPath: string\n outputPath: string\n manufacturer: string\n architecture: 'x86' | 'x64' | 'arm64'\n certificatePath?: string\n certificatePassword?: string\n}\n\nexport interface PackageResult {\n success: boolean\n platform: string\n format: string\n outputPath?: string\n error?: string\n}\n\nexport function formatPackagingCommandError(tool: string, code: number | null, stdout: string, stderr: string): string {\n const detail = `${stdout}${stderr}`.trim()\n return `${tool} exited with code ${code}${detail ? `: ${detail}` : ''}`\n}\n\n/**\n * Package a Craft application for distribution\n */\nexport async function packageApp(config: PackageConfig): Promise<PackageResult[]> {\n const results: PackageResult[] = []\n\n // Validate config\n if (!config.binaryPath || !existsSync(config.binaryPath)) {\n throw new Error(`Binary not found: ${config.binaryPath}`)\n }\n\n // Default platforms: current platform only\n const platforms = config.platforms || [detectPlatform()]\n\n // Create output directory\n const outDir = config.outDir || join(process.cwd(), 'dist')\n if (!existsSync(outDir)) {\n mkdirSync(outDir, { recursive: true })\n }\n\n // Package for each platform\n for (const platform of platforms) {\n switch (platform) {\n case 'macos':\n results.push(...await packageMacOS(config, outDir))\n break\n case 'windows':\n results.push(...await packageWindows(config, outDir))\n break\n case 'linux':\n results.push(...await packageLinux(config, outDir))\n break\n }\n }\n\n return results\n}\n\n/**\n * Package for macOS (DMG + PKG)\n */\nasync function packageMacOS(config: PackageConfig, outDir: string): Promise<PackageResult[]> {\n const results: PackageResult[] = []\n const { name, version, bundleId = `com.myapp.${name.toLowerCase()}` } = config\n const opts = config.macos || {}\n\n // App Store builds run sandboxed, so they must not opt into the hardened\n // runtime; every other distribution channel requires it for notarization.\n const hardenedRuntime = !opts.appStore\n\n // Create app bundle\n const appBundlePath = join(outDir, `${name}.app`)\n const appBundle = createMacOSAppBundle({\n name,\n version,\n bundleId,\n buildNumber: opts.buildNumber,\n category: opts.category,\n minimumSystemVersion: opts.minimumSystemVersion,\n menuBarOnly: opts.menuBarOnly,\n binaryPath: config.binaryPath,\n iconPath: config.iconPath,\n provisioningProfile: opts.provisioningProfile,\n additionalExecutables: opts.additionalExecutables,\n outputPath: appBundlePath,\n })\n\n if (!appBundle.success) {\n results.push({\n success: false,\n platform: 'macos',\n format: 'app',\n error: appBundle.error,\n })\n return results\n }\n\n // Sign the bundle before it is wrapped into a DMG or PKG — signing after\n // packaging would leave the copy inside the installer unsigned.\n if (opts.signIdentity) {\n const signed = await runTool('codesign', codesignArguments({\n path: appBundlePath,\n identity: opts.signIdentity,\n entitlements: opts.entitlements,\n hardenedRuntime,\n }))\n if (!signed.success) {\n results.push({ success: false, platform: 'macos', format: 'app', error: signed.error })\n return results\n }\n }\n else if (opts.appStore) {\n results.push({\n success: false,\n platform: 'macos',\n format: 'pkg',\n error: 'App Store packaging requires macos.signIdentity (a \"3rd Party Mac Developer Application\" identity)',\n })\n return results\n }\n\n results.push({ success: true, platform: 'macos', format: 'app', outputPath: appBundlePath })\n\n // Create DMG\n if (opts.dmg !== false) {\n const outputPath = join(outDir, `${name}-${version}.dmg`)\n const dmgResult = await createDMG({ appBundlePath, outputPath, volumeName: name })\n results.push({\n success: dmgResult.success,\n platform: 'macos',\n format: 'dmg',\n outputPath: dmgResult.outputPath,\n error: dmgResult.error,\n })\n if (dmgResult.success)\n results.push(...await notarizeIfRequested(opts, outputPath, 'dmg'))\n }\n\n // Create PKG\n if (opts.pkg || opts.appStore) {\n const outputPath = join(outDir, `${name}-${version}.pkg`)\n const pkgResult = await createPKG({\n appBundlePath,\n outputPath,\n identifier: bundleId,\n version,\n appStore: opts.appStore === true,\n installerIdentity: opts.installerIdentity,\n })\n results.push({\n success: pkgResult.success,\n platform: 'macos',\n format: opts.appStore ? 'pkg (app store)' : 'pkg',\n outputPath: pkgResult.outputPath,\n error: pkgResult.error,\n })\n // App Store submissions are notarized by Apple during review.\n if (pkgResult.success && !opts.appStore)\n results.push(...await notarizeIfRequested(opts, outputPath, 'pkg'))\n }\n\n return results\n}\n\n/**\n * Notarize and staple an artifact when `macos.notarize` is set. Returns the\n * result rows to append, or nothing when notarization was not requested.\n */\nasync function notarizeIfRequested(\n opts: NonNullable<PackageConfig['macos']>,\n artifactPath: string,\n format: string,\n): Promise<PackageResult[]> {\n if (!opts.notarize)\n return []\n\n if (!opts.appleId || !opts.applePassword || !opts.teamId) {\n return [{\n success: false,\n platform: 'macos',\n format: `${format} (notarize)`,\n error: 'Notarization requires macos.appleId, macos.applePassword and macos.teamId',\n }]\n }\n\n const submitted = await runTool('xcrun', notarytoolArguments({\n artifactPath,\n appleId: opts.appleId,\n applePassword: opts.applePassword,\n teamId: opts.teamId,\n }))\n if (!submitted.success)\n return [{ success: false, platform: 'macos', format: `${format} (notarize)`, error: submitted.error }]\n\n const stapled = await runTool('xcrun', ['stapler', 'staple', artifactPath])\n return [{\n success: stapled.success,\n platform: 'macos',\n format: `${format} (notarize)`,\n outputPath: stapled.success ? artifactPath : undefined,\n error: stapled.success ? undefined : stapled.error,\n }]\n}\n\n/**\n * Package for Windows (MSI + ZIP)\n */\nasync function packageWindows(config: PackageConfig, outDir: string): Promise<PackageResult[]> {\n const results: PackageResult[] = []\n const { name, version } = config\n const opts = config.windows || {}\n\n // Create MSI (if WiX available)\n if (opts.msi !== false) {\n const msiResult = await createMSI({\n name,\n version,\n binaryPath: config.binaryPath,\n outputPath: join(outDir, `${name}-${version}.msi`),\n manufacturer: config.author || 'Unknown',\n architecture: opts.architecture || windowsArchitecture(process.arch),\n certificatePath: opts.certificatePath,\n certificatePassword: opts.certificatePassword,\n })\n results.push({\n success: msiResult.success,\n platform: 'windows',\n format: 'msi',\n outputPath: msiResult.outputPath,\n error: msiResult.error,\n })\n }\n\n // Create ZIP (fallback)\n if (opts.zip || opts.msi === false) {\n const zipResult = await createZIP({\n name,\n version,\n binaryPath: config.binaryPath,\n outputPath: join(outDir, `${name}-${version}-windows.zip`),\n })\n results.push({\n success: zipResult.success,\n platform: 'windows',\n format: 'zip',\n outputPath: zipResult.outputPath,\n error: zipResult.error,\n })\n }\n\n return results\n}\n\n/**\n * Package for Linux (DEB + RPM + AppImage)\n */\nasync function packageLinux(config: PackageConfig, outDir: string): Promise<PackageResult[]> {\n const results: PackageResult[] = []\n const { name, version } = config\n const opts = config.linux || {}\n\n // Create DEB\n if (opts.deb !== false) {\n const debResult = await createDEB({\n name,\n version,\n binaryPath: config.binaryPath,\n outputPath: join(outDir, `${name}_${version}_amd64.deb`),\n description: config.description || '',\n maintainer: config.author || 'Unknown',\n dependencies: opts.debDependencies || ['libgtk-3-0', 'libwebkit2gtk-4.1-37'],\n })\n results.push({\n success: debResult.success,\n platform: 'linux',\n format: 'deb',\n outputPath: debResult.outputPath,\n error: debResult.error,\n })\n }\n\n // Create RPM\n if (opts.rpm) {\n const rpmResult = await createRPM({\n name,\n version,\n binaryPath: config.binaryPath,\n outputPath: join(outDir, `${name}-${version}-1.x86_64.rpm`),\n description: config.description || '',\n requires: opts.rpmDependencies || ['gtk3', 'webkit2gtk3'],\n })\n results.push({\n success: rpmResult.success,\n platform: 'linux',\n format: 'rpm',\n outputPath: rpmResult.outputPath,\n error: rpmResult.error,\n })\n }\n\n // Create AppImage\n if (opts.appImage) {\n const appImageResult = await createAppImage({\n name,\n version,\n binaryPath: config.binaryPath,\n outputPath: join(outDir, `${name}-${version}-x86_64.AppImage`),\n iconPath: config.iconPath,\n })\n results.push({\n success: appImageResult.success,\n platform: 'linux',\n format: 'appimage',\n outputPath: appImageResult.outputPath,\n error: appImageResult.error,\n })\n }\n\n return results\n}\n\nexport interface MacOSBundleMetadata {\n name: string\n version: string\n bundleId: string\n /** `CFBundleVersion`. Defaults to `version`. */\n buildNumber?: string\n /** Basename of the `.icns` inside `Contents/Resources`, without the extension */\n iconName?: string\n category?: string\n minimumSystemVersion?: string\n /** Sets `LSUIElement` — no Dock icon, no app switcher entry */\n menuBarOnly?: boolean\n}\n\n/**\n * Render `Contents/Info.plist` for a macOS app bundle.\n *\n * Only the keys that were asked for are emitted, so a plain desktop app does\n * not carry menu-bar or App Store metadata it has no use for.\n */\nexport function macOSInfoPlist(metadata: MacOSBundleMetadata): string {\n const entries: Array<[string, string | true]> = [\n ['CFBundleExecutable', metadata.name],\n ['CFBundleIdentifier', metadata.bundleId],\n ['CFBundleName', metadata.name],\n ['CFBundleShortVersionString', metadata.version],\n ['CFBundleVersion', metadata.buildNumber || metadata.version],\n ['CFBundlePackageType', 'APPL'],\n ['NSHighResolutionCapable', true],\n ]\n\n if (metadata.iconName) entries.push(['CFBundleIconFile', metadata.iconName])\n if (metadata.category) entries.push(['LSApplicationCategoryType', metadata.category])\n if (metadata.minimumSystemVersion) entries.push(['LSMinimumSystemVersion', metadata.minimumSystemVersion])\n if (metadata.menuBarOnly) entries.push(['LSUIElement', true])\n\n const body = entries\n .map(([key, value]) => ` <key>${xml(key)}</key>\\n${value === true ? ' <true/>' : ` <string>${xml(value)}</string>`}`)\n .join('\\n')\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n${body}\n</dict>\n</plist>`\n}\n\n/**\n * Build the `codesign` argument list for an app bundle.\n *\n * App Store builds are sandboxed and must *not* opt into the hardened runtime;\n * Developer ID builds must, or notarization rejects them.\n */\nexport function codesignArguments(opts: {\n path: string\n identity: string\n entitlements?: string\n hardenedRuntime?: boolean\n}): string[] {\n return [\n '--force',\n '--sign', opts.identity,\n '--timestamp',\n ...(opts.hardenedRuntime ? ['--options', 'runtime'] : []),\n ...(opts.entitlements ? ['--entitlements', opts.entitlements] : []),\n '--deep',\n opts.path,\n ]\n}\n\n/** Build the `productbuild` argument list for a Mac App Store submission package. */\nexport function productbuildArguments(opts: {\n appBundlePath: string\n outputPath: string\n identity: string\n}): string[] {\n return [\n '--component', opts.appBundlePath, '/Applications',\n '--sign', opts.identity,\n opts.outputPath,\n ]\n}\n\n/** Build the `xcrun notarytool submit` argument list for a DMG or PKG. */\nexport function notarytoolArguments(opts: {\n artifactPath: string\n appleId: string\n applePassword: string\n teamId: string\n}): string[] {\n return [\n 'notarytool',\n 'submit', opts.artifactPath,\n '--apple-id', opts.appleId,\n '--password', opts.applePassword,\n '--team-id', opts.teamId,\n '--wait',\n ]\n}\n\n/**\n * Helper: Create macOS app bundle\n */\nfunction createMacOSAppBundle(opts: MacOSBundleMetadata & {\n binaryPath: string\n /** Path to a `.icns` file copied into `Contents/Resources` */\n iconPath?: string\n /** Path to a `.provisionprofile` copied to `Contents/embedded.provisionprofile` */\n provisioningProfile?: string\n /** Extra executables copied beside the app binary in `Contents/MacOS/` */\n additionalExecutables?: string[]\n outputPath: string\n}): { success: boolean; error?: string } {\n try {\n const { name, binaryPath, iconPath, provisioningProfile, additionalExecutables, outputPath } = opts\n const contents = join(outputPath, 'Contents')\n const macOS = join(contents, 'MacOS')\n\n // Create bundle structure\n mkdirSync(macOS, { recursive: true })\n mkdirSync(join(contents, 'Resources'), { recursive: true })\n\n // Copy binary\n copyFileSync(binaryPath, join(macOS, name))\n\n // Make executable\n chmodSync(join(macOS, name), 0o755)\n\n // Bundle helper executables (e.g. the webview runtime a server-backed app\n // spawns) so the installed .app is self-contained.\n for (const executable of additionalExecutables || []) {\n if (!existsSync(executable))\n return { success: false, error: `Additional executable not found: ${executable}` }\n const destination = join(macOS, basename(executable))\n copyFileSync(executable, destination)\n chmodSync(destination, 0o755)\n }\n\n // Copy the icon into Resources so CFBundleIconFile resolves\n let iconName: string | undefined\n if (iconPath) {\n if (!existsSync(iconPath))\n return { success: false, error: `Icon not found: ${iconPath}` }\n iconName = basename(iconPath).replace(/\\.icns$/i, '')\n copyFileSync(iconPath, join(contents, 'Resources', `${iconName}.icns`))\n }\n\n // The App Store rejects submissions whose bundle has no embedded profile\n if (provisioningProfile) {\n if (!existsSync(provisioningProfile))\n return { success: false, error: `Provisioning profile not found: ${provisioningProfile}` }\n copyFileSync(provisioningProfile, join(contents, 'embedded.provisionprofile'))\n }\n\n writeFileSync(join(contents, 'Info.plist'), macOSInfoPlist({ ...opts, iconName }))\n\n return { success: true }\n }\ncatch (error) {\n return { success: false, error: (error as Error).message }\n }\n}\n\nconst MEBIBYTE = 1024 * 1024\n\nfunction pathContentBytes(path: string): number {\n const stat = lstatSync(path)\n if (!stat.isDirectory()) return stat.size\n return readdirSync(path).reduce((total, entry) => total + pathContentBytes(join(path, entry)), 0)\n}\n\nexport function dmgCapacityMegabytes(contentBytes: number): number {\n if (!Number.isSafeInteger(contentBytes) || contentBytes < 0)\n throw new Error(`DMG content size must be a non-negative safe integer: ${contentBytes}`)\n const contentMegabytes = Math.ceil(contentBytes / MEBIBYTE)\n return Math.max(64, Math.ceil(contentMegabytes * 1.25) + 32)\n}\n\nexport function dmgCreateArguments(opts: {\n appBundlePath: string\n outputPath: string\n volumeName: string\n}, contentBytes: number): string[] {\n return [\n 'create',\n '-volname', opts.volumeName,\n '-srcfolder', opts.appBundlePath,\n '-size', `${dmgCapacityMegabytes(contentBytes)}m`,\n '-ov',\n '-format', 'UDZO',\n opts.outputPath,\n ]\n}\n\nconst HDIUTIL_MAX_ATTEMPTS = 3\n\nexport function shouldRetryHdiutil(error: string, attempt: number, maxAttempts: number = HDIUTIL_MAX_ATTEMPTS): boolean {\n if (!Number.isInteger(attempt) || attempt < 1 || !Number.isInteger(maxAttempts) || maxAttempts < 1)\n throw new Error('hdiutil retry attempts must be positive integers')\n return attempt < maxAttempts && /(?:resource busy|resource temporarily unavailable)/i.test(error)\n}\n\n/** Run a packaging tool, capturing output so failures carry the real diagnostic. */\nfunction runTool(tool: string, args: string[]): Promise<{ success: true } | { success: false, error: string }> {\n return new Promise((resolve) => {\n const proc = spawn(tool, args)\n let stdout = ''\n let stderr = ''\n proc.stdout?.on('data', chunk => { stdout += chunk.toString() })\n proc.stderr?.on('data', chunk => { stderr += chunk.toString() })\n proc.on('close', (code) => {\n if (code === 0) resolve({ success: true })\n else resolve({ success: false, error: formatPackagingCommandError(tool, code, stdout, stderr) })\n })\n proc.on('error', err => resolve({ success: false, error: err.message }))\n })\n}\n\nconst runHdiutil = (args: string[]) => runTool('hdiutil', args)\n\n/**\n * Helper: Create DMG from app bundle\n */\nasync function createDMG(opts: {\n appBundlePath: string\n outputPath: string\n volumeName: string\n}): Promise<{ success: boolean; outputPath?: string; error?: string }> {\n // hdiutil rejects volume names containing `/`, `:`, or newlines and\n // truncates anything past 27 chars. Surfacing the error early gives a\n // clearer message than the cryptic exit-code-1 hdiutil returns.\n if (!/^[^/:\\n]{1,27}$/.test(opts.volumeName))\n return { success: false, error: `Invalid DMG volume name \"${opts.volumeName}\"; must be 1..27 chars without /, :, or newline` }\n\n const args = dmgCreateArguments(opts, pathContentBytes(opts.appBundlePath))\n const failures: string[] = []\n for (let attempt = 1; attempt <= HDIUTIL_MAX_ATTEMPTS; attempt++) {\n const result = await runHdiutil(args)\n if (result.success) return { success: true, outputPath: opts.outputPath }\n failures.push(`attempt ${attempt}: ${result.error}`)\n if (!shouldRetryHdiutil(result.error, attempt))\n return { success: false, error: failures.join('\\n') }\n\n rmSync(opts.outputPath, { force: true })\n await new Promise(resolve => setTimeout(resolve, attempt * 2000))\n }\n return { success: false, error: failures.join('\\n') }\n}\n\n/**\n * Helper: Create PKG from app bundle\n *\n * Two flavours share this entry point:\n * - a plain `pkgbuild` installer for direct distribution, and\n * - a signed `productbuild` submission package for the Mac App Store, which is\n * the only form App Store Connect accepts.\n */\nasync function createPKG(opts: {\n appBundlePath: string\n outputPath: string\n identifier: string\n version: string\n appStore?: boolean\n installerIdentity?: string\n}): Promise<{ success: boolean; outputPath?: string; error?: string }> {\n // pkgbuild requires reverse-DNS form for the identifier. Validate\n // upfront so the error message is actionable rather than the cryptic\n // pkgbuild \"-identifier requires\" output.\n if (!/^[a-zA-Z0-9._-]+$/.test(opts.identifier) || !opts.identifier.includes('.'))\n return { success: false, error: `Invalid pkg identifier \"${opts.identifier}\"; expected reverse-DNS like com.example.app` }\n\n if (!/^[A-Za-z0-9._+-]+$/.test(opts.version))\n return { success: false, error: `Invalid pkg version \"${opts.version}\"` }\n\n if (opts.appStore) {\n if (!opts.installerIdentity)\n return { success: false, error: 'App Store packaging requires macos.installerIdentity (a \"3rd Party Mac Developer Installer\" identity)' }\n\n const built = await runTool('productbuild', productbuildArguments({\n appBundlePath: opts.appBundlePath,\n outputPath: opts.outputPath,\n identity: opts.installerIdentity,\n }))\n return built.success\n ? { success: true, outputPath: opts.outputPath }\n : { success: false, error: built.error }\n }\n\n // pkgbuild installs the contents of --root, so stage the bundle under the\n // path it should land in.\n const tempDir = mkdtempSync(join(tmpdir(), 'craft-pkg-'))\n try {\n const appsDir = join(tempDir, 'Applications')\n mkdirSync(appsDir, { recursive: true })\n cpSync(opts.appBundlePath, join(appsDir, basename(opts.appBundlePath)), { recursive: true })\n\n const built = await runTool('pkgbuild', [\n '--root', tempDir,\n '--identifier', opts.identifier,\n '--version', opts.version,\n '--install-location', '/',\n ...(opts.installerIdentity ? ['--sign', opts.installerIdentity] : []),\n opts.outputPath,\n ])\n return built.success\n ? { success: true, outputPath: opts.outputPath }\n : { success: false, error: built.error }\n }\n finally {\n rmSync(tempDir, { recursive: true, force: true })\n }\n}\n\n/**\n * Helper: Create Windows MSI\n */\nfunction xml(value: string): string {\n return value.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('\"', '"').replaceAll(`'`, ''')\n}\n\nfunction wixIdentifier(value: string): string {\n const sanitized = value.replace(/[^A-Za-z0-9_.]/g, '_')\n return /^[A-Za-z_]/.test(sanitized) ? sanitized : `_${sanitized}`\n}\n\nfunction deterministicGuid(value: string): string {\n const digest = createHash('sha256').update(value).digest('hex').slice(0, 32).split('')\n digest[12] = '4'\n digest[16] = ((Number.parseInt(digest[16]!, 16) & 0x3) | 0x8).toString(16)\n const hex = digest.join('').toUpperCase()\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n\nexport function windowsArchitecture(architecture: string): 'x86' | 'x64' | 'arm64' {\n if (architecture === 'ia32' || architecture === 'x86') return 'x86'\n if (architecture === 'x64' || architecture === 'arm64') return architecture\n throw new Error(`Unsupported Windows package architecture: ${architecture}`)\n}\n\nexport function renderWixSource(opts: Pick<MSIOptions, 'name' | 'version' | 'manufacturer' | 'architecture'>, sourceName: string): string {\n if (!/^[0-9]+\\.[0-9]+\\.[0-9]+(?:\\.[0-9]+)?$/.test(opts.version)) throw new Error(`MSI version must have 3 or 4 numeric parts: ${opts.version}`)\n const id = wixIdentifier(opts.name)\n const manufacturer = opts.manufacturer.trim() || 'Unknown'\n const upgradeCode = deterministicGuid(`${manufacturer}/${opts.name}`)\n const programFilesFolder = opts.architecture === 'x86' ? 'ProgramFilesFolder' : 'ProgramFiles64Folder'\n const win64 = opts.architecture === 'x86' ? 'no' : 'yes'\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\">\n <Product Id=\"*\" Name=\"${xml(opts.name)}\" Language=\"1033\" Version=\"${opts.version}\" Manufacturer=\"${xml(manufacturer)}\" UpgradeCode=\"${upgradeCode}\">\n <Package InstallerVersion=\"500\" Compressed=\"yes\" InstallScope=\"perMachine\" Platform=\"${opts.architecture}\" />\n <MajorUpgrade AllowDowngrades=\"yes\" />\n <MediaTemplate EmbedCab=\"yes\" />\n <Directory Id=\"TARGETDIR\" Name=\"SourceDir\">\n <Directory Id=\"${programFilesFolder}\">\n <Directory Id=\"INSTALLFOLDER\" Name=\"${xml(opts.name)}\">\n <Component Id=\"${id}Executable\" Guid=\"*\" Win64=\"${win64}\">\n <File Id=\"${id}File\" Source=\"${xml(sourceName)}\" KeyPath=\"yes\" />\n </Component>\n </Directory>\n </Directory>\n </Directory>\n <Feature Id=\"ProductFeature\" Title=\"${xml(opts.name)}\" Level=\"1\">\n <ComponentRef Id=\"${id}Executable\" />\n </Feature>\n </Product>\n</Wix>\n`\n}\n\nexport function windowsExecutableName(name: string): string {\n if (name.length === 0 || name.trim() !== name || /[<>:\"/\\\\|?*\\u0000-\\u001F]/.test(name) || /[. ]$/.test(name))\n throw new Error(`Invalid Windows application name: ${JSON.stringify(name)}`)\n if (/^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\\.|$)/i.test(name))\n throw new Error(`Reserved Windows application name: ${JSON.stringify(name)}`)\n return `${name}.exe`\n}\n\nfunction runCommand(command: string, args: string[], cwd?: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, { cwd, stdio: 'inherit', windowsHide: true })\n child.once('error', reject)\n child.once('close', code => code === 0 ? resolve() : reject(new Error(`${command} exited with code ${code}`)))\n })\n}\n\nasync function createMSI(opts: MSIOptions): Promise<{ success: boolean; outputPath?: string; error?: string }> {\n const tempDir = mkdtempSync(join(tmpdir(), 'craft-msi-'))\n try {\n const binaryName = windowsExecutableName(opts.name)\n const sourcePath = join(tempDir, binaryName)\n const wxsPath = join(tempDir, 'installer.wxs')\n const wixobjPath = join(tempDir, 'installer.wixobj')\n copyFileSync(opts.binaryPath, sourcePath)\n writeFileSync(wxsPath, renderWixSource(opts, binaryName))\n await runCommand('candle.exe', ['-nologo', '-out', wixobjPath, wxsPath], tempDir)\n await runCommand('light.exe', ['-nologo', '-sval', '-out', opts.outputPath, wixobjPath], tempDir)\n if (opts.certificatePath) {\n const signArgs = ['sign', '/fd', 'sha256', '/tr', 'https://timestamp.digicert.com', '/td', 'sha256', '/f', opts.certificatePath]\n if (opts.certificatePassword) signArgs.push('/p', opts.certificatePassword)\n signArgs.push(opts.outputPath)\n await runCommand('signtool.exe', signArgs)\n await runCommand('signtool.exe', ['verify', '/pa', '/all', opts.outputPath])\n }\n return { success: true, outputPath: opts.outputPath }\n }\n catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n const missingTool = /ENOENT|not found/i.test(message)\n return { success: false, error: missingTool ? `WiX Toolset not found: ${message}` : message }\n }\n finally {\n rmSync(tempDir, { recursive: true, force: true })\n }\n}\n\n/**\n * Helper: Create Windows ZIP\n */\nasync function createZIP(opts: {\n name: string\n version: string\n binaryPath: string\n outputPath: string\n}): Promise<{ success: boolean; outputPath?: string; error?: string }> {\n try {\n const data = new Uint8Array(readFileSync(opts.binaryPath))\n const zip = buildZip([{ name: `${opts.name}.exe`, data }])\n writeFileSync(opts.outputPath, zip)\n return { success: true, outputPath: opts.outputPath }\n }\n catch (err) {\n return { success: false, error: `Failed to write ZIP: ${(err as Error).message}` }\n }\n}\n\n/**\n * Helper: Create Linux DEB package\n */\nasync function createDEB(opts: {\n name: string\n version: string\n binaryPath: string\n outputPath: string\n description: string\n maintainer: string\n dependencies: string[]\n}): Promise<{ success: boolean; outputPath?: string; error?: string }> {\n return new Promise((resolve) => {\n try {\n // Validate inputs that get interpolated into the DEBIAN/control file.\n // dpkg's control file is line-oriented; newlines or `,` in fields, or\n // `/` in the package name, corrupt the manifest.\n const sanitizedName = opts.name.toLowerCase()\n const safeDebName = /^[a-z0-9._+-]+$/\n const safeVersion = /^[A-Za-z0-9._+-]+$/\n if (!safeDebName.test(sanitizedName)) {\n resolve({ success: false, error: `DEB package name must match ${safeDebName} (got: ${sanitizedName})` })\n return\n }\n if (!safeVersion.test(opts.version)) {\n resolve({ success: false, error: `DEB version must match ${safeVersion} (got: ${opts.version})` })\n return\n }\n const cleanLine = (s: string): string => s.replace(/[\\r\\n]+/g, ' ').trim()\n const description = cleanLine(opts.description)\n const maintainer = cleanLine(opts.maintainer)\n for (const dep of opts.dependencies) {\n // Allow versioned constraints like `libgtk-3-0 (>= 3.22)`.\n if (!/^[a-z0-9._+-]+(?:\\s*\\([^)\\n,]+\\))?$/i.test(dep)) {\n resolve({ success: false, error: `Invalid DEB dependency \"${dep}\"` })\n return\n }\n }\n\n // Create DEB package structure\n const tempDir = mkdtempSync(join(tmpdir(), 'craft-deb-'))\n const debianDir = join(tempDir, 'DEBIAN')\n const binDir = join(tempDir, 'usr', 'bin')\n const applicationsDir = join(tempDir, 'usr', 'share', 'applications')\n\n mkdirSync(debianDir, { recursive: true })\n mkdirSync(binDir, { recursive: true })\n mkdirSync(applicationsDir, { recursive: true })\n\n // Copy binary\n const binaryName = sanitizedName\n copyFileSync(opts.binaryPath, join(binDir, binaryName))\n chmodSync(join(binDir, binaryName), 0o755)\n\n // Create control file. Every field has been sanitized above.\n const controlContent = `Package: ${sanitizedName}\nVersion: ${opts.version}\nSection: utils\nPriority: optional\nArchitecture: amd64\nDepends: ${opts.dependencies.join(', ')}\nMaintainer: ${maintainer}\nDescription: ${description || opts.name}\n`\n writeFileSync(join(debianDir, 'control'), controlContent)\n\n // Create .desktop file\n const desktopContent = `[Desktop Entry]\nType=Application\nName=${opts.name}\nExec=/usr/bin/${binaryName}\nTerminal=false\nCategories=Utility;\n`\n writeFileSync(join(applicationsDir, `${binaryName}.desktop`), desktopContent)\n\n // Build DEB using dpkg-deb\n const proc = spawn('dpkg-deb', ['--build', tempDir, opts.outputPath])\n\n proc.on('close', (code) => {\n rmSync(tempDir, { recursive: true, force: true })\n if (code === 0) {\n resolve({ success: true, outputPath: opts.outputPath })\n }\nelse {\n resolve({ success: false, error: `dpkg-deb exited with code ${code}` })\n }\n })\n\n proc.on('error', (err) => {\n rmSync(tempDir, { recursive: true, force: true })\n resolve({ success: false, error: err.message })\n })\n }\ncatch (error) {\n resolve({ success: false, error: (error as Error).message })\n }\n })\n}\n\n/**\n * Helper: Create Linux RPM package\n */\nasync function createRPM(opts: {\n name: string\n version: string\n binaryPath: string\n outputPath: string\n description: string\n requires: string[]\n}): Promise<{ success: boolean; outputPath?: string; error?: string }> {\n return new Promise((resolve) => {\n\n try {\n // Create RPM build structure\n const buildRoot = join(homedir(), 'rpmbuild')\n const specDir = join(buildRoot, 'SPECS')\n const sourcesDir = join(buildRoot, 'SOURCES')\n const buildDir = join(buildRoot, 'BUILD')\n const rpmsDir = join(buildRoot, 'RPMS')\n\n mkdirSync(specDir, { recursive: true })\n mkdirSync(sourcesDir, { recursive: true })\n mkdirSync(buildDir, { recursive: true })\n mkdirSync(rpmsDir, { recursive: true })\n\n // Validate inputs that get interpolated into the .spec file. RPM spec\n // files treat `%` as a macro prefix and parse line-by-line, so\n // newlines or `%` in user data could inject scriptlets / corrupt the\n // spec. Reject early with a clear message.\n const safePackageName = /^[a-z0-9._+-]+$/i\n const safeVersion = /^[A-Za-z0-9._+-]+$/\n const sanitizedName = opts.name.toLowerCase()\n if (!safePackageName.test(sanitizedName)) {\n return resolve({ success: false, error: `RPM package name must match ${safePackageName} (got: ${sanitizedName})` })\n }\n if (!safeVersion.test(opts.version)) {\n return resolve({ success: false, error: `RPM version must match ${safeVersion} (got: ${opts.version})` })\n }\n // Description / summary go into single-line spec headers; collapse\n // newlines and reject `%` to prevent macro expansion.\n const cleanLine = (s: string): string => s.replace(/[\\r\\n]+/g, ' ').replace(/%/g, '%%')\n const summary = cleanLine(opts.description || opts.name)\n const description = (opts.description || opts.name)\n .split(/\\r?\\n/).map(line => line.replace(/%/g, '%%')).join('\\n')\n const requires = opts.requires.map((r) => {\n if (!safePackageName.test(r)) {\n throw new Error(`RPM Requires entry must match ${safePackageName} (got: ${r})`)\n }\n return r\n }).join(', ')\n\n // Copy binary to sources\n copyFileSync(opts.binaryPath, join(sourcesDir, sanitizedName))\n\n // Create spec file\n const specContent = `Name: ${sanitizedName}\nVersion: ${opts.version}\nRelease: 1%{?dist}\nSummary: ${summary}\nLicense: MIT\nRequires: ${requires}\n\n%description\n${description}\n\n%install\nmkdir -p %{buildroot}/usr/bin\ninstall -m 755 %{SOURCE0} %{buildroot}/usr/bin/${sanitizedName}\n\n%files\n/usr/bin/${sanitizedName}\n`\n const specPath = join(specDir, `${opts.name.toLowerCase()}.spec`)\n writeFileSync(specPath, specContent)\n\n // Build RPM\n const proc = spawn('rpmbuild', ['-bb', specPath])\n\n proc.on('close', (code) => {\n if (code === 0) {\n // Find the built RPM and move it\n const rpmName = `${opts.name.toLowerCase()}-${opts.version}-1.x86_64.rpm`\n const builtRpmPath = join(rpmsDir, 'x86_64', rpmName)\n try {\n copyFileSync(builtRpmPath, opts.outputPath)\n resolve({ success: true, outputPath: opts.outputPath })\n }\ncatch {\n resolve({ success: false, error: 'Failed to copy built RPM' })\n }\n }\nelse {\n resolve({ success: false, error: `rpmbuild exited with code ${code}` })\n }\n })\n\n proc.on('error', (err) => {\n resolve({ success: false, error: err.message })\n })\n }\ncatch (error) {\n resolve({ success: false, error: (error as Error).message })\n }\n })\n}\n\n/**\n * Helper: Create Linux AppImage\n */\nasync function createAppImage(opts: {\n name: string\n version: string\n binaryPath: string\n outputPath: string\n iconPath?: string\n}): Promise<{ success: boolean; outputPath?: string; error?: string }> {\n return new Promise((resolve) => {\n\n try {\n // Create AppDir structure\n const appDir = mkdtempSync(join(tmpdir(), 'craft-appimage-'))\n const appDirPath = join(appDir, `${opts.name}.AppDir`)\n const binDir = join(appDirPath, 'usr', 'bin')\n const shareDir = join(appDirPath, 'usr', 'share')\n\n mkdirSync(binDir, { recursive: true })\n mkdirSync(shareDir, { recursive: true })\n\n // Copy binary\n const binaryName = opts.name.toLowerCase()\n copyFileSync(opts.binaryPath, join(binDir, binaryName))\n chmodSync(join(binDir, binaryName), 0o755)\n\n // Create AppRun script\n const appRunContent = `#!/bin/bash\nSELF=$(readlink -f \"$0\")\nHERE=\\${SELF%/*}\nexport PATH=\"\\${HERE}/usr/bin/:\\${PATH}\"\nexec \"\\${HERE}/usr/bin/${binaryName}\" \"$@\"\n`\n writeFileSync(join(appDirPath, 'AppRun'), appRunContent)\n chmodSync(join(appDirPath, 'AppRun'), 0o755)\n\n // Create .desktop file\n const desktopContent = `[Desktop Entry]\nType=Application\nName=${opts.name}\nExec=${binaryName}\nTerminal=false\nCategories=Utility;\nIcon=${binaryName}\n`\n writeFileSync(join(appDirPath, `${binaryName}.desktop`), desktopContent)\n\n // Copy or create icon\n if (opts.iconPath && existsSync(opts.iconPath)) {\n copyFileSync(opts.iconPath, join(appDirPath, `${binaryName}.png`))\n }\nelse {\n // Create placeholder icon (1x1 PNG)\n const placeholderPng = Buffer.from([\n 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,\n 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,\n 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xde, 0x00, 0x00, 0x00,\n 0x0c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff, 0xff, 0x3f,\n 0x00, 0x05, 0xfe, 0x02, 0xfe, 0xdc, 0xcc, 0x59, 0xe7, 0x00, 0x00, 0x00,\n 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82\n ])\n writeFileSync(join(appDirPath, `${binaryName}.png`), placeholderPng)\n }\n\n // Use appimagetool if available\n const proc = spawn('appimagetool', [appDirPath, opts.outputPath], {\n env: { ...process.env, ARCH: 'x86_64' }\n })\n\n proc.on('close', (code) => {\n rmSync(appDir, { recursive: true, force: true })\n if (code === 0) {\n chmodSync(opts.outputPath, 0o755)\n resolve({ success: true, outputPath: opts.outputPath })\n }\nelse {\n resolve({ success: false, error: `appimagetool exited with code ${code}. Install from https://appimage.github.io/appimagetool/` })\n }\n })\n\n proc.on('error', (err) => {\n rmSync(appDir, { recursive: true, force: true })\n resolve({ success: false, error: `appimagetool not found: ${err.message}` })\n })\n }\ncatch (error) {\n resolve({ success: false, error: (error as Error).message })\n }\n })\n}\n\n/**\n * Detect current platform\n */\nfunction detectPlatform(): 'macos' | 'windows' | 'linux' {\n switch (process.platform) {\n case 'darwin':\n return 'macos'\n case 'win32':\n return 'windows'\n default:\n return 'linux'\n }\n}\n\n/**\n * Simple packaging function for quick use\n */\nexport async function pack(options: {\n name: string\n version: string\n binaryPath: string\n outDir?: string\n}): Promise<PackageResult[]> {\n return packageApp({\n ...options,\n platforms: [detectPlatform()],\n })\n}\n",
|
|
8
|
+
"/**\n * Audio utilities for Craft applications\n * Provides simple abstractions for common audio tasks\n */\n\nexport type NoiseType = 'whitenoise' | 'brownnoise' | 'ocean' | 'rain' | 'forest'\nexport type ToneType = 'bell' | 'chime' | 'gong' | 'gentle'\n\ninterface AudioInstance {\n source?: AudioBufferSourceNode\n source2?: OscillatorNode\n context: AudioContext\n gain: GainNode\n}\n\n/**\n * Audio Manager - Handles all audio generation and playback\n */\nexport class AudioManager {\n private backgroundAudio: AudioInstance | null = null\n\n private readonly toneFrequencies: Record<ToneType, number> = {\n bell: 880, // A5\n chime: 1046.5, // C6\n gong: 440, // A4\n gentle: 523.25, // C5\n }\n\n /**\n * Play a tone sound (bell, chime, gong, gentle).\n *\n * Returns a promise that resolves once playback has been scheduled (or\n * rejects when the audio context cannot be resumed — typically because\n * the page hasn't received a user gesture yet, which Chrome/Safari/\n * Firefox all require for AudioContext.resume to succeed).\n */\n async playTone(type: ToneType, duration: number = 1.5): Promise<void> {\n let audioContext: AudioContext | null = null\n try {\n audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()\n // Modern browsers create AudioContexts in the `suspended` state until\n // a user gesture has been observed. Without an explicit resume the\n // oscillator schedules silently and the caller never hears anything.\n if (audioContext.state === 'suspended' && typeof audioContext.resume === 'function') {\n await audioContext.resume()\n }\n const oscillator = audioContext.createOscillator()\n const gainNode = audioContext.createGain()\n\n oscillator.connect(gainNode)\n gainNode.connect(audioContext.destination)\n\n oscillator.frequency.value = this.toneFrequencies[type]\n oscillator.type = 'sine'\n\n // Envelope for a pleasant bell-like sound\n const now = audioContext.currentTime\n gainNode.gain.setValueAtTime(0.3, now)\n gainNode.gain.exponentialRampToValueAtTime(0.01, now + duration)\n\n oscillator.start(now)\n oscillator.stop(now + duration)\n\n // Close the context once playback finishes so repeated calls don't leak\n // one AudioContext per tone. Browsers cap contexts at ~6 per tab.\n oscillator.onended = () => {\n audioContext!.close().catch(() => { /* ignore close errors */ })\n }\n }\n catch (e) {\n console.error('Failed to play tone:', e)\n audioContext?.close().catch(() => { /* best effort */ })\n throw e instanceof Error ? e : new Error(String(e))\n }\n }\n\n /**\n * Generate and play background noise\n */\n playBackgroundNoise(type: NoiseType, volume: number = 0.5): void {\n this.stopBackgroundNoise()\n\n try {\n const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()\n const gainNode = audioContext.createGain()\n gainNode.gain.value = volume\n\n switch (type) {\n case 'whitenoise':\n this.generateWhiteNoise(audioContext, gainNode)\n break\n case 'brownnoise':\n this.generateBrownNoise(audioContext, gainNode)\n break\n case 'ocean':\n this.generateOceanWaves(audioContext, gainNode)\n break\n case 'rain':\n this.generateRain(audioContext, gainNode)\n break\n case 'forest':\n this.generateForest(audioContext, gainNode)\n break\n }\n }\n catch (e) {\n console.error('Failed to generate background noise:', e)\n }\n }\n\n /**\n * Stop background noise\n */\n stopBackgroundNoise(): void {\n if (this.backgroundAudio) {\n try {\n if (this.backgroundAudio.source)\n this.backgroundAudio.source.stop()\n if (this.backgroundAudio.source2)\n this.backgroundAudio.source2.stop()\n if (this.backgroundAudio.context)\n this.backgroundAudio.context.close()\n this.backgroundAudio = null\n }\n catch (e) {\n console.error('Failed to stop background noise:', e)\n }\n }\n }\n\n /**\n * Update background noise volume\n */\n setVolume(volume: number): void {\n if (this.backgroundAudio && this.backgroundAudio.gain) {\n this.backgroundAudio.gain.gain.value = volume\n }\n }\n\n private generateWhiteNoise(audioContext: AudioContext, gainNode: GainNode): void {\n const bufferSize = 2 * audioContext.sampleRate\n const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate)\n const output = noiseBuffer.getChannelData(0)\n\n for (let i = 0; i < bufferSize; i++) {\n output[i] = Math.random() * 2 - 1\n }\n\n const source = audioContext.createBufferSource()\n source.buffer = noiseBuffer\n source.loop = true\n source.connect(gainNode)\n gainNode.connect(audioContext.destination)\n source.start(0)\n\n this.backgroundAudio = { source, context: audioContext, gain: gainNode }\n }\n\n private generateBrownNoise(audioContext: AudioContext, gainNode: GainNode): void {\n const bufferSize = 2 * audioContext.sampleRate\n const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate)\n const output = noiseBuffer.getChannelData(0)\n let lastOut = 0\n\n for (let i = 0; i < bufferSize; i++) {\n const white = Math.random() * 2 - 1\n output[i] = (lastOut + (0.02 * white)) / 1.02\n lastOut = output[i]\n output[i] *= 3.5\n }\n\n const source = audioContext.createBufferSource()\n source.buffer = noiseBuffer\n source.loop = true\n source.connect(gainNode)\n gainNode.connect(audioContext.destination)\n source.start(0)\n\n this.backgroundAudio = { source, context: audioContext, gain: gainNode }\n }\n\n private generateOceanWaves(audioContext: AudioContext, gainNode: GainNode): void {\n const bufferSize = 2 * audioContext.sampleRate\n const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate)\n const output = noiseBuffer.getChannelData(0)\n\n // Generate brown noise for wave texture\n let lastOut = 0\n for (let i = 0; i < bufferSize; i++) {\n const white = Math.random() * 2 - 1\n output[i] = (lastOut + (0.02 * white)) / 1.02\n lastOut = output[i]\n output[i] *= 2.0\n }\n\n const source = audioContext.createBufferSource()\n source.buffer = noiseBuffer\n source.loop = true\n\n // Low-pass filter for muffled wave sound\n const filter = audioContext.createBiquadFilter()\n filter.type = 'lowpass'\n filter.frequency.value = 800\n filter.Q.value = 1\n\n // LFO for wave motion\n const lfo = audioContext.createOscillator()\n lfo.frequency.value = 0.15\n const lfoGain = audioContext.createGain()\n lfoGain.gain.value = 0.3\n\n source.connect(filter)\n filter.connect(gainNode)\n lfo.connect(lfoGain)\n lfoGain.connect(gainNode.gain)\n gainNode.connect(audioContext.destination)\n\n source.start(0)\n lfo.start(0)\n\n this.backgroundAudio = { source, source2: lfo, context: audioContext, gain: gainNode }\n }\n\n private generateRain(audioContext: AudioContext, gainNode: GainNode): void {\n const bufferSize = 2 * audioContext.sampleRate\n const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate)\n const output = noiseBuffer.getChannelData(0)\n\n // Generate white noise with random intensity (raindrops)\n for (let i = 0; i < bufferSize; i++) {\n const intensity = Math.random() > 0.98 ? 2.0 : 1.0\n output[i] = (Math.random() * 2 - 1) * intensity\n }\n\n const source = audioContext.createBufferSource()\n source.buffer = noiseBuffer\n source.loop = true\n\n // High-pass filter for rain texture\n const filter = audioContext.createBiquadFilter()\n filter.type = 'highpass'\n filter.frequency.value = 400\n filter.Q.value = 0.5\n\n source.connect(filter)\n filter.connect(gainNode)\n gainNode.connect(audioContext.destination)\n source.start(0)\n\n this.backgroundAudio = { source, context: audioContext, gain: gainNode }\n }\n\n private generateForest(audioContext: AudioContext, gainNode: GainNode): void {\n const bufferSize = 2 * audioContext.sampleRate\n const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate)\n const output = noiseBuffer.getChannelData(0)\n\n // Gentle rustling (pink-ish noise)\n let b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0\n for (let i = 0; i < bufferSize; i++) {\n const white = Math.random() * 2 - 1\n b0 = 0.99886 * b0 + white * 0.0555179\n b1 = 0.99332 * b1 + white * 0.0750759\n b2 = 0.96900 * b2 + white * 0.1538520\n b3 = 0.86650 * b3 + white * 0.3104856\n b4 = 0.55000 * b4 + white * 0.5329522\n b5 = -0.7616 * b5 - white * 0.0168980\n output[i] = (b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362) * 0.11\n b6 = white * 0.115926\n }\n\n const source = audioContext.createBufferSource()\n source.buffer = noiseBuffer\n source.loop = true\n\n // Band-pass filter for natural forest ambience\n const filter = audioContext.createBiquadFilter()\n filter.type = 'bandpass'\n filter.frequency.value = 1200\n filter.Q.value = 0.8\n\n source.connect(filter)\n filter.connect(gainNode)\n gainNode.connect(audioContext.destination)\n source.start(0)\n\n this.backgroundAudio = { source, context: audioContext, gain: gainNode }\n }\n}\n",
|
|
9
|
+
"/**\n * Helpers for accessing the native Craft runtime injected on `window.craft`.\n *\n * Prefer these over `(window as any).craft.*` so call sites are typed and we\n * have a single seam to mock in tests.\n */\n\nimport type { CraftBridgeAPI, CraftEventEmitter } from '../types'\n\ntype CraftBridge = CraftBridgeAPI & CraftEventEmitter\n\n/** True when running inside a Craft webview (i.e. `window.craft` is present). */\nexport function isCraftRuntime(): boolean {\n return typeof window !== 'undefined' && !!window.craft\n}\n\n/** Returns the global Craft runtime, or null if running outside Craft. */\nexport function getCraft(): CraftBridge | null {\n if (typeof window === 'undefined') return null\n return (window.craft as CraftBridge | undefined) ?? null\n}\n\n/**\n * Returns the low-level bridge `call(method, params)` function, or null when\n * unavailable. Use this when you need to invoke a method that doesn't have a\n * typed wrapper yet.\n */\nexport function getNativeBridgeCall(): ((method: string, params?: unknown) => Promise<unknown>) | null {\n const c = getCraft() as (CraftBridge & { bridge?: { call?: (m: string, p?: unknown) => Promise<unknown> } }) | null\n return c?.bridge?.call ?? null\n}\n\n/**\n * Returns the standard \"API unavailable\" message used throughout the SDK.\n * Centralized so call sites are consistent and easy to grep for.\n */\nexport function craftUnavailableMessage(api: string): string {\n return `${api} not available. Must run in Craft environment.`\n}\n\n/** Throws a consistent error when an API is invoked outside Craft. */\nexport function requireCraftRuntime(api: string): CraftBridge {\n const c = getCraft()\n if (!c) {\n throw new Error(craftUnavailableMessage(api))\n }\n return c\n}\n",
|
|
10
|
+
"/**\n * Storage utilities for Craft applications\n * Simple localStorage abstraction with type safety\n */\n\nfunction hasLocalStorage(): boolean {\n return typeof globalThis !== 'undefined' && typeof (globalThis as any).localStorage !== 'undefined'\n}\n\nexport class Storage<T> {\n constructor(private key: string, private defaults: T) {}\n\n /**\n * Load data from localStorage.\n *\n * Object-shaped saved values are merged on top of `defaults`, so newly\n * added keys in `defaults` still appear when an older payload is read.\n * Arrays and primitives are returned verbatim — the previous\n * implementation spread them into `defaults`, which silently corrupted\n * arrays (each numeric index turned into a key on an object) and\n * threw on primitives.\n */\n load(): T {\n if (!hasLocalStorage()) return this.defaults\n try {\n const saved = localStorage.getItem(this.key)\n if (saved) {\n const parsed = JSON.parse(saved) as T\n if (Array.isArray(parsed) || Array.isArray(this.defaults as unknown)) {\n return parsed\n }\n if (\n parsed !== null\n && typeof parsed === 'object'\n && this.defaults !== null\n && typeof this.defaults === 'object'\n ) {\n return { ...(this.defaults as object), ...(parsed as object) } as T\n }\n return parsed\n }\n }\n catch (e) {\n console.error(`Failed to load ${this.key}:`, e)\n }\n return this.defaults\n }\n\n /**\n * Save data to localStorage\n */\n save(data: T): void {\n if (!hasLocalStorage()) return\n try {\n localStorage.setItem(this.key, JSON.stringify(data))\n }\n catch (e) {\n console.error(`Failed to save ${this.key}:`, e)\n }\n }\n\n /**\n * Update partial data in localStorage. Merges only when both the\n * existing and incoming values are plain objects; otherwise replaces\n * outright (so this method never silently corrupts array data).\n */\n update(partial: Partial<T>): void {\n const current = this.load()\n if (\n current !== null\n && typeof current === 'object'\n && !Array.isArray(current)\n && partial !== null\n && typeof partial === 'object'\n && !Array.isArray(partial)\n ) {\n this.save({ ...(current as object), ...(partial as object) } as T)\n return\n }\n this.save(partial as T)\n }\n\n /**\n * Clear data from localStorage\n */\n clear(): void {\n if (!hasLocalStorage()) return\n try {\n localStorage.removeItem(this.key)\n }\n catch (e) {\n console.error(`Failed to clear ${this.key}:`, e)\n }\n }\n}\n",
|
|
11
|
+
"/**\n * Timer utilities for Craft applications\n * Simple interval-based timer with callbacks\n */\n\nexport type TimerCallback = (_timeRemaining: number) => void\n\nexport class Timer {\n private intervalId: ReturnType<typeof setInterval> | null = null\n private timeRemaining: number = 0\n private isRunning: boolean = false\n /** Wallclock deadline (ms epoch). Used to recompute timeRemaining each\n * tick so the timer doesn't drift under load or tab throttling — a\n * simple `--` counter loses minutes over hours. */\n private endAt: number = 0\n /** Reference to a clock for testability — overridable so tests can\n * advance time deterministically. Defaults to `Date.now`. */\n private static now: () => number = () => Date.now()\n\n constructor(\n private duration: number,\n private onTick: TimerCallback,\n private onComplete?: () => void,\n ) {\n this.timeRemaining = duration\n }\n\n /**\n * Start the timer\n */\n start(): void {\n if (this.isRunning)\n return\n\n this.isRunning = true\n this.endAt = Timer.now() + this.timeRemaining * 1000\n this.intervalId = setInterval(() => {\n const ms = Math.max(0, this.endAt - Timer.now())\n this.timeRemaining = Math.ceil(ms / 1000)\n this.onTick(this.timeRemaining)\n\n if (this.timeRemaining <= 0) {\n this.pause()\n this.onComplete?.()\n }\n }, 250)\n }\n\n /**\n * Pause the timer\n */\n pause(): void {\n if (!this.isRunning)\n return\n\n this.isRunning = false\n if (this.intervalId) {\n clearInterval(this.intervalId)\n this.intervalId = null\n }\n }\n\n /**\n * Reset the timer to initial duration\n */\n reset(): void {\n this.pause()\n this.timeRemaining = this.duration\n this.endAt = Timer.now() + this.duration * 1000\n this.onTick(this.timeRemaining)\n }\n\n /**\n * Set a new duration\n */\n setDuration(duration: number): void {\n this.duration = duration\n this.timeRemaining = duration\n if (this.isRunning) {\n this.endAt = Timer.now() + duration * 1000\n }\n }\n\n /**\n * Get current time remaining\n */\n getTimeRemaining(): number {\n return this.timeRemaining\n }\n\n /**\n * Check if timer is running\n */\n running(): boolean {\n return this.isRunning\n }\n\n /**\n * Format time as MM:SS. Negative values are clamped to zero since the\n * timer should never display \"negative time remaining\" in a UI.\n */\n static formatTime(seconds: number): string {\n const clamped = Math.max(0, Math.floor(seconds))\n const mins = Math.floor(clamped / 60)\n const secs = clamped % 60\n return `${mins}:${secs.toString().padStart(2, '0')}`\n }\n\n /**\n * Override the wallclock used by `start()`/`reset()` for the lifetime\n * of the process. Intended for tests that need to advance time\n * deterministically. Pass `null` to restore `Date.now`.\n */\n static _setClockForTests(clock: (() => number) | null): void {\n Timer.now = clock ?? (() => Date.now())\n }\n}\n",
|
|
12
|
+
"/**\n * Craft Native Bridge Core\n * Bidirectional async communication, message queue, and type-safe protocols\n */\n\nimport { EventEmitter } from 'events'\nimport { secureUUID } from './ids'\n\n// Ambient types for native bridges injected by the host. These globals are\n// defined by WKWebView (iOS), Android WebView, Electron's contextBridge, and\n// the WinRT `chrome.webview` object respectively. We don't import them — they\n// just need to be known so we don't cast through `any` in the send path.\ninterface WkWebKitGlobal {\n messageHandlers?: {\n craft?: { postMessage(message: unknown): void }\n }\n}\ninterface AndroidWebViewGlobal {\n postMessage(message: string): void\n}\ninterface CraftIPCGlobal {\n send(channel: string, message: unknown): void\n}\ndeclare global {\n // eslint-disable-next-line vars-on-top\n interface Window {\n webkit?: WkWebKitGlobal\n CraftBridge?: AndroidWebViewGlobal\n craftIPC?: CraftIPCGlobal\n }\n}\n\n/**\n * Bridge error codes returned by the native layer.\n * Used in BridgeMessage.error.code field.\n */\nexport const BridgeErrorCodes = {\n /** Generic/unknown error */\n UNKNOWN: -1,\n /** Operation timed out waiting for native response */\n TIMEOUT: -2,\n /** Offline queue full, cannot enqueue more requests */\n QUEUE_FULL: -3,\n /** Binary transfer not enabled */\n BINARY_DISABLED: -4,\n /** Expected binary response but got non-binary */\n EXPECTED_BINARY: -5,\n /** Bridge destroyed while requests were pending */\n BRIDGE_DESTROYED: -6,\n /** Bridge in-flight request limit exceeded (backpressure) */\n BUSY: -7,\n /** Native side speaks an incompatible bridge protocol version */\n PROTOCOL_MISMATCH: -8,\n /** Bridge transitioned from connected to disconnected with requests in flight */\n DISCONNECTED: -9,\n} as const\n\nexport type BridgeErrorCode = typeof BridgeErrorCodes[keyof typeof BridgeErrorCodes]\n\n/**\n * Bridge wire-protocol version. Bumped when the message envelope changes in a\n * backwards-incompatible way. Native and SDK must agree, or the bridge will\n * reject the handshake with PROTOCOL_MISMATCH.\n */\nexport const BRIDGE_PROTOCOL_VERSION = 1\n\n// Types\nexport interface BridgeMessage<T = unknown> {\n id: string\n type: 'request' | 'response' | 'event' | 'stream'\n method?: string\n params?: T\n result?: unknown\n error?: { code: number; message: string; data?: unknown }\n streamId?: string\n streamEvent?: 'data' | 'end' | 'error'\n}\n\nexport interface BridgeConfig {\n timeout?: number\n retries?: number\n retryDelay?: number\n queueSize?: number\n batchSize?: number\n batchDelay?: number\n enableOfflineQueue?: boolean\n enableBinaryTransfer?: boolean\n /**\n * Maximum number of in-flight requests before new requests are rejected\n * with `BridgeErrorCodes.BUSY`. Prevents user code from DOSing the native\n * layer with tight loops. Defaults to 10_000.\n */\n maxConcurrentRequests?: number\n /**\n * Origin to use when the bridge falls back to `window.parent.postMessage`\n * (i.e. Craft is running inside a host iframe rather than a native\n * webview). Defaults to `null`, which **disables** the postMessage path\n * entirely — `'*'` was the old default and leaks bridge traffic to any\n * cross-origin parent. Set this to your host page's exact origin\n * (e.g. `'https://app.example.com'`) when embedding.\n */\n parentOrigin?: string | null\n}\n\nexport interface StreamController<T> {\n onData(callback: (data: T) => void): void\n onEnd(callback: () => void): void\n onError(callback: (error: Error) => void): void\n cancel(): void\n}\n\n/**\n * Build a unique message ID. Each {@link NativeBridge} owns its own counter\n * (`#counter`) and a per-instance secret (`prefix`) derived from\n * {@link secureUUID}, so two bridges in the same process produce IDs from\n * fully-disjoint namespaces — there is no longer a module-level counter\n * that could leak state across bridges (e.g. between tests after a\n * `resetGlobalBridge()` call).\n */\nfunction buildMessageId(prefix: string, counter: number): string {\n return `${prefix}_${Date.now().toString(36)}_${counter.toString(36)}`\n}\n\n// Native Bridge Core\nexport class NativeBridge extends EventEmitter {\n private config: Required<BridgeConfig>\n private pendingRequests = new Map<string, { resolve: (value: unknown) => void; reject: (error: Error) => void; timeout: NodeJS.Timeout }>()\n private offlineQueue: BridgeMessage[] = []\n private connected = false\n private streams = new Map<string, { onData: (data: unknown) => void; onEnd: () => void; onError: (error: Error) => void }>()\n private batchBuffer: BridgeMessage[] = []\n private batchTimer: NodeJS.Timeout | null = null\n private destroyed = false\n // Per-instance ID prefix so two bridges in the same process can never\n // produce the same message ID even if they happen to construct on the\n // same millisecond. Derived from a secure UUID's first 8 hex chars\n // (32 bits of entropy, plenty for collision resistance across the\n // typically-tiny number of bridges in a session).\n private readonly idPrefix: string = `msg-${secureUUID().slice(0, 8)}`\n // Per-instance message counter, seeded with a random offset so attackers\n // can't predict outstanding ids by counting from zero.\n private idCounter: number = Math.floor(Math.random() * 1e9)\n private nextMessageId(): string {\n if (this.idCounter >= Number.MAX_SAFE_INTEGER - 1) {\n this.idCounter = Math.floor(Math.random() * 1e9)\n }\n this.idCounter++\n return buildMessageId(this.idPrefix, this.idCounter)\n }\n // Track DOM listeners so destroy() can remove them. Without this, tests\n // that construct/destroy NativeBridge in a loop accumulate craft-ready\n // and message listeners and exhaust the runtime's listener cap.\n // eslint-disable-next-line pickier/no-unused-vars\n private boundHandleMessage: ((event: MessageEvent | CustomEvent) => void) | null = null\n private craftReadyHandler: (() => void) | null = null\n\n constructor(config: BridgeConfig = {}) {\n super()\n // The default EventEmitter cap is 10. Real apps subscribe to many\n // bridge channels (`menu.click`, `component.event`, lifecycle, …)\n // plus internal ones; the cap fires \"MaxListenersExceeded\" warnings\n // long before there's a real leak. 100 is generous-but-bounded so a\n // genuine listener leak still surfaces.\n this.setMaxListeners(100)\n this.config = {\n timeout: 30000,\n retries: 3,\n retryDelay: 1000,\n queueSize: 1000,\n batchSize: 10,\n batchDelay: 50,\n enableOfflineQueue: true,\n enableBinaryTransfer: true,\n maxConcurrentRequests: 10000,\n parentOrigin: null,\n ...config,\n }\n this.setupBridge()\n }\n\n private setupBridge(): void {\n if (typeof window === 'undefined') return\n\n // Listen for messages from native. Bind once and store the reference so\n // destroy() can remove the listener cleanly.\n this.boundHandleMessage = this.handleMessage.bind(this)\n window.addEventListener('message', this.boundHandleMessage)\n window.addEventListener('craft-bridge-message' as any, this.boundHandleMessage)\n\n // Auto-connect when the host fires `craft:ready`. Without this, every\n // request sat in `offlineQueue` because nothing called setConnected().\n // Hosts that wire up the bridge synchronously (e.g. before the\n // injected JS dispatches craft:ready) can also detect the runtime\n // immediately via `window.craft`.\n if (window.craft) {\n // The runtime is already there — flip on the next microtask so\n // subscribers to `'connected'` have a chance to register first.\n Promise.resolve().then(() => this.setConnected(true))\n }\n else {\n this.craftReadyHandler = () => {\n if (this.craftReadyHandler) {\n window.removeEventListener('craft:ready' as any, this.craftReadyHandler)\n this.craftReadyHandler = null\n }\n this.setConnected(true)\n }\n // `once: true` is also defensive — if `craft:ready` fires twice we\n // still only flip once. The handler also self-removes on first run\n // so we don't depend on `once` semantics that older webviews lack.\n window.addEventListener('craft:ready' as any, this.craftReadyHandler, { once: true })\n }\n }\n\n private teardownBridgeListeners(): void {\n if (typeof window === 'undefined') return\n if (this.boundHandleMessage) {\n window.removeEventListener('message', this.boundHandleMessage)\n window.removeEventListener('craft-bridge-message' as any, this.boundHandleMessage)\n this.boundHandleMessage = null\n }\n if (this.craftReadyHandler) {\n window.removeEventListener('craft:ready' as any, this.craftReadyHandler)\n this.craftReadyHandler = null\n }\n }\n\n private handleMessage(event: MessageEvent | CustomEvent): void {\n let data: BridgeMessage\n try {\n data = 'detail' in event ? event.detail : typeof event.data === 'string' ? JSON.parse(event.data) : event.data\n }\ncatch (err) {\n console.warn('[Craft Bridge] Failed to parse message:', err)\n return\n }\n\n if (!data || !data.id) return\n\n // Drop responses whose id wasn't minted by THIS bridge instance. Without\n // this guard, a third-party script that can fire `craft-bridge-message`\n // events (anything on the same page, in dev) could resolve any\n // outstanding request by guessing the id. Stream/event ids aren't\n // generated by us in the same way, so they're left unrestricted.\n if (data.type === 'response' && !this.isOwnId(data.id)) {\n return\n }\n\n switch (data.type) {\n case 'response':\n this.handleResponse(data)\n break\n case 'event':\n this.handleEvent(data)\n break\n case 'stream':\n this.handleStream(data)\n break\n }\n }\n\n /** True when the given id starts with this bridge's per-instance prefix. */\n private isOwnId(id: string): boolean {\n return typeof id === 'string' && id.startsWith(`${this.idPrefix}_`)\n }\n\n private handleResponse(message: BridgeMessage): void {\n const pending = this.pendingRequests.get(message.id)\n if (!pending) return\n\n clearTimeout(pending.timeout)\n this.pendingRequests.delete(message.id)\n\n if (message.error) {\n pending.reject(new BridgeError(message.error.message, message.error.code, message.error.data))\n }\nelse {\n pending.resolve(message.result)\n }\n }\n\n private handleEvent(message: BridgeMessage): void {\n if (message.method) {\n this.emit(message.method, message.params)\n }\n }\n\n private handleStream(message: BridgeMessage): void {\n if (!message.streamId) return\n const stream = this.streams.get(message.streamId)\n if (!stream) return\n\n switch (message.streamEvent) {\n case 'data':\n stream.onData(message.result)\n break\n case 'end':\n stream.onEnd()\n this.streams.delete(message.streamId)\n break\n case 'error':\n stream.onError(new Error(message.error?.message || 'Stream error'))\n this.streams.delete(message.streamId)\n break\n }\n }\n\n /**\n * Send a request to native and wait for response\n */\n async request<T = unknown, R = unknown>(method: string, params?: T, options?: { timeout?: number }): Promise<R> {\n return this.requestWithRetry(method, params, this.config.retries, options?.timeout)\n }\n\n private async requestWithRetry<T, R>(method: string, params: T | undefined, retriesLeft: number, timeout?: number): Promise<R> {\n try {\n return await this.sendRequest<T, R>(method, params, timeout)\n }\ncatch (error) {\n if (retriesLeft > 0 && this.isRetryableError(error)) {\n await this.delay(this.config.retryDelay)\n return this.requestWithRetry(method, params, retriesLeft - 1, timeout)\n }\n throw error\n }\n }\n\n private isRetryableError(error: unknown): boolean {\n if (error instanceof BridgeError) {\n // Network errors, timeouts are retryable\n return error.code === BridgeErrorCodes.UNKNOWN || error.code === BridgeErrorCodes.TIMEOUT\n }\n return false\n }\n\n private async sendRequest<T, R>(method: string, params?: T, timeout?: number): Promise<R> {\n if (this.destroyed) {\n throw new BridgeError('Bridge destroyed', BridgeErrorCodes.BRIDGE_DESTROYED)\n }\n if (this.pendingRequests.size >= this.config.maxConcurrentRequests) {\n throw new BridgeError(\n `Bridge busy: ${this.pendingRequests.size} in-flight requests exceeds maxConcurrentRequests=${this.config.maxConcurrentRequests}`,\n BridgeErrorCodes.BUSY\n )\n }\n\n const effectiveTimeout = timeout ?? this.config.timeout\n const message: BridgeMessage<T> = {\n id: this.nextMessageId(),\n type: 'request',\n method,\n params,\n }\n\n if (!this.connected && this.config.enableOfflineQueue) {\n if (this.offlineQueue.length >= this.config.queueSize) {\n throw new BridgeError('Offline queue full', BridgeErrorCodes.QUEUE_FULL)\n }\n this.offlineQueue.push(message)\n // Return a promise that will be resolved when connected. Mirror the\n // online timeout so requests that never connect are rejected rather\n // than leaking forever — and remove from offlineQueue too so a late\n // reconnect doesn't deliver to a dead request.\n return new Promise((resolve, reject) => {\n this.pendingRequests.set(message.id, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeout: setTimeout(() => {\n this.pendingRequests.delete(message.id)\n const idx = this.offlineQueue.findIndex(m => m.id === message.id)\n if (idx >= 0) this.offlineQueue.splice(idx, 1)\n reject(new BridgeError('Request timeout (offline)', BridgeErrorCodes.TIMEOUT))\n }, effectiveTimeout),\n })\n })\n }\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingRequests.delete(message.id)\n reject(new BridgeError('Request timeout', BridgeErrorCodes.TIMEOUT))\n }, effectiveTimeout)\n\n this.pendingRequests.set(message.id, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeout: timer,\n })\n\n // Fail fast when no transport is wired (plain `bun build` / Vite dev\n // without a Craft host). Otherwise the caller waits the full timeout\n // for a request that was never delivered.\n if (!this.send(message)) {\n clearTimeout(timer)\n this.pendingRequests.delete(message.id)\n reject(new BridgeError(\n 'No bridge transport available — not running inside a Craft host',\n BridgeErrorCodes.UNKNOWN,\n ))\n }\n })\n }\n\n /**\n * Negotiate the wire-protocol version with the native layer. Throws\n * BridgeError(PROTOCOL_MISMATCH) if the native side reports a version we\n * don't speak.\n *\n * This is **opt-in** — you must call it explicitly. It assumes the host\n * registers a `_handshake` handler; the Zig core's\n * `Bridge.registerDefaults()` does this for you. If you're embedding Craft\n * inside a host that hasn't wired `_handshake`, do not call this method\n * (the timeout path will reject with TIMEOUT, which is louder than a\n * silent mismatch but still a failure).\n */\n async handshake(): Promise<{ nativeVersion: number }> {\n const result = await this.request<{ sdkVersion: number }, { version: number }>(\n '_handshake',\n { sdkVersion: BRIDGE_PROTOCOL_VERSION }\n )\n if (result?.version !== BRIDGE_PROTOCOL_VERSION) {\n throw new BridgeError(\n `Bridge protocol mismatch: SDK speaks v${BRIDGE_PROTOCOL_VERSION}, native speaks v${result?.version ?? 'unknown'}`,\n BridgeErrorCodes.PROTOCOL_MISMATCH\n )\n }\n return { nativeVersion: result.version }\n }\n\n /**\n * Send a fire-and-forget message (no response expected)\n */\n notify<T = unknown>(method: string, params?: T): void {\n const message: BridgeMessage<T> = {\n id: this.nextMessageId(),\n type: 'request',\n method,\n params,\n }\n this.send(message)\n }\n\n /**\n * Create a stream for receiving multiple responses.\n *\n * @param method - native method name\n * @param params - method params\n * @param options.bufferLimit - max events buffered before consumer registers\n * `onData`. Once exceeded the stream is failed with `BUFFER_OVERFLOW`\n * instead of growing indefinitely. Defaults to 1000.\n */\n stream<T = unknown>(\n method: string,\n params?: unknown,\n options?: { bufferLimit?: number },\n ): StreamController<T> {\n const bufferLimit = options?.bufferLimit ?? 1000\n const streamId = this.nextMessageId()\n const message: BridgeMessage = {\n id: this.nextMessageId(),\n type: 'request',\n method,\n params,\n streamId,\n }\n\n // Buffer events received before the consumer registers callbacks, so we\n // don't silently drop them (previous implementation used no-op stubs).\n const pendingData: T[] = []\n let ended = false\n let pendingError: Error | undefined\n let cancelled = false\n // eslint-disable-next-line pickier/no-unused-vars\n let dataCallback: ((data: T) => void) | null = null\n let endCallback: (() => void) | null = null\n // eslint-disable-next-line pickier/no-unused-vars\n let errorCallback: ((error: Error) => void) | null = null\n\n const controller: StreamController<T> = {\n onData: (cb) => {\n dataCallback = cb\n // Flush any buffered events. Honor the `ended` and `pendingError`\n // flags AFTER the buffer drains so consumers see the full event\n // history before the terminal signal — otherwise a fast end can\n // race the buffered data and the consumer thinks the stream\n // finished empty.\n while (pendingData.length > 0) {\n cb(pendingData.shift() as T)\n }\n },\n onEnd: (cb) => {\n endCallback = cb\n if (ended) cb()\n },\n onError: (cb) => {\n errorCallback = cb\n if (pendingError) cb(pendingError)\n },\n cancel: () => {\n // Idempotent: a second cancel() must not delete a stream that's\n // already gone or fire a duplicate `_cancelStream` to native.\n if (cancelled) return\n cancelled = true\n if (!this.streams.has(streamId)) return\n this.streams.delete(streamId)\n this.send({\n id: this.nextMessageId(),\n type: 'request',\n method: '_cancelStream',\n params: { streamId },\n })\n },\n }\n\n this.streams.set(streamId, {\n onData: (data) => {\n if (dataCallback) {\n dataCallback(data as T)\n return\n }\n if (pendingData.length >= bufferLimit) {\n // Don't grow forever — fail the stream instead. Set pendingError\n // so a late onError handler still sees it.\n const overflow = new BridgeError(\n `Stream buffer overflow: ${pendingData.length} events buffered with no consumer (limit=${bufferLimit})`,\n BridgeErrorCodes.BUSY,\n )\n pendingError = overflow\n if (errorCallback) errorCallback(overflow)\n this.streams.delete(streamId)\n // Tell the native side to stop producing — without this, the\n // peer keeps sending events into the dropped stream forever.\n this.send({\n id: this.nextMessageId(),\n type: 'request',\n method: '_cancelStream',\n params: { streamId },\n })\n return\n }\n pendingData.push(data as T)\n },\n onEnd: () => {\n ended = true\n if (endCallback) endCallback()\n },\n onError: (error) => {\n pendingError = error\n if (errorCallback) errorCallback(error)\n },\n })\n\n this.send(message)\n return controller\n }\n\n /**\n * Send binary data to native\n */\n async sendBinary(method: string, data: ArrayBuffer | Uint8Array): Promise<void> {\n if (!this.config.enableBinaryTransfer) {\n throw new BridgeError('Binary transfer not enabled', BridgeErrorCodes.BINARY_DISABLED)\n }\n\n const base64 = this.arrayBufferToBase64(data instanceof ArrayBuffer ? new Uint8Array(data) : data)\n await this.request(method, { _binary: true, data: base64 })\n }\n\n /**\n * Receive binary data from native\n */\n async receiveBinary(method: string, params?: unknown): Promise<ArrayBuffer> {\n if (!this.config.enableBinaryTransfer) {\n throw new BridgeError('Binary transfer not enabled', BridgeErrorCodes.BINARY_DISABLED)\n }\n\n const result = await this.request<unknown, { _binary: boolean; data: string }>(method, params)\n if (result._binary) {\n return this.base64ToArrayBuffer(result.data)\n }\n throw new BridgeError('Expected binary response', BridgeErrorCodes.EXPECTED_BINARY)\n }\n\n /**\n * Batch multiple requests\n */\n async batch<T extends Array<{ method: string; params?: unknown }>>(\n requests: T\n ): Promise<Array<{ result?: unknown; error?: { code: number; message: string } }>> {\n return this.request('_batch', { requests })\n }\n\n /**\n * Add request to batch buffer (auto-flushed)\n */\n addToBatch<T = unknown>(method: string, params?: T): void {\n this.batchBuffer.push({\n id: this.nextMessageId(),\n type: 'request',\n method,\n params,\n })\n\n if (this.batchBuffer.length >= this.config.batchSize) {\n this.flushBatch()\n }\nelse if (!this.batchTimer) {\n this.batchTimer = setTimeout(() => this.flushBatch(), this.config.batchDelay)\n }\n }\n\n private flushBatch(): void {\n if (this.batchTimer) {\n clearTimeout(this.batchTimer)\n this.batchTimer = null\n }\n\n // Drop any buffered work if destroy() ran between schedule and flush — the\n // bridge is gone, the native side won't reply, and emitting would resurrect\n // listeners we just torn down.\n if (this.destroyed) {\n this.batchBuffer = []\n return\n }\n\n if (this.batchBuffer.length === 0) return\n\n const batch = this.batchBuffer\n this.batchBuffer = []\n\n // If we lost connection between scheduling the batch and flushing it,\n // re-queue the messages onto the offline queue (when enabled) instead\n // of dropping them on the floor of `send()` — otherwise the\n // fire-and-forget `addToBatch()` path silently loses every request\n // sent during a transient disconnect.\n if (!this.connected) {\n if (this.config.enableOfflineQueue) {\n for (const msg of batch) {\n if (this.offlineQueue.length >= this.config.queueSize) break\n this.offlineQueue.push(msg)\n }\n }\n return\n }\n\n // Match the shape used by `batch()` above so the native side has a single\n // batch envelope format to parse. Previously `{ messages }` and `{ requests }`\n // diverged and the buffered path silently broke on the native side.\n this.send({\n id: this.nextMessageId(),\n type: 'request',\n method: '_batch',\n params: { requests: batch },\n })\n }\n\n /**\n * Set connection status. Emits `'connected'` / `'disconnected'`. On\n * disconnect, every outstanding pending request is rejected with\n * `BridgeErrorCodes.DISCONNECTED` immediately — previously they sat\n * until `timeout` (default 30s) expired, hanging the calling app.\n */\n setConnected(connected: boolean): void {\n const wasConnected = this.connected\n this.connected = connected\n\n if (connected && !wasConnected) {\n this.emit('connected')\n this.flushOfflineQueue()\n }\n else if (!connected && wasConnected) {\n this.emit('disconnected')\n // Reject pending requests so callers can retry/back off rather than\n // wait for the per-request timeout to fire.\n for (const [id, pending] of this.pendingRequests) {\n clearTimeout(pending.timeout)\n pending.reject(new BridgeError('Bridge disconnected', BridgeErrorCodes.DISCONNECTED))\n this.pendingRequests.delete(id)\n }\n }\n }\n\n private flushOfflineQueue(): void {\n const queue = this.offlineQueue\n this.offlineQueue = []\n for (const message of queue) {\n this.send(message)\n }\n }\n\n /**\n * Dispatch a message to whichever native transport is available. Returns\n * `true` when the message was handed off to a transport, `false` when no\n * transport could be found — the caller (only `sendRequest` cares) can\n * use that to fail fast instead of waiting for the request timeout.\n */\n private send(message: BridgeMessage): boolean {\n let json: string\n try {\n json = JSON.stringify(message)\n }\n catch (e) {\n // The most common cause is a circular params payload. Reject the\n // matching pending request synchronously so the caller doesn't\n // wait the full timeout for a message we never managed to send.\n this.failPendingForMessage(message, new BridgeError(\n `Failed to serialize bridge message: ${(e as Error).message}`,\n BridgeErrorCodes.UNKNOWN,\n { originalError: String(e) },\n ))\n return false\n }\n\n try {\n if (typeof window !== 'undefined') {\n // iOS WKWebView\n if (window.webkit?.messageHandlers?.craft) {\n window.webkit.messageHandlers.craft.postMessage(message)\n return true\n }\n\n // Android WebView\n if (window.CraftBridge) {\n window.CraftBridge.postMessage(json)\n return true\n }\n\n // Electron IPC\n if (window.craftIPC) {\n window.craftIPC.send('bridge-message', message)\n return true\n }\n\n // Generic postMessage. Only enabled when the host explicitly opts in\n // via `BridgeConfig.parentOrigin`; previously this used `'*'`, which\n // broadcasts every native call to whatever cross-origin frame is\n // hosting Craft.\n if (window.parent !== window && this.config.parentOrigin) {\n window.parent.postMessage(message, this.config.parentOrigin)\n return true\n }\n }\n\n // Node.js (for testing)\n if (typeof process !== 'undefined' && typeof (process as { send?: (m: unknown) => void }).send === 'function') {\n ;(process as { send: (m: unknown) => void }).send(message)\n return true\n }\n\n return false\n }\n catch (e) {\n // postMessage can throw DataCloneError on un-cloneable values even\n // when JSON.stringify would have succeeded (e.g. functions, DOM\n // nodes). Fail the matching pending entry rather than letting the\n // exception escape into the caller's microtask.\n this.failPendingForMessage(message, new BridgeError(\n `Bridge transport rejected the message: ${(e as Error).message}`,\n BridgeErrorCodes.UNKNOWN,\n ))\n return false\n }\n }\n\n /**\n * Reject the pending entry corresponding to `message.id` with `error`,\n * if any. Used by `send()` when serialization or transport throws so\n * the caller's promise rejects immediately.\n */\n private failPendingForMessage(message: BridgeMessage, error: BridgeError): void {\n const pending = this.pendingRequests.get(message.id)\n if (!pending) return\n clearTimeout(pending.timeout)\n this.pendingRequests.delete(message.id)\n pending.reject(error)\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n }\n\n private arrayBufferToBase64(buffer: Uint8Array): string {\n const chunks: string[] = []\n const chunkSize = 8192\n for (let i = 0; i < buffer.byteLength; i += chunkSize) {\n chunks.push(String.fromCharCode(...buffer.subarray(i, i + chunkSize)))\n }\n return btoa(chunks.join(''))\n }\n\n private base64ToArrayBuffer(base64: string): ArrayBuffer {\n const binary = atob(base64)\n const buffer = new ArrayBuffer(binary.length)\n const bytes = new Uint8Array(buffer)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return buffer\n }\n\n /**\n * Destroy the bridge. Idempotent.\n */\n destroy(): void {\n if (this.destroyed) return\n this.destroyed = true\n\n // Clear all pending requests\n for (const [, pending] of this.pendingRequests) {\n clearTimeout(pending.timeout)\n pending.reject(new BridgeError('Bridge destroyed', BridgeErrorCodes.BRIDGE_DESTROYED))\n }\n this.pendingRequests.clear()\n this.streams.clear()\n this.offlineQueue = []\n this.batchBuffer = []\n if (this.batchTimer) {\n clearTimeout(this.batchTimer)\n this.batchTimer = null\n }\n this.teardownBridgeListeners()\n this.removeAllListeners()\n }\n}\n\n// Bridge Error\nexport class BridgeError extends Error {\n code: number\n data?: unknown\n\n constructor(message: string, code: number, data?: unknown) {\n super(message)\n this.name = 'BridgeError'\n this.code = code\n this.data = data\n }\n}\n\n// Type-safe Bridge Protocol Generator\nexport interface BridgeMethod<P = void, R = void> {\n method: string\n params: P\n result: R\n}\n\nexport type InferParams<T> = T extends BridgeMethod<infer P, unknown> ? P : never\nexport type InferResult<T> = T extends BridgeMethod<unknown, infer R> ? R : never\n\nexport function createTypedBridge<T extends Record<string, BridgeMethod<any, any>>>(bridge: NativeBridge) {\n return new Proxy(\n {},\n {\n get(_, method: string) {\n return (params?: unknown) => bridge.request(method, params)\n },\n }\n ) as {\n [K in keyof T]: (params: InferParams<T[K]>) => Promise<InferResult<T[K]>>\n }\n}\n\n// Native Menu System\nexport interface MenuItem {\n id: string\n label: string\n accelerator?: string\n type?: 'normal' | 'separator' | 'checkbox' | 'radio'\n checked?: boolean\n enabled?: boolean\n visible?: boolean\n icon?: string\n submenu?: MenuItem[]\n}\n\nexport class NativeMenus {\n constructor(private bridge: NativeBridge) {}\n\n /**\n * Set application menu\n */\n async setApplicationMenu(menu: MenuItem[]): Promise<void> {\n await this.bridge.request('menu.setApplicationMenu', { menu })\n }\n\n /**\n * Show context menu\n */\n async showContextMenu(menu: MenuItem[], position?: { x: number; y: number }): Promise<string | null> {\n return this.bridge.request('menu.showContextMenu', { menu, position })\n }\n\n /**\n * Update menu item\n */\n async updateMenuItem(id: string, updates: Partial<MenuItem>): Promise<void> {\n await this.bridge.request('menu.updateMenuItem', { id, updates })\n }\n\n /**\n * Listen for menu item clicks\n */\n onMenuClick(callback: (id: string) => void): () => void {\n this.bridge.on('menu.click', callback)\n return () => this.bridge.off('menu.click', callback)\n }\n}\n\n// Native Dialogs\nexport interface OpenDialogOptions {\n title?: string\n defaultPath?: string\n buttonLabel?: string\n filters?: Array<{ name: string; extensions: string[] }>\n properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory' | 'dontAddToRecent'>\n message?: string\n}\n\nexport interface SaveDialogOptions {\n title?: string\n defaultPath?: string\n buttonLabel?: string\n filters?: Array<{ name: string; extensions: string[] }>\n properties?: Array<'showHiddenFiles' | 'createDirectory' | 'showOverwriteConfirmation' | 'dontAddToRecent'>\n message?: string\n nameFieldLabel?: string\n showsTagField?: boolean\n}\n\nexport interface MessageBoxOptions {\n type?: 'none' | 'info' | 'error' | 'question' | 'warning'\n buttons?: string[]\n defaultId?: number\n cancelId?: number\n title?: string\n message: string\n detail?: string\n checkboxLabel?: string\n checkboxChecked?: boolean\n icon?: string\n}\n\nexport class NativeDialogs {\n constructor(private bridge: NativeBridge) {}\n\n /**\n * Show open file dialog\n */\n async showOpenDialog(options: OpenDialogOptions = {}): Promise<{ canceled: boolean; filePaths: string[] }> {\n return this.bridge.request('dialog.showOpenDialog', options)\n }\n\n /**\n * Show save file dialog\n */\n async showSaveDialog(options: SaveDialogOptions = {}): Promise<{ canceled: boolean; filePath?: string }> {\n return this.bridge.request('dialog.showSaveDialog', options)\n }\n\n /**\n * Show message box\n */\n async showMessageBox(options: MessageBoxOptions): Promise<{ response: number; checkboxChecked?: boolean }> {\n return this.bridge.request('dialog.showMessageBox', options)\n }\n\n /**\n * Show error box\n */\n async showErrorBox(title: string, content: string): Promise<void> {\n await this.bridge.request('dialog.showErrorBox', { title, content })\n }\n\n /**\n * Show color picker\n */\n async showColorPicker(options?: { defaultColor?: string; title?: string }): Promise<string | null> {\n return this.bridge.request('dialog.showColorPicker', options || {})\n }\n\n /**\n * Show font picker\n */\n async showFontPicker(options?: { defaultFont?: { family: string; size: number }; title?: string }): Promise<{ family: string; size: number } | null> {\n return this.bridge.request('dialog.showFontPicker', options || {})\n }\n}\n\n// Native Component Bridge\nexport interface NativeComponent {\n id: string\n type: string\n props: Record<string, unknown>\n}\n\nexport class NativeComponentBridge {\n private components = new Map<string, NativeComponent>()\n\n constructor(private bridge: NativeBridge) {\n this.bridge.on('component.event', this.handleComponentEvent.bind(this))\n }\n\n private handleComponentEvent(event: { componentId: string; eventType: string; data: unknown }): void {\n const component = this.components.get(event.componentId)\n if (component) {\n this.bridge.emit(`component:${event.componentId}:${event.eventType}`, event.data)\n }\n }\n\n /**\n * Create a native sidebar\n */\n async createSidebar(config: {\n width?: number\n minWidth?: number\n maxWidth?: number\n position?: 'left' | 'right'\n collapsible?: boolean\n collapsed?: boolean\n variant?: 'tahoe' | 'vibrancy' | 'solid' | 'transparent' | 'workspace' | 'desktop'\n material?: 'auto' | 'sidebar' | 'hud' | 'popover' | 'content'\n backgroundEffect?: 'none' | 'vibrancy' | 'shimmer'\n allowsVibrancy?: boolean\n materialOpacity?: number\n materialDarkOpacity?: number\n sections?: Array<{\n id: string\n label?: string\n title?: string\n items?: Array<{\n id: string\n label: string\n icon?: string\n href?: string\n badge?: string | number\n }>\n }>\n }): Promise<string> {\n const id = await this.bridge.request<typeof config, string>('component.createSidebar', config)\n this.components.set(id, { id, type: 'sidebar', props: config })\n return id\n }\n\n /**\n * Create a native file browser\n */\n async createFileBrowser(config: {\n rootPath?: string\n showHidden?: boolean\n selectionMode?: 'single' | 'multiple'\n fileFilter?: Array<{ name: string; extensions: string[] }>\n }): Promise<string> {\n const id = await this.bridge.request<typeof config, string>('component.createFileBrowser', config)\n this.components.set(id, { id, type: 'fileBrowser', props: config })\n return id\n }\n\n /**\n * Create a native split view\n */\n async createSplitView(config: {\n orientation?: 'horizontal' | 'vertical'\n dividerStyle?: 'thin' | 'thick' | 'paneSplitter'\n initialPosition?: number\n minPositions?: [number, number]\n }): Promise<string> {\n const id = await this.bridge.request<typeof config, string>('component.createSplitView', config)\n this.components.set(id, { id, type: 'splitView', props: config })\n return id\n }\n\n /**\n * Update component props\n */\n async updateComponent(componentId: string, props: Record<string, unknown>): Promise<void> {\n const component = this.components.get(componentId)\n if (component) {\n component.props = { ...component.props, ...props }\n }\n await this.bridge.request('component.update', { componentId, props })\n }\n\n /**\n * Destroy component\n */\n async destroyComponent(componentId: string): Promise<void> {\n this.components.delete(componentId)\n await this.bridge.request('component.destroy', { componentId })\n }\n\n /**\n * Listen for component events\n */\n onComponentEvent(componentId: string, eventType: string, callback: (data: unknown) => void): () => void {\n const eventName = `component:${componentId}:${eventType}`\n this.bridge.on(eventName, callback)\n return () => this.bridge.off(eventName, callback)\n }\n\n /**\n * Get selection from file browser\n */\n async getFileBrowserSelection(componentId: string): Promise<string[]> {\n return this.bridge.request('component.getFileBrowserSelection', { componentId })\n }\n}\n\n// Global bridge instance\nlet globalBridge: NativeBridge | null = null\nlet globalBridgeConfig: BridgeConfig | null = null\n\n/**\n * Get the process-wide singleton bridge, constructing it on first call.\n *\n * **Caveats for multi-window apps:**\n * - The first caller's `config` wins; later calls receive the existing\n * instance regardless of the config they pass — and we now log a\n * `console.warn` when a follow-up caller passes a config that differs\n * from the original (so silently-discarded configs are at least\n * visible during development).\n * - Calling `destroy()` on the returned bridge tears down state for\n * every consumer, not just the caller.\n *\n * If your app opens more than one window or test harness, prefer\n * {@link createBridge} to create independent instances and pass them\n * explicitly to the components that need them.\n */\nexport function getBridge(config?: BridgeConfig): NativeBridge {\n if (!globalBridge) {\n globalBridge = new NativeBridge(config)\n globalBridgeConfig = config ?? null\n return globalBridge\n }\n if (config && globalBridgeConfig && !shallowConfigEqual(config, globalBridgeConfig)) {\n console.warn(\n '[Craft Bridge] getBridge() ignored a follow-up config that differs from the '\n + 'original — the singleton was already constructed. Use createBridge() for '\n + 'independent instances, or call resetGlobalBridge() first.',\n )\n }\n else if (config && !globalBridgeConfig) {\n console.warn(\n '[Craft Bridge] getBridge() ignored a follow-up config — singleton already '\n + 'exists with no recorded config. Use createBridge() for independent instances.',\n )\n }\n return globalBridge\n}\n\nfunction shallowConfigEqual(a: BridgeConfig, b: BridgeConfig): boolean {\n const keys = new Set<keyof BridgeConfig>([\n ...(Object.keys(a) as Array<keyof BridgeConfig>),\n ...(Object.keys(b) as Array<keyof BridgeConfig>),\n ])\n for (const k of keys) {\n if (a[k] !== b[k]) return false\n }\n return true\n}\n\n/**\n * Create an independent bridge instance. Use this in multi-window apps and\n * tests where the singleton from {@link getBridge} would cause two callers\n * to share state.\n */\nexport function createBridge(config?: BridgeConfig): NativeBridge {\n return new NativeBridge(config)\n}\n\n/**\n * Reset the global bridge. Intended for tests that need to start from a\n * known state — call `destroy()` on the previous instance first if you\n * created any pending work.\n */\nexport function resetGlobalBridge(): void {\n globalBridge = null\n globalBridgeConfig = null\n}\n\n// Export convenience instances\nexport function getMenus(): NativeMenus {\n return new NativeMenus(getBridge())\n}\n\nexport function getDialogs(): NativeDialogs {\n return new NativeDialogs(getBridge())\n}\n\nexport function getComponents(): NativeComponentBridge {\n return new NativeComponentBridge(getBridge())\n}\n\nconst bridgeCore: {\n NativeBridge: typeof NativeBridge\n BridgeError: typeof BridgeError\n BridgeErrorCodes: typeof BridgeErrorCodes\n createTypedBridge: typeof createTypedBridge\n NativeMenus: typeof NativeMenus\n NativeDialogs: typeof NativeDialogs\n NativeComponentBridge: typeof NativeComponentBridge\n getBridge: typeof getBridge\n createBridge: typeof createBridge\n getMenus: typeof getMenus\n getDialogs: typeof getDialogs\n getComponents: typeof getComponents\n} = {\n NativeBridge,\n BridgeError,\n BridgeErrorCodes,\n createTypedBridge,\n NativeMenus,\n NativeDialogs,\n NativeComponentBridge,\n getBridge,\n createBridge,\n getMenus,\n getDialogs,\n getComponents,\n}\n\nexport default bridgeCore\n",
|
|
13
|
+
"/**\n * Cryptographically-secure ID helpers shared across the bridge implementations.\n *\n * Math.random() is not safe for IDs that are routed back to the page (callback\n * IDs, webview IDs) — predictable IDs let injected JS hijack pending callbacks.\n * Use these helpers instead.\n */\n\n/**\n * Returns a v4 UUID string. Falls back to crypto.getRandomValues when\n * randomUUID is unavailable. Throws if no Web Crypto is available at all,\n * which would indicate a non-browser, non-Node environment we don't support.\n */\nexport function secureUUID(): string {\n const c = globalThis.crypto as Crypto | undefined\n if (c && typeof c.randomUUID === 'function') {\n return c.randomUUID()\n }\n if (c && typeof c.getRandomValues === 'function') {\n const bytes = new Uint8Array(16)\n c.getRandomValues(bytes)\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`\n }\n throw new Error('[Craft] No Web Crypto available; cannot generate secure IDs')\n}\n\n/**\n * Returns a prefixed, secure ID, e.g. `webview_3f7a…`.\n */\nexport function secureId(prefix: string): string {\n return `${prefix}_${secureUUID()}`\n}\n",
|
|
14
|
+
"/**\n * Shared WKWebView pending-response helper.\n *\n * The legacy WKWebView path uses `webkit.messageHandlers.craft.postMessage`,\n * which is one-way — the native side calls back into the page via\n * `window.__craftBridgeResolve(action, payload)` (or `__craftBridgeReject`).\n *\n * Before this helper, every API module (`api/dialog.ts`, `api/clipboard.ts`)\n * re-implemented the same `__craftBridgePending` queue and a number of others\n * (`api/window.ts`, `api/app.ts`) skipped it entirely and resolved with\n * `undefined`. Centralizing it here means:\n *\n * - one place to enforce a default timeout (callers that \"just call once\"\n * can't leak closures forever),\n * - one place to expose the `__craftBridgeResolve`/`__craftBridgeReject`\n * globals the native side needs (the legacy native bridge looks for these\n * names, so they have to be declared on `window`),\n * - one place to swap the implementation later without touching every API.\n */\n\nconst DEFAULT_TIMEOUT_MS = 30_000\n\ninterface PendingEntry<T> {\n resolve: (value: T) => void\n reject: (reason: unknown) => void\n}\n\ninterface CraftBridgePendingHost {\n __craftBridgePending?: Record<string, Array<PendingEntry<any>>>\n __craftBridgeResolve?: (bucket: string, payload: unknown) => boolean\n __craftBridgeReject?: (bucket: string, error: unknown) => boolean\n}\n\nfunction host(): CraftBridgePendingHost | null {\n if (typeof window === 'undefined') return null\n return window as unknown as CraftBridgePendingHost\n}\n\n/**\n * Install the native-callable hooks (`window.__craftBridgeResolve` and\n * `window.__craftBridgeReject`) once. Idempotent — safe to call from every\n * helper that needs them.\n */\nfunction ensureGlobalHooks(): void {\n const w = host()\n if (!w) return\n w.__craftBridgePending = w.__craftBridgePending || {}\n if (!w.__craftBridgeResolve) {\n w.__craftBridgeResolve = (bucket: string, payload: unknown) => {\n const list = w.__craftBridgePending![bucket]\n if (!list || list.length === 0) return false\n const entry = list.shift()!\n entry.resolve(payload)\n return true\n }\n }\n if (!w.__craftBridgeReject) {\n w.__craftBridgeReject = (bucket: string, error: unknown) => {\n const list = w.__craftBridgePending![bucket]\n if (!list || list.length === 0) return false\n const entry = list.shift()!\n entry.reject(error instanceof Error ? error : new Error(String(error)))\n return true\n }\n }\n}\n\n/**\n * Returns true when the page is running inside a WKWebView with a registered\n * `craft` message handler.\n */\nexport function isWebKitHost(): boolean {\n return typeof window !== 'undefined' && !!window.webkit?.messageHandlers?.craft\n}\n\n/**\n * Send a fire-and-forget message into the WKWebView host. Returns true if\n * the message was delivered, false otherwise.\n */\nexport function postWebKit(message: unknown): boolean {\n if (!isWebKitHost()) return false\n window.webkit!.messageHandlers!.craft!.postMessage(message)\n return true\n}\n\n/**\n * Send a request via the WKWebView host and wait for the native side to\n * resolve it through `window.__craftBridgeResolve(bucket, payload)`. The\n * returned promise:\n *\n * - rejects with `Error('No WKWebView host')` if the page isn't running\n * inside a webview,\n * - rejects with a timeout error after `timeoutMs` if the native side\n * never replies (default 30s — match the bridge core's default),\n * - cleans up its slot in the pending queue on settle / cancel so it can\n * never leak the resolver closure.\n */\nexport function webkitRequest<T>(\n bucket: string,\n message: unknown,\n options: { timeoutMs?: number } = {},\n): Promise<T> {\n if (!isWebKitHost()) {\n return Promise.reject(new Error('No WKWebView host'))\n }\n ensureGlobalHooks()\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS\n const w = host()!\n return new Promise<T>((resolve, reject) => {\n let settled = false\n const list = (w.__craftBridgePending![bucket] = w.__craftBridgePending![bucket] || [])\n let timer: ReturnType<typeof setTimeout>\n const entry: PendingEntry<T> = {\n resolve: (v: T) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n const idx = list.indexOf(entry)\n if (idx >= 0) list.splice(idx, 1)\n resolve(v)\n },\n reject: (e: unknown) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n const idx = list.indexOf(entry)\n if (idx >= 0) list.splice(idx, 1)\n reject(e)\n },\n }\n list.push(entry)\n timer = setTimeout(() => {\n entry.reject(new Error(`[WKWebView] ${bucket} timed out after ${timeoutMs}ms`))\n }, timeoutMs)\n try {\n window.webkit!.messageHandlers!.craft!.postMessage(message)\n }\n catch (e) {\n entry.reject(e)\n }\n })\n}\n\n/**\n * Test helper: drain every queued promise and reject them with the given\n * error. Used by the test suite to assert that we don't leak closures.\n */\nexport function _drainPendingForTests(error: Error = new Error('drain')): number {\n const w = host()\n if (!w?.__craftBridgePending) return 0\n let count = 0\n for (const bucket of Object.keys(w.__craftBridgePending)) {\n const list = w.__craftBridgePending[bucket]\n while (list.length > 0) {\n const entry = list.shift()!\n entry.reject(error)\n count++\n }\n }\n return count\n}\n",
|
|
15
|
+
"/**\n * Craft Window API\n * Comprehensive window management for desktop applications\n * @module @craft-native/api/window\n */\n\nimport { getBridge } from '../bridge/core'\nimport { isWebKitHost, webkitRequest } from '../bridge/webkit-pending'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Window position on screen\n */\nexport interface WindowPosition {\n x: number\n y: number\n}\n\n/**\n * Window size dimensions\n */\nexport interface WindowSize {\n width: number\n height: number\n}\n\n/**\n * Window bounds (position + size)\n */\nexport interface WindowBounds {\n x: number\n y: number\n width: number\n height: number\n}\n\n/**\n * Window state information\n */\nexport interface WindowState {\n /** Whether window is visible */\n isVisible: boolean\n /** Whether window is minimized */\n isMinimized: boolean\n /** Whether window is maximized */\n isMaximized: boolean\n /** Whether window is fullscreen */\n isFullscreen: boolean\n /** Whether window is focused */\n isFocused: boolean\n /** Whether window is always on top */\n isAlwaysOnTop: boolean\n /** Current window bounds */\n bounds: WindowBounds\n}\n\n/**\n * Window creation options\n */\nexport interface WindowCreateOptions {\n /** Window title */\n title?: string\n /** Window width */\n width?: number\n /** Window height */\n height?: number\n /** X position (undefined = center) */\n x?: number\n /** Y position (undefined = center) */\n y?: number\n /** Minimum width */\n minWidth?: number\n /** Minimum height */\n minHeight?: number\n /** Maximum width */\n maxWidth?: number\n /** Maximum height */\n maxHeight?: number\n /** Whether window is resizable */\n resizable?: boolean\n /** Whether window is movable */\n movable?: boolean\n /** Whether window is minimizable */\n minimizable?: boolean\n /** Whether window is maximizable */\n maximizable?: boolean\n /** Whether window is closable */\n closable?: boolean\n /** Whether window is focusable */\n focusable?: boolean\n /** Whether window is always on top */\n alwaysOnTop?: boolean\n /** Whether window is fullscreen */\n fullscreen?: boolean\n /** Whether window is frameless */\n frameless?: boolean\n /** Whether window has transparency */\n transparent?: boolean\n /** Background color (for transparent windows) */\n backgroundColor?: string\n /** Whether to show in taskbar */\n skipTaskbar?: boolean\n /** Whether titlebar is hidden */\n titlebarHidden?: boolean\n /** Draw native macOS sidebar material behind a web-rendered sidebar */\n webSidebarMaterial?: boolean\n /** Width of the native material backdrop behind a web-rendered sidebar */\n webSidebarWidth?: number\n /** White/dark tint opacity over the native material backdrop */\n webSidebarMaterialOpacity?: number\n /** Titlebar style (macOS) */\n titlebarStyle?: 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover'\n /** Traffic light position (macOS) */\n trafficLightPosition?: { x: number; y: number }\n /** Vibrancy effect (macOS) */\n vibrancy?: 'appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'header' | 'sheet' | 'window' | 'hud' | 'fullscreen-ui' | 'tooltip' | 'content' | 'under-window' | 'under-page'\n /** Background material (Windows 11) */\n backgroundMaterial?: 'auto' | 'none' | 'mica' | 'acrylic' | 'tabbed'\n /** Parent window ID */\n parent?: string\n /** Whether this is a modal window */\n modal?: boolean\n /** HTML content to load */\n html?: string\n /** URL to load */\n url?: string\n}\n\n/**\n * Window event types\n */\nexport type WindowEventType =\n | 'show'\n | 'hide'\n | 'focus'\n | 'blur'\n | 'minimize'\n | 'maximize'\n | 'unmaximize'\n | 'restore'\n | 'resize'\n | 'move'\n | 'close'\n | 'closed'\n | 'enter-fullscreen'\n | 'leave-fullscreen'\n | 'ready-to-show'\n\n/**\n * Window event data map\n */\nexport interface WindowEventMap {\n 'show': void\n 'hide': void\n 'focus': void\n 'blur': void\n 'minimize': void\n 'maximize': void\n 'unmaximize': void\n 'restore': void\n 'resize': WindowSize\n 'move': WindowPosition\n 'close': { preventDefault: () => void }\n 'closed': void\n 'enter-fullscreen': void\n 'leave-fullscreen': void\n 'ready-to-show': void\n}\n\n/**\n * Window event handler\n */\nexport type WindowEventHandler<T extends WindowEventType> = (_data: WindowEventMap[T]) => void\n\n// ============================================================================\n// Window Class\n// ============================================================================\n\n/**\n * Window instance for managing a single window\n */\nexport class Window {\n private _id: string\n private _listeners: Map<string, Set<Function>> = new Map()\n private _closed: boolean = false\n private _domListeners: Array<{ type: string; handler: EventListener }> = []\n\n constructor(id: string) {\n this._id = id\n this._setupEventListeners()\n }\n\n /**\n * Get window ID\n */\n get id(): string {\n return this._id\n }\n\n /**\n * Check if window is closed\n */\n get isClosed(): boolean {\n return this._closed\n }\n\n private _setupEventListeners(): void {\n if (typeof window !== 'undefined') {\n const eventTypes: WindowEventType[] = [\n 'show', 'hide', 'focus', 'blur', 'minimize', 'maximize',\n 'unmaximize', 'restore', 'resize', 'move', 'close', 'closed',\n 'enter-fullscreen', 'leave-fullscreen', 'ready-to-show'\n ]\n\n eventTypes.forEach(type => {\n const handler = ((event: CustomEvent) => {\n if (event.detail?.windowId === this._id || !event.detail?.windowId) {\n this._emit(type, event.detail?.data)\n }\n }) as EventListener\n const eventName = `craft:window:${type}`\n globalThis.window.addEventListener(eventName, handler)\n this._domListeners.push({ type: eventName, handler })\n })\n }\n }\n\n private _cleanupEventListeners(): void {\n if (typeof window !== 'undefined') {\n for (const { type, handler } of this._domListeners) {\n globalThis.window.removeEventListener(type, handler)\n }\n this._domListeners = []\n }\n }\n\n private _emit(event: string, data?: any): void {\n const listeners = this._listeners.get(event)\n if (listeners) {\n listeners.forEach(fn => fn(data))\n }\n }\n\n /**\n * Register an event handler\n */\n on<T extends WindowEventType>(event: T, handler: WindowEventHandler<T>): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n this._listeners.get(event)!.add(handler)\n\n return () => {\n this._listeners.get(event)?.delete(handler)\n }\n }\n\n /**\n * Register a one-time event handler\n */\n once<T extends WindowEventType>(event: T, handler: WindowEventHandler<T>): () => void {\n const wrapper = (data: WindowEventMap[T]) => {\n this._listeners.get(event)?.delete(wrapper)\n handler(data)\n }\n return this.on(event, wrapper as any)\n }\n\n /**\n * Remove an event handler\n */\n off<T extends WindowEventType>(event: T, handler: WindowEventHandler<T>): void {\n this._listeners.get(event)?.delete(handler)\n }\n\n // ==========================================================================\n // Window Control Methods\n // ==========================================================================\n\n /**\n * Show the window\n */\n async show(): Promise<void> {\n await this._call('show')\n }\n\n /**\n * Hide the window\n */\n async hide(): Promise<void> {\n await this._call('hide')\n }\n\n /**\n * Toggle window visibility\n */\n async toggle(): Promise<void> {\n await this._call('toggle')\n }\n\n /**\n * Focus the window\n */\n async focus(): Promise<void> {\n await this._call('focus')\n }\n\n /**\n * Blur the window (remove focus)\n */\n async blur(): Promise<void> {\n await this._call('blur')\n }\n\n /**\n * Minimize the window\n */\n async minimize(): Promise<void> {\n await this._call('minimize')\n }\n\n /**\n * Maximize the window\n */\n async maximize(): Promise<void> {\n await this._call('maximize')\n }\n\n /**\n * Unmaximize the window\n */\n async unmaximize(): Promise<void> {\n await this._call('unmaximize')\n }\n\n /**\n * Restore the window from minimized/maximized state\n */\n async restore(): Promise<void> {\n await this._call('restore')\n }\n\n /**\n * Close the window\n */\n async close(): Promise<void> {\n await this._call('close')\n this._closed = true\n this._cleanupEventListeners()\n }\n\n /**\n * Destroy the window (force close without events)\n */\n async destroy(): Promise<void> {\n await this._call('destroy')\n this._closed = true\n this._cleanupEventListeners()\n }\n\n /**\n * Enter fullscreen mode\n */\n async setFullscreen(fullscreen: boolean = true): Promise<void> {\n await this._call('setFullscreen', { fullscreen })\n }\n\n /**\n * Toggle fullscreen mode\n */\n async toggleFullscreen(): Promise<void> {\n await this._call('toggleFullscreen')\n }\n\n // ==========================================================================\n // Window Properties\n // ==========================================================================\n\n /**\n * Set window title\n */\n async setTitle(title: string): Promise<void> {\n await this._call('setTitle', { title })\n }\n\n /**\n * Get window title\n */\n async getTitle(): Promise<string> {\n return this._call('getTitle')\n }\n\n /**\n * Set window size\n */\n async setSize(width: number, height: number, animate?: boolean): Promise<void> {\n await this._call('setSize', { width, height, animate })\n }\n\n /**\n * Get window size\n */\n async getSize(): Promise<WindowSize> {\n return this._call('getSize')\n }\n\n /**\n * Set minimum window size\n */\n async setMinimumSize(width: number, height: number): Promise<void> {\n await this._call('setMinimumSize', { width, height })\n }\n\n /**\n * Set maximum window size\n */\n async setMaximumSize(width: number, height: number): Promise<void> {\n await this._call('setMaximumSize', { width, height })\n }\n\n /**\n * Set window position\n */\n async setPosition(x: number, y: number, animate?: boolean): Promise<void> {\n await this._call('setPosition', { x, y, animate })\n }\n\n /**\n * Move window by a relative screen delta.\n */\n async moveBy(dx: number, dy: number): Promise<void> {\n await this._call('moveBy', { dx, dy })\n }\n\n /**\n * Get window position\n */\n async getPosition(): Promise<WindowPosition> {\n return this._call('getPosition')\n }\n\n /**\n * Set window bounds (position and size)\n */\n async setBounds(bounds: Partial<WindowBounds>, animate?: boolean): Promise<void> {\n await this._call('setBounds', { ...bounds, animate })\n }\n\n /**\n * Get window bounds\n */\n async getBounds(): Promise<WindowBounds> {\n return this._call('getBounds')\n }\n\n /**\n * Center window on screen\n */\n async center(): Promise<void> {\n await this._call('center')\n }\n\n /**\n * Set always on top\n */\n async setAlwaysOnTop(alwaysOnTop: boolean, level?: 'normal' | 'floating' | 'modal-panel' | 'main-menu' | 'status' | 'pop-up-menu' | 'screen-saver'): Promise<void> {\n await this._call('setAlwaysOnTop', { alwaysOnTop, level })\n }\n\n /**\n * Check if window is always on top\n */\n async isAlwaysOnTop(): Promise<boolean> {\n return this._call('isAlwaysOnTop')\n }\n\n /**\n * Set window resizable\n */\n async setResizable(resizable: boolean): Promise<void> {\n await this._call('setResizable', { resizable })\n }\n\n /**\n * Check if window is resizable\n */\n async isResizable(): Promise<boolean> {\n return this._call('isResizable')\n }\n\n /**\n * Set window movable\n */\n async setMovable(movable: boolean): Promise<void> {\n await this._call('setMovable', { movable })\n }\n\n /**\n * Start moving the native window from the current pointer event.\n */\n async startDrag(): Promise<void> {\n await this._call('startDrag')\n }\n\n /**\n * Check if window is movable\n */\n async isMovable(): Promise<boolean> {\n return this._call('isMovable')\n }\n\n /**\n * Set minimum window size\n */\n async setMinSize(width: number, height: number): Promise<void> {\n await this._call('setMinSize', { width, height })\n }\n\n /**\n * Set maximum window size\n */\n async setMaxSize(width: number, height: number): Promise<void> {\n await this._call('setMaxSize', { width, height })\n }\n\n /**\n * Set window opacity\n */\n async setOpacity(opacity: number): Promise<void> {\n await this._call('setOpacity', { opacity: Math.max(0, Math.min(1, opacity)) })\n }\n\n /**\n * Get window opacity\n */\n async getOpacity(): Promise<number> {\n return this._call('getOpacity')\n }\n\n /**\n * Set background color\n */\n async setBackgroundColor(color: string): Promise<void> {\n await this._call('setBackgroundColor', { color })\n }\n\n /**\n * Get window state\n */\n async getState(): Promise<WindowState> {\n return this._call('getState')\n }\n\n // ==========================================================================\n // macOS Specific\n // ==========================================================================\n\n /**\n * Set vibrancy effect (macOS)\n */\n async setVibrancy(vibrancy: WindowCreateOptions['vibrancy'] | null): Promise<void> {\n await this._call('setVibrancy', { vibrancy })\n }\n\n /**\n * Set traffic light position (macOS)\n */\n async setTrafficLightPosition(position: { x: number; y: number }): Promise<void> {\n await this._call('setTrafficLightPosition', position)\n }\n\n /**\n * Set window level (macOS)\n */\n async setWindowLevel(level: number): Promise<void> {\n await this._call('setWindowLevel', { level })\n }\n\n /**\n * Enable/disable window shadow (macOS)\n */\n async setHasShadow(hasShadow: boolean): Promise<void> {\n await this._call('setHasShadow', { hasShadow })\n }\n\n // ==========================================================================\n // Windows Specific\n // ==========================================================================\n\n /**\n * Set background material (Windows 11)\n */\n async setBackgroundMaterial(material: WindowCreateOptions['backgroundMaterial']): Promise<void> {\n await this._call('setBackgroundMaterial', { material })\n }\n\n /**\n * Flash window in taskbar (Windows)\n */\n async flashFrame(flash: boolean): Promise<void> {\n await this._call('flashFrame', { flash })\n }\n\n /**\n * Set taskbar overlay icon (Windows)\n */\n async setOverlayIcon(icon: string | null, description?: string): Promise<void> {\n await this._call('setOverlayIcon', { icon, description })\n }\n\n // ==========================================================================\n // Content\n // ==========================================================================\n\n /**\n * Load HTML content\n */\n async loadHTML(html: string): Promise<void> {\n await this._call('loadHTML', { html })\n }\n\n /**\n * Load URL\n */\n async loadURL(url: string): Promise<void> {\n await this._call('loadURL', { url })\n }\n\n /**\n * Reload content\n */\n async reload(): Promise<void> {\n await this._call('reload')\n }\n\n /**\n * Execute JavaScript in window\n */\n async executeJavaScript<T = unknown>(code: string): Promise<T> {\n return this._call('executeJavaScript', { code })\n }\n\n // ==========================================================================\n // Helper Methods\n // ==========================================================================\n\n private async _call<T = void>(action: string, data?: Record<string, any>): Promise<T> {\n if (isWebKitHost()) {\n // Route via the unified WKWebView pending queue so getters actually\n // receive their native response instead of resolving with `undefined`\n // (the previous implementation silently broke `getTitle()`,\n // `getSize()`, `getBounds()`, `getState()`, etc.).\n return webkitRequest<T>(`window.${action}`, {\n type: 'window',\n action,\n windowId: this._id,\n data,\n })\n }\n\n // Fallback to unified NativeBridge.\n const bridge = getBridge()\n return bridge.request(`window.${action}`, { windowId: this._id, ...data })\n }\n}\n\n// ============================================================================\n// Window Manager\n// ============================================================================\n\n/**\n * Window manager for creating and managing multiple windows\n */\nclass WindowManager {\n private _windows: Map<string, Window> = new Map()\n private _currentWindow: Window | null = null\n private _idCounter: number = 0\n\n constructor() {\n // Initialize current window if in WebView context\n if (typeof globalThis.window !== 'undefined') {\n this._currentWindow = new Window('main')\n this._windows.set('main', this._currentWindow)\n }\n }\n\n /**\n * Get current window (the window this code is running in)\n */\n get current(): Window {\n if (!this._currentWindow) {\n this._currentWindow = new Window('main')\n this._windows.set('main', this._currentWindow)\n }\n return this._currentWindow\n }\n\n /**\n * Get all windows\n */\n get all(): Window[] {\n return Array.from(this._windows.values())\n }\n\n /**\n * Get window by ID\n */\n get(id: string): Window | undefined {\n return this._windows.get(id)\n }\n\n /**\n * Create a new window\n */\n async create(options: WindowCreateOptions = {}): Promise<Window> {\n const id = `window_${++this._idCounter}_${Date.now()}`\n\n const bridge = getBridge()\n await bridge.request('window.create', { id, ...options })\n\n const win = new Window(id)\n this._windows.set(id, win)\n\n return win\n }\n\n /**\n * Get focused window\n */\n async getFocused(): Promise<Window | null> {\n const bridge = getBridge()\n const id = await bridge.request<void, string | null>('window.getFocused')\n return id ? this._windows.get(id) || null : null\n }\n\n // ==========================================================================\n // Convenience methods for current window\n // ==========================================================================\n\n /** Show current window */\n show = (): Promise<void> => this.current.show()\n\n /** Hide current window */\n hide = (): Promise<void> => this.current.hide()\n\n /** Toggle current window visibility */\n toggle = (): Promise<void> => this.current.toggle()\n\n /** Minimize current window */\n minimize = (): Promise<void> => this.current.minimize()\n\n /** Maximize current window */\n maximize = (): Promise<void> => this.current.maximize()\n\n /** Close current window */\n close = (): Promise<void> => this.current.close()\n\n /** Focus current window */\n focus = (): Promise<void> => this.current.focus()\n\n /** Center current window */\n center = (): Promise<void> => this.current.center()\n\n /** Set current window fullscreen */\n setFullscreen = (fullscreen?: boolean): Promise<void> => this.current.setFullscreen(fullscreen)\n\n /** Toggle current window fullscreen */\n toggleFullscreen = (): Promise<void> => this.current.toggleFullscreen()\n\n /** Set current window title */\n setTitle = (title: string): Promise<void> => this.current.setTitle(title)\n\n /** Set current window size */\n setSize = (width: number, height: number, animate?: boolean): Promise<void> => this.current.setSize(width, height, animate)\n\n /** Set current window position */\n setPosition = (x: number, y: number, animate?: boolean): Promise<void> => this.current.setPosition(x, y, animate)\n\n /** Move current window by a relative screen delta */\n moveBy = (dx: number, dy: number): Promise<void> => this.current.moveBy(dx, dy)\n\n /** Set current window bounds */\n setBounds = (bounds: Partial<WindowBounds>, animate?: boolean): Promise<void> => this.current.setBounds(bounds, animate)\n\n /** Set current window always on top */\n setAlwaysOnTop = (alwaysOnTop: boolean): Promise<void> => this.current.setAlwaysOnTop(alwaysOnTop)\n\n /** Set current window opacity */\n setOpacity = (opacity: number): Promise<void> => this.current.setOpacity(opacity)\n\n /** Set current window background color */\n setBackgroundColor = (color: string): Promise<void> => this.current.setBackgroundColor(color)\n\n /** Set current window vibrancy (macOS) */\n setVibrancy = (vibrancy: WindowCreateOptions['vibrancy'] | null): Promise<void> => this.current.setVibrancy(vibrancy)\n\n /** Set current window resizable */\n setResizable = (resizable: boolean): Promise<void> => this.current.setResizable(resizable)\n\n /** Start moving current window from a native pointer event */\n startDrag = (): Promise<void> => this.current.startDrag()\n\n /** Get current window state */\n getState = (): Promise<WindowState> => this.current.getState()\n\n /** Register event handler on current window */\n on = <T extends WindowEventType>(event: T, handler: WindowEventHandler<T>): (() => void) => this.current.on(event, handler)\n\n /** Register one-time event handler on current window */\n once = <T extends WindowEventType>(event: T, handler: WindowEventHandler<T>): (() => void) => this.current.once(event, handler)\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\n/**\n * Global window manager instance\n */\nexport const windowManager: WindowManager = new WindowManager()\n\n/**\n * Alias for convenience - manage the current window and child windows.\n */\nexport const win: WindowManager = windowManager\n\n/**\n * Documentation-friendly alias for the window manager.\n */\nexport const window: WindowManager = windowManager\n\n/**\n * Create a new native window.\n */\nexport function createWindow(_options?: WindowCreateOptions): Promise<Window>\nexport function createWindow(_html: string, _options?: WindowCreateOptions): Promise<Window>\nexport function createWindow(\n htmlOrOptions: string | WindowCreateOptions = {},\n options: WindowCreateOptions = {},\n): Promise<Window> {\n const windowOptions = typeof htmlOrOptions === 'string'\n ? { ...options, html: htmlOrOptions }\n : htmlOrOptions\n\n return windowManager.create(windowOptions)\n}\n\nexport default windowManager\n",
|
|
16
|
+
"/**\n * Craft System Tray / Menubar API\n * Comprehensive system tray and menubar app management\n * @module @craft-native/api/tray\n */\n\nimport { getBridge } from '../bridge/core'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Menu item configuration\n */\nexport interface MenuItem {\n /** Unique identifier */\n id?: string\n /** Display label */\n label?: string\n /** Menu item type */\n type?: 'normal' | 'separator' | 'checkbox' | 'radio' | 'submenu'\n /** Checked state (checkbox/radio) */\n checked?: boolean\n /** Enabled state */\n enabled?: boolean\n /** Visible state */\n visible?: boolean\n /** Icon path or SF Symbol name */\n icon?: string\n /** Keyboard shortcut (e.g., 'Cmd+Q', 'Ctrl+Shift+N') */\n shortcut?: string\n /** Action identifier or built-in action */\n action?: 'show' | 'hide' | 'toggle' | 'quit' | string\n /** Submenu items */\n submenu?: MenuItem[]\n /** Tooltip text */\n tooltip?: string\n /** Role (built-in menu item) */\n role?: 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'selectAll' | 'delete' | 'minimize' | 'close' | 'quit' | 'toggleFullScreen' | 'hide' | 'hideOthers' | 'unhide' | 'front' | 'zoom' | 'window' | 'help' | 'about' | 'services' | 'recentDocuments' | 'clearRecentDocuments'\n}\n\n/**\n * Tray click event\n */\nexport interface TrayClickEvent {\n /** Mouse button clicked */\n button: 'left' | 'right' | 'middle'\n /** Click timestamp */\n timestamp: number\n /** Double click */\n doubleClick?: boolean\n /** Alt/Option key held */\n altKey?: boolean\n /** Shift key held */\n shiftKey?: boolean\n /** Control key held */\n ctrlKey?: boolean\n /** Command/Meta key held */\n metaKey?: boolean\n /** Click position */\n position?: { x: number; y: number }\n /** Tray bounds */\n bounds?: { x: number; y: number; width: number; height: number }\n}\n\n/**\n * Tray configuration options\n */\nexport interface TrayOptions {\n /** Title/text to display in menubar */\n title?: string\n /** Icon path or template image name */\n icon?: string\n /** Tooltip text */\n tooltip?: string\n /** Menu items */\n menu?: MenuItem[]\n /** Highlight mode on click */\n highlightMode?: 'always' | 'selection' | 'never'\n /** Ignore double click events */\n ignoreDoubleClickEvents?: boolean\n}\n\n/**\n * Menubar app configuration\n */\nexport interface MenubarAppConfig {\n /** Tray title/text */\n title?: string\n /** Tray icon */\n icon?: string\n /** Tooltip */\n tooltip?: string\n /** Menu items */\n menu?: MenuItem[]\n /** Show window on tray click */\n showWindowOnClick?: boolean\n /** Window width when shown */\n windowWidth?: number\n /** Window height when shown */\n windowHeight?: number\n /** Window position relative to tray */\n windowPosition?: 'center' | 'trayCenter' | 'trayBottomCenter' | 'trayBottomLeft' | 'trayBottomRight'\n /** Arrow pointing to tray icon */\n showArrow?: boolean\n /** Vibrancy effect for popup window (macOS) */\n vibrancy?: 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar'\n /** Hide dock icon (macOS) */\n hideDockIcon?: boolean\n /** Show on all workspaces/spaces */\n showOnAllWorkspaces?: boolean\n /** Activation policy (macOS) */\n activationPolicy?: 'regular' | 'accessory' | 'prohibited'\n}\n\n/**\n * Tray event types\n */\nexport type TrayEventType =\n | 'click'\n | 'right-click'\n | 'double-click'\n | 'mouse-enter'\n | 'mouse-leave'\n | 'mouse-move'\n | 'drop-files'\n | 'drop-text'\n | 'menu-click'\n | 'balloon-click'\n | 'balloon-closed'\n\n/**\n * Tray event data map\n */\nexport interface TrayEventMap {\n 'click': TrayClickEvent\n 'right-click': TrayClickEvent\n 'double-click': TrayClickEvent\n 'mouse-enter': { position: { x: number; y: number } }\n 'mouse-leave': void\n 'mouse-move': { position: { x: number; y: number } }\n 'drop-files': { files: string[] }\n 'drop-text': { text: string }\n 'menu-click': { menuId: string; action: string }\n 'balloon-click': void\n 'balloon-closed': void\n}\n\n/**\n * Tray event handler\n */\nexport type TrayEventHandler<T extends TrayEventType> = (_data: TrayEventMap[T]) => void\n\n// ============================================================================\n// System Tray Class\n// ============================================================================\n\n/**\n * System tray instance\n */\nexport class SystemTray {\n private _id: string\n private _options: TrayOptions\n private _listeners: Map<string, Set<Function>> = new Map()\n private _menuHandlers: Map<string, Function> = new Map()\n private _destroyed: boolean = false\n // Tracked DOM listeners so we can remove them on destroy() — without\n // this the listener count grew unbounded on each tray construction\n // and multiple trays all received each others' click events.\n private _domListeners: Array<{ type: string; handler: EventListener }> = []\n\n constructor(id: string, options: TrayOptions = {}) {\n this._id = id\n this._options = options\n this._setupEventListeners()\n }\n\n /**\n * Get tray ID\n */\n get id(): string {\n return this._id\n }\n\n /**\n * Check if tray is destroyed\n */\n get isDestroyed(): boolean {\n return this._destroyed\n }\n\n /**\n * Filter incoming events to those addressed to this tray. The native\n * side may attach `trayId` to `event.detail`; older hosts that don't\n * set it fall through (we still fire — single-tray apps shouldn't\n * regress).\n */\n private _isForThisTray(detail: any): boolean {\n if (!detail) return true\n const id = detail.trayId ?? detail.id\n if (id === undefined || id === null) return true\n return id === this._id\n }\n\n private _addDomListener(type: string, handler: EventListener): void {\n if (typeof window === 'undefined') return\n window.addEventListener(type, handler)\n this._domListeners.push({ type, handler })\n }\n\n private _setupEventListeners(): void {\n if (typeof window !== 'undefined') {\n this._addDomListener('craft:tray:click', ((event: CustomEvent) => {\n if (this._isForThisTray(event.detail)) this._emit('click', event.detail)\n }) as EventListener)\n\n this._addDomListener('craft:tray:rightClick', ((event: CustomEvent) => {\n if (this._isForThisTray(event.detail)) this._emit('right-click', event.detail)\n }) as EventListener)\n\n this._addDomListener('craft:tray:doubleClick', ((event: CustomEvent) => {\n if (this._isForThisTray(event.detail)) this._emit('double-click', event.detail)\n }) as EventListener)\n\n this._addDomListener('craft:tray:menuAction', ((event: CustomEvent) => {\n if (!this._isForThisTray(event.detail)) return\n const action = event.detail?.action\n this._emit('menu-click', { menuId: action, action })\n\n const handler = this._menuHandlers.get(action)\n if (handler) handler()\n }) as EventListener)\n\n this._addDomListener('craft:tray:dropFiles', ((event: CustomEvent) => {\n if (this._isForThisTray(event.detail)) this._emit('drop-files', { files: event.detail?.files || [] })\n }) as EventListener)\n\n this._addDomListener('craft:tray:dropText', ((event: CustomEvent) => {\n if (this._isForThisTray(event.detail)) this._emit('drop-text', { text: event.detail?.text || '' })\n }) as EventListener)\n }\n }\n\n /**\n * Tear down DOM listeners. Idempotent. Always pair with `destroy()` on\n * the manager when constructing trays in tests/long-lived processes.\n */\n protected _teardownDomListeners(): void {\n if (typeof window === 'undefined') return\n for (const { type, handler } of this._domListeners) {\n window.removeEventListener(type, handler)\n }\n this._domListeners = []\n }\n\n private _emit(event: string, data?: any): void {\n const listeners = this._listeners.get(event)\n if (listeners) {\n listeners.forEach(fn => fn(data))\n }\n }\n\n /**\n * Register an event handler\n */\n on<T extends TrayEventType>(event: T, handler: TrayEventHandler<T>): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n this._listeners.get(event)!.add(handler)\n\n return () => {\n this._listeners.get(event)?.delete(handler)\n }\n }\n\n /**\n * Register a one-time event handler\n */\n once<T extends TrayEventType>(event: T, handler: TrayEventHandler<T>): () => void {\n const wrapper = (data: TrayEventMap[T]) => {\n this._listeners.get(event)?.delete(wrapper)\n handler(data)\n }\n return this.on(event, wrapper as any)\n }\n\n /**\n * Remove event handler\n */\n off<T extends TrayEventType>(event: T, handler: TrayEventHandler<T>): void {\n this._listeners.get(event)?.delete(handler)\n }\n\n // ==========================================================================\n // Tray Control Methods\n // ==========================================================================\n\n /**\n * Set tray title/text\n */\n async setTitle(title: string): Promise<void> {\n this._options.title = title\n await this._call('setTitle', title)\n }\n\n /**\n * Get current title\n */\n getTitle(): string {\n return this._options.title || ''\n }\n\n /**\n * Set tray icon\n */\n async setIcon(icon: string): Promise<void> {\n this._options.icon = icon\n await this._call('setIcon', icon)\n }\n\n /**\n * Set tray tooltip\n */\n async setTooltip(tooltip: string): Promise<void> {\n this._options.tooltip = tooltip\n await this._call('setTooltip', tooltip)\n }\n\n /**\n * Set or update menu\n */\n async setMenu(items: MenuItem[]): Promise<void> {\n this._options.menu = items\n\n // Process items to add handlers\n const processItems = (menuItems: MenuItem[]): MenuItem[] => {\n return menuItems.map((item, index) => {\n const processedItem = { ...item }\n\n // Generate ID if not provided\n if (!processedItem.id && processedItem.label) {\n processedItem.id = `menu_${index}_${Date.now()}`\n }\n\n // Process submenu recursively\n if (processedItem.submenu) {\n processedItem.submenu = processItems(processedItem.submenu)\n }\n\n return processedItem\n })\n }\n\n const processedItems = processItems(items)\n await this._call('setMenu', JSON.stringify(processedItems))\n }\n\n /**\n * Update a single menu item\n */\n async updateMenuItem(id: string, updates: Partial<MenuItem>): Promise<void> {\n await this._call('updateMenuItem', JSON.stringify({ id, updates }))\n }\n\n /**\n * Register a handler for a menu item action\n */\n onMenuAction(actionId: string, handler: () => void): () => void {\n this._menuHandlers.set(actionId, handler)\n return () => {\n this._menuHandlers.delete(actionId)\n }\n }\n\n /**\n * Show tray icon\n */\n async show(): Promise<void> {\n await this._call('show', '')\n }\n\n /**\n * Hide tray icon\n */\n async hide(): Promise<void> {\n await this._call('hide', '')\n }\n\n /**\n * Set highlight mode\n */\n async setHighlightMode(mode: 'always' | 'selection' | 'never'): Promise<void> {\n await this._call('setHighlightMode', mode)\n }\n\n /**\n * Display balloon notification (Windows)\n */\n async displayBalloon(options: { title: string; content: string; icon?: 'none' | 'info' | 'warning' | 'error'; largeIcon?: boolean; noSound?: boolean; respectQuietTime?: boolean }): Promise<void> {\n await this._call('displayBalloon', JSON.stringify(options))\n }\n\n /**\n * Remove balloon notification (Windows)\n */\n async removeBalloon(): Promise<void> {\n await this._call('removeBalloon', '')\n }\n\n /**\n * Get tray bounds (position and size)\n */\n async getBounds(): Promise<{ x: number; y: number; width: number; height: number }> {\n return this._call('getBounds', '')\n }\n\n /**\n * Destroy the tray\n */\n async destroy(): Promise<void> {\n await this._call('destroy', '')\n this._destroyed = true\n this._listeners.clear()\n this._menuHandlers.clear()\n this._teardownDomListeners()\n }\n\n // ==========================================================================\n // Convenience Methods\n // ==========================================================================\n\n /**\n * Show window when tray is clicked\n */\n onClickShowWindow(): () => void {\n return this.on('click', () => {\n if (typeof window !== 'undefined' && (window as any).craft?.window?.show) {\n (window as any).craft.window.show()\n }\n })\n }\n\n /**\n * Toggle window when tray is clicked\n */\n onClickToggleWindow(): () => void {\n return this.on('click', () => {\n if (typeof window !== 'undefined' && (window as any).craft?.window?.toggle) {\n (window as any).craft.window.toggle()\n }\n })\n }\n\n // ==========================================================================\n // Helper Methods\n // ==========================================================================\n\n private async _call<T = void>(action: string, data: string | object): Promise<T> {\n if (typeof window !== 'undefined' && (window as any).webkit?.messageHandlers?.craft) {\n return new Promise((resolve, reject) => {\n try {\n (window as any).webkit.messageHandlers.craft.postMessage({\n type: 'tray',\n action,\n data: typeof data === 'string' ? data : JSON.stringify(data)\n })\n resolve(undefined as T)\n }\ncatch (error) {\n reject(error)\n }\n })\n }\n\n const bridge = getBridge()\n return bridge.request(`tray.${action}`, { data })\n }\n}\n\n// ============================================================================\n// Menubar App Class\n// ============================================================================\n\n/**\n * Menubar app with optional popup window\n * Perfect for:\n * - Status bar utilities (Pomodoro timers, CPU monitors)\n * - Quick access tools (clipboard managers, color pickers)\n * - Background services with UI (sync status, VPN controls)\n */\nexport class MenubarApp {\n private _tray: SystemTray\n private _config: MenubarAppConfig\n private _windowVisible: boolean = false\n\n constructor(config: MenubarAppConfig = {}) {\n this._config = {\n showWindowOnClick: true,\n windowWidth: 320,\n windowHeight: 400,\n windowPosition: 'trayBottomCenter',\n hideDockIcon: true,\n ...config\n }\n\n this._tray = new SystemTray('menubar', {\n title: config.title,\n icon: config.icon,\n tooltip: config.tooltip,\n menu: config.menu\n })\n\n this._setupBehavior()\n }\n\n /**\n * Get the underlying tray instance\n */\n get tray(): SystemTray {\n return this._tray\n }\n\n /**\n * Check if popup window is visible\n */\n get isWindowVisible(): boolean {\n return this._windowVisible\n }\n\n private _setupBehavior(): void {\n // Handle clicks based on config\n if (this._config.showWindowOnClick) {\n this._tray.on('click', () => {\n this.toggleWindow()\n })\n }\n\n // Hide dock icon if configured\n if (this._config.hideDockIcon) {\n this._hideDockIcon()\n }\n }\n\n private async _hideDockIcon(): Promise<void> {\n if (typeof window !== 'undefined' && (window as any).craft?.app?.hideDockIcon) {\n await (window as any).craft.app.hideDockIcon()\n }\n }\n\n /**\n * Show the popup window\n */\n async showWindow(): Promise<void> {\n if (typeof window !== 'undefined' && (window as any).craft?.window?.show) {\n await (window as any).craft.window.show()\n this._windowVisible = true\n }\n }\n\n /**\n * Hide the popup window\n */\n async hideWindow(): Promise<void> {\n if (typeof window !== 'undefined' && (window as any).craft?.window?.hide) {\n await (window as any).craft.window.hide()\n this._windowVisible = false\n }\n }\n\n /**\n * Toggle the popup window\n */\n async toggleWindow(): Promise<void> {\n if (this._windowVisible) {\n await this.hideWindow()\n }\nelse {\n await this.showWindow()\n }\n }\n\n /**\n * Set tray title\n */\n setTitle(title: string): Promise<void> {\n return this._tray.setTitle(title)\n }\n\n /**\n * Set tray icon\n */\n setIcon(icon: string): Promise<void> {\n return this._tray.setIcon(icon)\n }\n\n /**\n * Set menu\n */\n setMenu(items: MenuItem[]): Promise<void> {\n return this._tray.setMenu(items)\n }\n\n /**\n * Register menu action handler\n */\n onMenuAction(actionId: string, handler: () => void): () => void {\n return this._tray.onMenuAction(actionId, handler)\n }\n\n /**\n * Quit the app\n */\n async quit(): Promise<void> {\n if (typeof window !== 'undefined' && (window as any).craft?.app?.quit) {\n await (window as any).craft.app.quit()\n }\n }\n}\n\n// ============================================================================\n// Tray Manager\n// ============================================================================\n\n/**\n * Manage system tray instances\n */\nclass TrayManager {\n private _trays: Map<string, SystemTray> = new Map()\n private _mainTray: SystemTray | null = null\n\n /**\n * Get or create the main tray\n */\n get main(): SystemTray {\n if (!this._mainTray) {\n this._mainTray = new SystemTray('main')\n this._trays.set('main', this._mainTray)\n }\n return this._mainTray\n }\n\n /**\n * Create a new tray\n */\n create(id: string, options: TrayOptions = {}): SystemTray {\n const tray = new SystemTray(id, options)\n this._trays.set(id, tray)\n\n if (!this._mainTray) {\n this._mainTray = tray\n }\n\n return tray\n }\n\n /**\n * Get tray by ID\n */\n get(id: string): SystemTray | undefined {\n return this._trays.get(id)\n }\n\n /**\n * Destroy a tray\n */\n async destroy(id: string): Promise<void> {\n const tray = this._trays.get(id)\n if (tray) {\n await tray.destroy()\n this._trays.delete(id)\n if (this._mainTray?.id === id) {\n this._mainTray = null\n }\n }\n }\n\n /**\n * Destroy all trays\n */\n async destroyAll(): Promise<void> {\n for (const tray of this._trays.values()) {\n await tray.destroy()\n }\n this._trays.clear()\n this._mainTray = null\n }\n\n // ==========================================================================\n // Convenience methods for main tray\n // ==========================================================================\n\n /** Set main tray title */\n setTitle = (title: string): Promise<void> => this.main.setTitle(title)\n\n /** Set main tray icon */\n setIcon = (icon: string): Promise<void> => this.main.setIcon(icon)\n\n /** Set main tray tooltip */\n setTooltip = (tooltip: string): Promise<void> => this.main.setTooltip(tooltip)\n\n /** Set main tray menu */\n setMenu = (items: MenuItem[]): Promise<void> => this.main.setMenu(items)\n\n /** Register menu action on main tray */\n onMenuAction = (actionId: string, handler: () => void): (() => void) => this.main.onMenuAction(actionId, handler)\n\n /** Register click handler on main tray */\n onClick = (handler: TrayEventHandler<'click'>): (() => void) => this.main.on('click', handler)\n\n /** Register right-click handler on main tray */\n onRightClick = (handler: TrayEventHandler<'right-click'>): (() => void) => this.main.on('right-click', handler)\n\n /** Toggle window on click */\n onClickToggleWindow = (): (() => void) => this.main.onClickToggleWindow()\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\n/**\n * Global tray manager instance\n */\nexport const trayManager: TrayManager = new TrayManager()\n\n/**\n * Alias for convenience\n */\nexport const tray: TrayManager = trayManager\n\n/**\n * Create a menubar app\n */\nexport function createMenubarApp(config?: MenubarAppConfig): MenubarApp {\n return new MenubarApp(config)\n}\n\n/**\n * Helper to build a menu from items\n */\nexport function buildMenu(...items: MenuItem[]): MenuItem[] {\n return items\n}\n\n/**\n * Create a separator menu item\n */\nexport function separator(): MenuItem {\n return { type: 'separator' }\n}\n\n/**\n * Create a normal menu item\n */\nexport function menuItem(label: string, options: Omit<MenuItem, 'label' | 'type'> = {}): MenuItem {\n return { label, type: 'normal', ...options }\n}\n\n/**\n * Create a checkbox menu item\n */\nexport function checkbox(label: string, checked: boolean, options: Omit<MenuItem, 'label' | 'type' | 'checked'> = {}): MenuItem {\n return { label, type: 'checkbox', checked, ...options }\n}\n\n/**\n * Create a submenu\n */\nexport function submenu(label: string, items: MenuItem[], options: Omit<MenuItem, 'label' | 'type' | 'submenu'> = {}): MenuItem {\n return { label, type: 'submenu', submenu: items, ...options }\n}\n\nexport default trayManager\n",
|
|
17
|
+
"/**\n * Craft App API\n * Application lifecycle, configuration, and system integration\n * @module @craft-native/api/app\n */\n\nimport { getBridge } from '../bridge/core'\nimport { isWebKitHost, webkitRequest } from '../bridge/webkit-pending'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Application information\n */\nexport interface AppInfo {\n /** App name */\n name: string\n /** App version */\n version: string\n /** Bundle identifier */\n bundleId?: string\n /** Build number */\n buildNumber?: string\n /** Platform */\n platform: 'macos' | 'windows' | 'linux' | 'ios' | 'android'\n /** Architecture */\n arch: 'x64' | 'arm64' | 'x86' | 'arm'\n /** App path */\n appPath: string\n /** User data path */\n userDataPath: string\n /** Executable path */\n executablePath: string\n /** Resources path */\n resourcesPath: string\n /** Temp path */\n tempPath: string\n /** Logs path */\n logsPath: string\n /** Is packaged app */\n isPackaged: boolean\n /** Is development mode */\n isDevelopment: boolean\n}\n\n/**\n * System preferences\n */\nexport interface SystemPreferences {\n /** Dark mode enabled */\n isDarkMode: boolean\n /** Accent color */\n accentColor: string\n /** Reduced motion */\n reducedMotion: boolean\n /** Reduced transparency */\n reducedTransparency: boolean\n /** High contrast */\n highContrast: boolean\n /** System font */\n systemFont: string\n /** System locale */\n locale: string\n /** System timezone */\n timezone: string\n}\n\n/**\n * Display information\n */\nexport interface DisplayInfo {\n /** Display ID */\n id: string\n /** Display name */\n name: string\n /** Width in pixels */\n width: number\n /** Height in pixels */\n height: number\n /** Scale factor */\n scaleFactor: number\n /** Is primary display */\n isPrimary: boolean\n /** Display bounds */\n bounds: { x: number; y: number; width: number; height: number }\n /** Work area (excluding taskbar/dock) */\n workArea: { x: number; y: number; width: number; height: number }\n /** Refresh rate */\n refreshRate?: number\n /** Color depth */\n colorDepth?: number\n /** Is touchscreen */\n touchSupport?: boolean\n}\n\n/**\n * Badge options (dock/taskbar)\n */\nexport interface BadgeOptions {\n /** Badge text/number */\n badge: string | number | null\n /** Badge color (optional) */\n color?: string\n}\n\n/**\n * Notification options\n */\nexport interface NotificationOptions {\n /** Notification title */\n title: string\n /** Notification body */\n body?: string\n /** Notification subtitle (macOS) */\n subtitle?: string\n /** Icon path */\n icon?: string\n /** Sound to play */\n sound?: string | 'default' | 'none'\n /** Action buttons */\n actions?: Array<{ action: string; title: string; icon?: string }>\n /** Close button text */\n closeButtonText?: string\n /** Has reply field */\n hasReply?: boolean\n /** Reply placeholder */\n replyPlaceholder?: string\n /** Timeout type */\n timeoutType?: 'default' | 'never'\n /** Urgency (Linux) */\n urgency?: 'low' | 'normal' | 'critical'\n /** Silent */\n silent?: boolean\n /** Tag for grouping/replacing */\n tag?: string\n}\n\n/**\n * App event types\n */\nexport type AppEventType =\n | 'ready'\n | 'activate'\n | 'deactivate'\n | 'will-quit'\n | 'quit'\n | 'before-quit'\n | 'window-all-closed'\n | 'open-file'\n | 'open-url'\n | 'theme-changed'\n | 'accent-color-changed'\n | 'display-added'\n | 'display-removed'\n | 'display-metrics-changed'\n | 'power-suspend'\n | 'power-resume'\n | 'power-on-ac'\n | 'power-on-battery'\n | 'lock-screen'\n | 'unlock-screen'\n | 'user-did-become-active'\n | 'user-did-resign-active'\n\n/**\n * App event data map\n */\nexport interface AppEventMap {\n 'ready': void\n 'activate': { hasVisibleWindows: boolean }\n 'deactivate': void\n 'will-quit': { preventDefault: () => void }\n 'quit': void\n 'before-quit': { preventDefault: () => void }\n 'window-all-closed': void\n 'open-file': { path: string }\n 'open-url': { url: string }\n 'theme-changed': { theme: 'light' | 'dark' }\n 'accent-color-changed': { color: string }\n 'display-added': DisplayInfo\n 'display-removed': { id: string }\n 'display-metrics-changed': { display: DisplayInfo; changedMetrics: string[] }\n 'power-suspend': void\n 'power-resume': void\n 'power-on-ac': void\n 'power-on-battery': void\n 'lock-screen': void\n 'unlock-screen': void\n 'user-did-become-active': void\n 'user-did-resign-active': void\n}\n\n/**\n * App event handler\n */\nexport type AppEventHandler<T extends AppEventType> = (_data: AppEventMap[T]) => void\n\n/**\n * Global shortcut handler\n */\nexport type ShortcutHandler = () => void\n\n// ============================================================================\n// App Manager Class\n// ============================================================================\n\n/**\n * Application manager for lifecycle and system integration\n */\nclass AppManager {\n private _listeners: Map<string, Set<Function>> = new Map()\n private _shortcuts: Map<string, ShortcutHandler> = new Map()\n private _info: AppInfo | null = null\n private _preferences: SystemPreferences | null = null\n private _domListeners: Array<{ type: string; handler: EventListener }> = []\n private _mediaQuery: MediaQueryList | null = null\n private _mediaQueryHandler: ((_event: MediaQueryListEvent) => void) | null = null\n\n constructor() {\n this._setupEventListeners()\n }\n\n private _addDomListener(type: string, handler: EventListener): void {\n if (typeof window === 'undefined') return\n window.addEventListener(type, handler)\n this._domListeners.push({ type, handler })\n }\n\n /**\n * Tear down DOM listeners. Intended for tests that construct/destroy\n * the manager and for advanced multi-window setups; the singleton\n * `appManager` is normally process-lived.\n */\n destroy(): void {\n if (typeof window !== 'undefined') {\n for (const { type, handler } of this._domListeners) {\n window.removeEventListener(type, handler)\n }\n this._domListeners = []\n if (this._mediaQuery && this._mediaQueryHandler) {\n this._mediaQuery.removeEventListener('change', this._mediaQueryHandler)\n this._mediaQuery = null\n this._mediaQueryHandler = null\n }\n }\n this._listeners.clear()\n this._shortcuts.clear()\n this._info = null\n this._preferences = null\n }\n\n private _setupEventListeners(): void {\n if (typeof window !== 'undefined') {\n // System events\n const events: AppEventType[] = [\n 'ready', 'activate', 'deactivate', 'will-quit', 'quit', 'before-quit',\n 'window-all-closed', 'open-file', 'open-url', 'theme-changed',\n 'accent-color-changed', 'display-added', 'display-removed',\n 'display-metrics-changed', 'power-suspend', 'power-resume',\n 'power-on-ac', 'power-on-battery', 'lock-screen', 'unlock-screen',\n 'user-did-become-active', 'user-did-resign-active',\n ]\n\n events.forEach(event => {\n const handler = ((e: CustomEvent) => {\n // Invalidate caches that the event has just made stale.\n // `_preferences` snapshots theme/accent/reduced-motion/locale,\n // so any of these events must clear it to avoid serving stale\n // values from `getSystemPreferences()`. `_info` snapshots\n // immutable bundle metadata, so it's preserved.\n if (\n event === 'theme-changed'\n || event === 'accent-color-changed'\n || event === 'display-added'\n || event === 'display-removed'\n || event === 'display-metrics-changed'\n ) {\n this._preferences = null\n }\n this._emit(event, e.detail)\n }) as EventListener\n this._addDomListener(`craft:app:${event}`, handler)\n })\n\n // Global shortcut events\n const shortcutHandler = ((e: CustomEvent) => {\n const accelerator = e.detail?.accelerator\n const handler = this._shortcuts.get(accelerator)\n if (handler) handler()\n }) as EventListener\n this._addDomListener('craft:shortcut', shortcutHandler)\n\n // Theme change detection via media query\n if (window.matchMedia) {\n this._mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n this._mediaQueryHandler = (e: MediaQueryListEvent) => {\n this._preferences = null\n this._emit('theme-changed', { theme: e.matches ? 'dark' : 'light' })\n }\n this._mediaQuery.addEventListener('change', this._mediaQueryHandler)\n }\n }\n }\n\n private _emit(event: string, data?: any): void {\n const listeners = this._listeners.get(event)\n if (listeners) {\n listeners.forEach(fn => fn(data))\n }\n }\n\n /**\n * Register an event handler\n */\n on<T extends AppEventType>(event: T, handler: AppEventHandler<T>): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n this._listeners.get(event)!.add(handler)\n\n return () => {\n this._listeners.get(event)?.delete(handler)\n }\n }\n\n /**\n * Register a one-time event handler\n */\n once<T extends AppEventType>(event: T, handler: AppEventHandler<T>): () => void {\n const wrapper = (data: AppEventMap[T]) => {\n this._listeners.get(event)?.delete(wrapper)\n handler(data)\n }\n return this.on(event, wrapper as any)\n }\n\n /**\n * Remove event handler\n */\n off<T extends AppEventType>(event: T, handler: AppEventHandler<T>): void {\n this._listeners.get(event)?.delete(handler)\n }\n\n // ==========================================================================\n // App Lifecycle\n // ==========================================================================\n\n /**\n * Quit the application\n */\n async quit(): Promise<void> {\n await this._call('quit')\n }\n\n /**\n * Exit with code\n */\n async exit(code: number = 0): Promise<void> {\n await this._call('exit', { code })\n }\n\n /**\n * Relaunch the application\n */\n async relaunch(options?: { args?: string[]; execPath?: string }): Promise<void> {\n await this._call('relaunch', options)\n }\n\n /**\n * Hide the application (macOS)\n */\n async hide(): Promise<void> {\n await this._call('hide')\n }\n\n /**\n * Show the application (macOS)\n */\n async show(): Promise<void> {\n await this._call('show')\n }\n\n /**\n * Focus the application\n */\n async focus(): Promise<void> {\n await this._call('focus')\n }\n\n // ==========================================================================\n // Dock Icon (macOS)\n // ==========================================================================\n\n /**\n * Hide dock icon (macOS)\n */\n async hideDockIcon(): Promise<void> {\n await this._call('hideDockIcon')\n }\n\n /**\n * Show dock icon (macOS)\n */\n async showDockIcon(): Promise<void> {\n await this._call('showDockIcon')\n }\n\n /**\n * Set dock icon badge\n */\n async setBadge(badge: string | number | null): Promise<void> {\n await this._call('setBadge', { badge: badge?.toString() ?? '' })\n }\n\n /**\n * Get dock icon badge\n */\n async getBadge(): Promise<string> {\n return this._call('getBadge')\n }\n\n /**\n * Bounce dock icon (macOS)\n */\n async bounce(type: 'critical' | 'informational' = 'informational'): Promise<number> {\n return this._call('bounce', { type })\n }\n\n /**\n * Cancel dock icon bounce (macOS)\n */\n async cancelBounce(id: number): Promise<void> {\n await this._call('cancelBounce', { id })\n }\n\n /**\n * Set dock icon\n */\n async setDockIcon(icon: string): Promise<void> {\n await this._call('setDockIcon', { icon })\n }\n\n // ==========================================================================\n // App Information\n // ==========================================================================\n\n /**\n * Get application information\n */\n async getInfo(): Promise<AppInfo> {\n if (!this._info) {\n this._info = await this._call<AppInfo>('getInfo')\n }\n return this._info\n }\n\n /**\n * Get app name\n */\n async getName(): Promise<string> {\n const info = await this.getInfo()\n return info.name\n }\n\n /**\n * Get app version\n */\n async getVersion(): Promise<string> {\n const info = await this.getInfo()\n return info.version\n }\n\n /**\n * Get app path\n */\n async getAppPath(): Promise<string> {\n const info = await this.getInfo()\n return info.appPath\n }\n\n /**\n * Get path to special directory\n */\n async getPath(name: 'home' | 'appData' | 'userData' | 'temp' | 'exe' | 'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos' | 'logs'): Promise<string> {\n return this._call('getPath', { name })\n }\n\n // ==========================================================================\n // System Preferences\n // ==========================================================================\n\n /**\n * Get system preferences\n */\n async getSystemPreferences(): Promise<SystemPreferences> {\n if (!this._preferences) {\n this._preferences = await this._call<SystemPreferences>('getSystemPreferences')\n }\n return this._preferences\n }\n\n /**\n * Check if dark mode is enabled\n */\n async isDarkMode(): Promise<boolean> {\n // Try browser API first\n if (typeof window !== 'undefined' && window.matchMedia) {\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n }\n const prefs = await this.getSystemPreferences()\n return prefs.isDarkMode\n }\n\n /**\n * Get accent color\n */\n async getAccentColor(): Promise<string> {\n const prefs = await this.getSystemPreferences()\n return prefs.accentColor\n }\n\n /**\n * Check if reduced motion is enabled\n */\n async isReducedMotion(): Promise<boolean> {\n if (typeof window !== 'undefined' && window.matchMedia) {\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n }\n const prefs = await this.getSystemPreferences()\n return prefs.reducedMotion\n }\n\n /**\n * Get system locale\n */\n async getLocale(): Promise<string> {\n if (typeof navigator !== 'undefined') {\n return navigator.language || 'en-US'\n }\n const prefs = await this.getSystemPreferences()\n return prefs.locale\n }\n\n // ==========================================================================\n // Display\n // ==========================================================================\n\n /**\n * Get all displays\n */\n async getDisplays(): Promise<DisplayInfo[]> {\n return this._call('getDisplays')\n }\n\n /**\n * Get primary display\n */\n async getPrimaryDisplay(): Promise<DisplayInfo> {\n return this._call('getPrimaryDisplay')\n }\n\n /**\n * Get display at point\n */\n async getDisplayAtPoint(x: number, y: number): Promise<DisplayInfo | null> {\n return this._call('getDisplayAtPoint', { x, y })\n }\n\n // ==========================================================================\n // Notifications\n // ==========================================================================\n\n /**\n * Send a notification\n */\n async notify(options: NotificationOptions): Promise<void> {\n await this._call('notify', options)\n }\n\n /**\n * Check if notifications are supported\n */\n async isNotificationSupported(): Promise<boolean> {\n if (typeof Notification !== 'undefined') {\n return Notification.permission !== 'denied'\n }\n return this._call('isNotificationSupported')\n }\n\n // ==========================================================================\n // Global Shortcuts\n // ==========================================================================\n\n /**\n * Register a global shortcut\n */\n async registerShortcut(accelerator: string, handler: ShortcutHandler): Promise<boolean> {\n this._shortcuts.set(accelerator, handler)\n return this._call('registerShortcut', { accelerator })\n }\n\n /**\n * Unregister a global shortcut\n */\n async unregisterShortcut(accelerator: string): Promise<void> {\n this._shortcuts.delete(accelerator)\n await this._call('unregisterShortcut', { accelerator })\n }\n\n /**\n * Unregister all global shortcuts\n */\n async unregisterAllShortcuts(): Promise<void> {\n this._shortcuts.clear()\n await this._call('unregisterAllShortcuts')\n }\n\n /**\n * Check if a shortcut is registered\n */\n async isShortcutRegistered(accelerator: string): Promise<boolean> {\n return this._call('isShortcutRegistered', { accelerator })\n }\n\n // ==========================================================================\n // Appearance\n // ==========================================================================\n\n /**\n * Set app appearance (macOS)\n */\n async setAppearance(appearance: 'light' | 'dark' | 'system'): Promise<void> {\n await this._call('setAppearance', { appearance })\n }\n\n /**\n * Get current appearance\n */\n async getAppearance(): Promise<'light' | 'dark'> {\n return this._call('getAppearance')\n }\n\n // ==========================================================================\n // Power Management\n // ==========================================================================\n\n /**\n * Start power save blocker\n */\n async startPowerSaveBlocker(type: 'prevent-app-suspension' | 'prevent-display-sleep'): Promise<number> {\n return this._call('startPowerSaveBlocker', { type })\n }\n\n /**\n * Stop power save blocker\n */\n async stopPowerSaveBlocker(id: number): Promise<void> {\n await this._call('stopPowerSaveBlocker', { id })\n }\n\n /**\n * Check if power save blocker is active\n */\n async isPowerSaveBlockerActive(id: number): Promise<boolean> {\n return this._call('isPowerSaveBlockerActive', { id })\n }\n\n /**\n * Get system idle time\n */\n async getIdleTime(): Promise<number> {\n return this._call('getIdleTime')\n }\n\n // ==========================================================================\n // Login Items (macOS/Windows)\n // ==========================================================================\n\n /**\n * Set login item settings\n */\n async setLoginItemSettings(options: { openAtLogin: boolean; openAsHidden?: boolean; path?: string; args?: string[] }): Promise<void> {\n await this._call('setLoginItemSettings', options)\n }\n\n /**\n * Get login item settings\n */\n async getLoginItemSettings(): Promise<{ openAtLogin: boolean; openAsHidden: boolean; wasOpenedAtLogin: boolean; wasOpenedAsHidden: boolean }> {\n return this._call('getLoginItemSettings')\n }\n\n // ==========================================================================\n // Helper Methods\n // ==========================================================================\n\n private async _call<T = void>(action: string, data?: Record<string, any>): Promise<T> {\n if (isWebKitHost()) {\n // Route via the unified WKWebView pending queue so getters\n // (`getInfo`, `getDisplays`, `getBadge`, `getAppearance`, …) actually\n // receive their native response instead of resolving with `undefined`.\n return webkitRequest<T>(`app.${action}`, {\n type: 'app',\n action,\n data,\n })\n }\n\n const bridge = getBridge()\n return bridge.request(`app.${action}`, data)\n }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\n/**\n * Global app manager instance\n */\nexport const appManager: AppManager = new AppManager()\n\n/**\n * Alias for convenience\n */\nexport const app: AppManager = appManager\n\n// Re-export common functionality directly\nexport const quit = (): Promise<void> => appManager.quit()\nexport const hide = (): Promise<void> => appManager.hide()\nexport const show = (): Promise<void> => appManager.show()\nexport const focus = (): Promise<void> => appManager.focus()\nexport const hideDockIcon = (): Promise<void> => appManager.hideDockIcon()\nexport const showDockIcon = (): Promise<void> => appManager.showDockIcon()\nexport const setBadge = (badge: string | number | null): Promise<void> => appManager.setBadge(badge)\nexport const getInfo = (): Promise<AppInfo> => appManager.getInfo()\nexport const getVersion = (): Promise<string> => appManager.getVersion()\nexport const getName = (): Promise<string> => appManager.getName()\nexport const getPath = (name: Parameters<typeof appManager.getPath>[0]): Promise<string> => appManager.getPath(name)\nexport const isDarkMode = (): Promise<boolean> => appManager.isDarkMode()\nexport const getLocale = (): Promise<string> => appManager.getLocale()\nexport const notify = (options: NotificationOptions): Promise<void> => appManager.notify(options)\nexport const registerShortcut = (accelerator: string, handler: ShortcutHandler): Promise<boolean> => appManager.registerShortcut(accelerator, handler)\nexport const unregisterShortcut = (accelerator: string): Promise<void> => appManager.unregisterShortcut(accelerator)\n\nexport default appManager\n",
|
|
18
|
+
"/**\n * @fileoverview Craft File System API\n * @description Provides native file system access through the Craft bridge.\n * Works in both browser (via native bridge) and Node.js environments.\n * @module @craft-native/api/fs\n *\n * @example\n * ```typescript\n * import { fs, readBinaryFile, stat, watch } from '@craft-native/api/fs'\n *\n * // Read a text file\n * const content = await fs.readFile('/path/to/file.txt')\n *\n * // Write to a file\n * await fs.writeFile('/path/to/output.txt', 'Hello, World!')\n *\n * // List directory contents\n * const files = await fs.readDir('/path/to/directory')\n *\n * // Watch for changes (returns a Promise<() => void>)\n * const unwatch = await watch('/path/to/watch', (event, filename) => {\n * console.log(`${event}: ${filename}`)\n * })\n * ```\n */\n\nimport { getBridge } from '../bridge/core'\nimport type { CraftFileSystemAPI } from '../types'\n\n/**\n * Get the host-injected legacy file-system bridge, or null. The legacy\n * `window.craft.fs` interface is honored when present so existing native\n * hosts keep working — but new code paths route through the unified\n * {@link NativeBridge} (see {@link callBridge}).\n */\nfunction getCraftFs(): CraftFileSystemAPI | null {\n if (typeof window !== 'undefined' && (window as any).craft?.fs) {\n return (window as any).craft.fs\n }\n return null\n}\n\n/**\n * Send a request through the unified `NativeBridge`. This replaces the old\n * `window.craft.bridge.call(...)` legacy hook so every API module routes\n * through one transport with consistent timeout/retry/error semantics.\n */\nasync function callBridge<T = unknown>(method: string, params?: unknown): Promise<T> {\n return getBridge().request<unknown, T>(method, params)\n}\n\n/**\n * Validate a file path to prevent directory traversal attacks.\n *\n * Rejects:\n * - Any `..` segment (including after URL-decoding, since the host bridge may\n * percent-decode before opening the file)\n * - Embedded NULs (truncate filenames in C APIs)\n * - Empty/whitespace-only paths\n *\n * When a `root` is provided, additionally asserts that the resolved absolute\n * path is contained within `root` (best-effort — symlinks are still resolved\n * by the OS at open time).\n */\nexport function validatePath(path: string, root?: string): void {\n if (typeof path !== 'string' || path.length === 0) {\n throw new Error('Invalid path: must be a non-empty string')\n }\n\n // Block null bytes (can truncate paths in C APIs)\n if (path.includes('\\0')) {\n throw new Error('Invalid path: contains null byte')\n }\n\n // Decode percent-encoded sequences before splitting so an attacker can't\n // sneak `..` past us as `%2e%2e`.\n let decoded = path\n try {\n decoded = decodeURIComponent(path)\n }\n catch {\n // decodeURIComponent throws on malformed sequences; treat the raw path as\n // suspect rather than failing open.\n throw new Error('Invalid path: malformed percent-encoding')\n }\n\n // Normalize backslashes to forward slashes and split on / segments.\n const segments = decoded.replace(/\\\\/g, '/').split('/')\n for (const segment of segments) {\n if (segment === '..') {\n throw new Error(`Path traversal detected: \"${path}\" contains a \"..\" segment`)\n }\n }\n\n if (root) {\n // Best-effort containment check (browser path-resolve is approximate).\n const baseAbs = root.endsWith('/') ? root : `${root}/`\n const resolved = decoded.startsWith('/') ? decoded : `${baseAbs}${decoded}`\n if (!resolved.startsWith(baseAbs) && resolved !== root) {\n throw new Error(`Path escapes root: \"${path}\" not within \"${root}\"`)\n }\n }\n}\n\n/**\n * Encode a Uint8Array as base64 in chunks. Avoids `String.fromCharCode(...big)`\n * blowing up on large buffers and produces a far more compact wire payload\n * than `Array.from(uint8)` (which JSON-encodes ~5 bytes per byte).\n */\nexport function uint8ToBase64(bytes: Uint8Array): string {\n const chunks: string[] = []\n const chunkSize = 0x8000\n for (let i = 0; i < bytes.byteLength; i += chunkSize) {\n chunks.push(String.fromCharCode(...bytes.subarray(i, i + chunkSize)))\n }\n if (typeof btoa === 'function') return btoa(chunks.join(''))\n return Buffer.from(bytes).toString('base64')\n}\n\n/**\n * Decode a base64 string into a Uint8Array. Mirrors {@link uint8ToBase64}.\n */\nexport function base64ToUint8(base64: string): Uint8Array {\n if (typeof atob === 'function') {\n const binary = atob(base64)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n return bytes\n }\n return new Uint8Array(Buffer.from(base64, 'base64'))\n}\n\n/**\n * File system API implementation.\n * Uses the native Craft bridge for file operations when running in a Craft app,\n * with automatic fallback to Node.js APIs when running in a Node environment.\n *\n * @example\n * ```typescript\n * import { fs } from '@craft-native/api/fs'\n *\n * // Check if a file exists before reading\n * if (await fs.exists('/config.json')) {\n * const config = JSON.parse(await fs.readFile('/config.json'))\n * }\n * ```\n */\nexport const fs: CraftFileSystemAPI = {\n async readFile(path: string): Promise<string> {\n validatePath(path)\n const native = getCraftFs()\n if (native) return native.readFile(path)\n if (typeof window !== 'undefined' && (window as any).craft) {\n return callBridge<string>('fs.readFile', { path })\n }\n const { readFile } = await import('node:fs/promises')\n return readFile(path, 'utf-8')\n },\n\n async writeFile(path: string, content: string): Promise<void> {\n validatePath(path)\n const native = getCraftFs()\n if (native) return native.writeFile(path, content)\n if (typeof window !== 'undefined' && (window as any).craft) {\n await callBridge('fs.writeFile', { path, content })\n return\n }\n const { writeFile } = await import('node:fs/promises')\n return writeFile(path, content, 'utf-8')\n },\n\n async readDir(path: string): Promise<string[]> {\n validatePath(path)\n // Defensive filter on `.` / `..` regardless of which transport\n // returns the listing. node:fs.readdir already excludes them, but\n // the legacy host bridge (`window.craft.fs.readDir`) is at the host\n // implementation's discretion — and many callers iterate the result\n // and stat each entry, where a stray `..` would silently let them\n // walk above the directory they thought they were enumerating.\n const filter = (xs: string[]) => xs.filter((n) => n !== '.' && n !== '..')\n const native = getCraftFs()\n if (native) return filter(await native.readDir(path))\n if (typeof window !== 'undefined' && (window as any).craft) {\n return filter(await callBridge<string[]>('fs.readDir', { path }))\n }\n const { readdir } = await import('node:fs/promises')\n return filter(await readdir(path))\n },\n\n async mkdir(path: string): Promise<void> {\n validatePath(path)\n const native = getCraftFs()\n if (native) return native.mkdir(path)\n if (typeof window !== 'undefined' && (window as any).craft) {\n await callBridge('fs.mkdir', { path })\n return\n }\n const { mkdir } = await import('node:fs/promises')\n await mkdir(path, { recursive: true })\n },\n\n async remove(path: string): Promise<void> {\n validatePath(path)\n const native = getCraftFs()\n if (native) return native.remove(path)\n if (typeof window !== 'undefined' && (window as any).craft) {\n await callBridge('fs.remove', { path })\n return\n }\n const { rm } = await import('node:fs/promises')\n return rm(path, { recursive: true, force: true })\n },\n\n async exists(path: string): Promise<boolean> {\n validatePath(path)\n const native = getCraftFs()\n if (native) return native.exists(path)\n if (typeof window !== 'undefined' && (window as any).craft) {\n return callBridge<boolean>('fs.exists', { path })\n }\n const { access } = await import('node:fs/promises')\n try {\n await access(path)\n return true\n }\n catch {\n return false\n }\n },\n}\n\n/**\n * Read file as binary data (Uint8Array).\n * Use this for non-text files like images, PDFs, or other binary formats.\n */\nexport async function readBinaryFile(path: string): Promise<Uint8Array> {\n validatePath(path)\n if (typeof window !== 'undefined' && (window as any).craft) {\n // Bridge response carries base64 — converts to Uint8Array on this side.\n // The previous shape `{ data: number[] }` ate ~5x the wire bytes per\n // byte and was JSON.stringify'd by the bridge envelope.\n const response = await callBridge<{ data: string }>('fs.readBinaryFile', { path })\n return base64ToUint8(response.data)\n }\n const { readFile } = await import('node:fs/promises')\n return readFile(path)\n}\n\n/**\n * Write binary data to a file.\n * Sends the bytes as base64 (with an `_binary: true` marker) so the wire\n * payload is ~33% overhead instead of the ~5x-10x overhead of JSON-encoded\n * `Array.from(uint8)`.\n */\nexport async function writeBinaryFile(path: string, data: Uint8Array): Promise<void> {\n validatePath(path)\n if (typeof window !== 'undefined' && (window as any).craft) {\n await callBridge('fs.writeBinaryFile', {\n path,\n _binary: true,\n data: uint8ToBase64(data),\n })\n return\n }\n const { writeFile } = await import('node:fs/promises')\n return writeFile(path, data)\n}\n\n/**\n * File statistics information.\n */\nexport interface FileStats {\n /** File size in bytes */\n size: number\n /** True if this is a regular file */\n isFile: boolean\n /** True if this is a directory */\n isDirectory: boolean\n /** Date when the file was last modified */\n modifiedAt: Date\n /** Date when the file was created */\n createdAt: Date\n}\n\n/**\n * Get file or directory statistics.\n */\nexport async function stat(path: string): Promise<FileStats> {\n validatePath(path)\n if (typeof window !== 'undefined' && (window as any).craft) {\n const response = await callBridge<{\n size: number\n isFile: boolean\n isDirectory: boolean\n modifiedAt: number\n createdAt: number\n }>('fs.stat', { path })\n return {\n size: response.size,\n isFile: response.isFile,\n isDirectory: response.isDirectory,\n modifiedAt: new Date(response.modifiedAt),\n createdAt: new Date(response.createdAt),\n }\n }\n const { stat: nodeStat } = await import('node:fs/promises')\n const stats = await nodeStat(path)\n return {\n size: stats.size,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n modifiedAt: stats.mtime,\n createdAt: stats.birthtime,\n }\n}\n\n/**\n * Copy a file or directory to a new location.\n */\nexport async function copy(src: string, dest: string): Promise<void> {\n validatePath(src)\n validatePath(dest)\n if (typeof window !== 'undefined' && (window as any).craft) {\n await callBridge('fs.copy', { src, dest })\n return\n }\n // Node.js fallback. dereference: false stops a symlink under `src` from\n // tricking cp into writing files outside `dest`. verbatimSymlinks: true\n // keeps the link itself intact instead of resolving it relative to `dest`.\n const { cp } = await import('node:fs/promises')\n return cp(src, dest, {\n recursive: true,\n dereference: false,\n verbatimSymlinks: true,\n })\n}\n\n/**\n * Move or rename a file or directory.\n */\nexport async function move(src: string, dest: string): Promise<void> {\n validatePath(src)\n validatePath(dest)\n if (typeof window !== 'undefined' && (window as any).craft) {\n await callBridge('fs.move', { src, dest })\n return\n }\n const { rename } = await import('node:fs/promises')\n return rename(src, dest)\n}\n\n/**\n * Watch options. `recursive` recurses into subdirectories — supported by\n * the Craft bridge always, by Node.js's `fs.watch` only on macOS/Windows.\n * Linux falls back to a non-recursive watch and logs a one-time warning.\n */\nexport interface WatchOptions {\n recursive?: boolean\n}\n\nlet _watchRecursiveWarned = false\n\n/**\n * Test-only: clear the once-per-process recursive-watch warning flag so\n * tests that exercise the warning path can do so deterministically.\n */\nexport function _resetWatchWarningForTests(): void {\n _watchRecursiveWarned = false\n}\n\n/**\n * Watch a file or directory for changes.\n *\n * Returns a Promise that resolves with an unwatch function once the watcher\n * is fully initialized.\n *\n * Important: the returned unwatch function MUST be called when the watcher\n * is no longer needed. Forgotten watchers leak both the underlying OS handle\n * and the JS-side event listener.\n */\nexport async function watch(\n path: string,\n callback: (event: string, filename: string) => void,\n options: WatchOptions = {},\n): Promise<() => void> {\n validatePath(path)\n const recursive = options.recursive ?? true\n\n if (typeof window !== 'undefined' && (window as any).craft) {\n const watchId = typeof globalThis.crypto !== 'undefined' && 'randomUUID' in globalThis.crypto\n ? (globalThis.crypto as Crypto).randomUUID()\n : `${Date.now()}_${performance.now()}`\n await callBridge('fs.watch', { path, watchId, recursive })\n\n const handler = (event: CustomEvent) => {\n if (event.detail.watchId === watchId) {\n callback(event.detail.eventType, event.detail.filename)\n }\n }\n window.addEventListener('craft:fs:watch' as any, handler)\n\n return () => {\n window.removeEventListener('craft:fs:watch' as any, handler)\n void callBridge('fs.unwatch', { watchId })\n }\n }\n\n const nodeFs = await import('node:fs')\n const platform = typeof process !== 'undefined' ? process.platform : ''\n // node:fs.watch supports `recursive` on darwin/win32; on linux it's\n // ignored. Surface a single warning so callers aren't surprised.\n if (recursive && platform === 'linux' && !_watchRecursiveWarned) {\n _watchRecursiveWarned = true\n console.warn(\n '[Craft fs.watch] recursive watching is not supported by node:fs.watch on linux; '\n + 'only direct children of the path will fire events. Use the Craft bridge for true recursion.',\n )\n }\n const watcher = nodeFs.watch(\n path,\n { recursive: recursive && platform !== 'linux' },\n (event: string, filename: string | null) => {\n if (filename) callback(event, filename)\n },\n )\n return () => watcher.close()\n}\n\nexport default fs\n",
|
|
19
|
+
"/**\n * @fileoverview Craft Database API\n * @description Provides SQLite database access through the Craft bridge.\n * Includes transaction support, table management, and a key-value store abstraction.\n * @module @craft-native/api/db\n *\n * @example\n * ```typescript\n * import { openDatabase, KeyValueStore } from '@craft-native/api/db'\n *\n * // Open a database\n * const myDb = await openDatabase('myapp.db')\n *\n * // Create a table\n * await myDb.createTable('users', [\n * { name: 'id', type: 'INTEGER', primaryKey: true, autoIncrement: true },\n * { name: 'name', type: 'TEXT', notNull: true },\n * { name: 'email', type: 'TEXT', unique: true }\n * ])\n *\n * // Insert data\n * await myDb.execute('INSERT INTO users (name, email) VALUES (?, ?)', ['John', 'john@example.com'])\n *\n * // Query data\n * const users = await myDb.query('SELECT * FROM users')\n * ```\n */\n\nimport { EventEmitter } from 'events'\nimport { getBridge } from '../bridge/core'\nimport type { CraftDatabaseAPI } from '../types'\n\n/**\n * Send a request through the unified `NativeBridge`. Replaces the legacy\n * `window.craft.bridge.call(...)` hook; everything routes through one\n * transport with consistent timeout/retry/error semantics.\n */\nasync function callBridge<T = unknown>(method: string, params?: unknown): Promise<T> {\n return getBridge().request<unknown, T>(method, params)\n}\n\n/**\n * Statements that mutate state. Read-only databases reject anything matching\n * this pattern at the start of a statement (after stripping leading\n * whitespace and `--` comments).\n */\nconst WRITE_STATEMENT_RE = /^\\s*(?:--[^\\n]*\\n\\s*)*(INSERT|UPDATE|DELETE|REPLACE|DROP|CREATE|ALTER|TRUNCATE|ATTACH|DETACH|VACUUM|REINDEX|PRAGMA)\\b/i\n\n/**\n * Global emitter for `db:execute` audit events. Subscribe to log every SQL\n * statement that goes through the SDK. The event payload is `{ name, sql,\n * paramsCount, readOnly }` — params themselves are not included by default\n * to avoid leaking secrets to logs.\n *\n * `setMaxListeners(0)` lifts the default 10-listener cap: analytics, the\n * dev overlay, and tests routinely subscribe in parallel and the cap\n * triggered spurious \"MaxListenersExceeded\" warnings without indicating\n * an actual leak.\n */\nexport const dbAudit: EventEmitter = new EventEmitter().setMaxListeners(0)\n\n/**\n * Maximum length for SQL identifiers (table/column names). SQLite has no\n * built-in cap but extremely long identifiers cause pathological query plans\n * and bloat sqlite_master rows; 64 is the limit used by MySQL and is plenty\n * for any sensible schema.\n */\nconst MAX_IDENTIFIER_LEN = 64\n\n/**\n * Validate a SQL identifier (table or column name) to prevent SQL injection\n * and runaway identifiers. Only allows alphanumeric characters and\n * underscores, with a length cap.\n *\n * @param name The identifier to validate.\n * @param kind Human-readable label for error messages (`'table'` /\n * `'column'` / `'index'` …). Defaults to `'identifier'`.\n */\nexport function validateIdentifier(name: string, kind: string = 'identifier'): void {\n if (typeof name !== 'string' || name.length === 0) {\n throw new Error(`Invalid ${kind} name: must be a non-empty string`)\n }\n if (name.length > MAX_IDENTIFIER_LEN) {\n throw new Error(`Invalid ${kind} name: \"${name.slice(0, 16)}…\" exceeds ${MAX_IDENTIFIER_LEN} characters`)\n }\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n throw new Error(`Invalid ${kind} name: \"${name}\". ${kind} names must contain only letters, numbers, and underscores.`)\n }\n}\n\n/**\n * Back-compat alias for {@link validateIdentifier} when validating a table\n * name. Existing call sites that say `validateTableName(...)` keep working.\n */\nexport function validateTableName(name: string): void {\n validateIdentifier(name, 'table')\n}\n\n/**\n * Encode a SQL literal for safe inclusion in a `DEFAULT` clause. Strings\n * have their single quotes doubled per the SQL standard. Numbers are\n * emitted verbatim (after `Number.isFinite` check). `null`/`undefined`\n * become `NULL`. Booleans become `0`/`1`. Anything else throws — DEFAULT\n * with a JSON object/array would silently misencode.\n */\nexport function encodeDefaultLiteral(value: unknown): string {\n if (value === null || value === undefined) return 'NULL'\n if (typeof value === 'boolean') return value ? '1' : '0'\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error(`Invalid DEFAULT: ${value} is not a finite number`)\n }\n return String(value)\n }\n if (typeof value === 'string') {\n return `'${value.replace(/'/g, '\\'\\'')}'`\n }\n throw new Error(`Invalid DEFAULT: ${typeof value} cannot be encoded as a SQL literal`)\n}\n\n/**\n * Low-level database API implementation.\n * Uses native SQLite through the Craft bridge.\n * For most use cases, prefer the {@link Database} class or {@link KeyValueStore}.\n *\n * @example\n * ```typescript\n * import { db } from '@craft-native/api/db'\n *\n * // Execute a statement\n * await db.execute('CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT)')\n *\n * // Query data\n * const results = await db.query('SELECT * FROM settings WHERE key = ?', ['theme'])\n * ```\n */\nexport const db: CraftDatabaseAPI = {\n /**\n * Execute a SQL statement that doesn't return data.\n * Use for INSERT, UPDATE, DELETE, CREATE TABLE, etc.\n *\n * @param sql - SQL statement to execute\n * @param params - Optional parameters for prepared statement\n * @returns Promise that resolves when execution is complete\n * @throws {Error} If not running in Craft environment or SQL error occurs\n *\n * @example\n * ```typescript\n * // Create table\n * await db.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)')\n *\n * // Insert with parameters (prevents SQL injection)\n * await db.execute('INSERT INTO users (name) VALUES (?)', ['John Doe'])\n *\n * // Update\n * await db.execute('UPDATE users SET name = ? WHERE id = ?', ['Jane', 1])\n * ```\n */\n async execute(sql: string, params?: unknown[]): Promise<void> {\n if (typeof window !== 'undefined' && window.craft?.db) {\n return window.craft.db.execute(sql, params)\n }\n throw new Error('Database API not available. Must run in Craft environment.')\n },\n\n /**\n * Execute a SQL query that returns data.\n * Use for SELECT statements.\n *\n * @param sql - SQL SELECT statement\n * @param params - Optional parameters for prepared statement\n * @returns Promise resolving to array of result rows\n * @throws {Error} If not running in Craft environment or SQL error occurs\n *\n * @example\n * ```typescript\n * // Simple query\n * const allUsers = await db.query('SELECT * FROM users')\n *\n * // Query with parameters\n * const user = await db.query('SELECT * FROM users WHERE id = ?', [1])\n *\n * // Query with multiple conditions\n * const results = await db.query(\n * 'SELECT * FROM products WHERE price > ? AND category = ?',\n * [10.00, 'electronics']\n * )\n * ```\n */\n async query(sql: string, params?: unknown[]): Promise<unknown[]> {\n if (typeof window !== 'undefined' && window.craft?.db) {\n return window.craft.db.query(sql, params)\n }\n throw new Error('Database API not available. Must run in Craft environment.')\n },\n\n /**\n * Begin a database transaction.\n * All subsequent operations until commit() or rollback() are part of the transaction.\n *\n * @returns Promise that resolves when transaction begins\n * @throws {Error} If not running in Craft environment\n *\n * @example\n * ```typescript\n * await db.beginTransaction()\n * try {\n * await db.execute('INSERT INTO orders (user_id, total) VALUES (?, ?)', [1, 99.99])\n * await db.execute('UPDATE inventory SET quantity = quantity - 1 WHERE product_id = ?', [42])\n * await db.commit()\n * }\ncatch (error) {\n * await db.rollback()\n * throw error\n * }\n * ```\n */\n async beginTransaction(): Promise<void> {\n if (typeof window !== 'undefined' && window.craft?.db) {\n return window.craft.db.beginTransaction()\n }\n throw new Error('Database API not available. Must run in Craft environment.')\n },\n\n /**\n * Commit the current transaction.\n * Makes all changes since beginTransaction() permanent.\n *\n * @returns Promise that resolves when transaction is committed\n * @throws {Error} If not running in Craft environment\n */\n async commit(): Promise<void> {\n if (typeof window !== 'undefined' && window.craft?.db) {\n return window.craft.db.commit()\n }\n throw new Error('Database API not available. Must run in Craft environment.')\n },\n\n /**\n * Rollback the current transaction.\n * Discards all changes since beginTransaction().\n *\n * @returns Promise that resolves when transaction is rolled back\n * @throws {Error} If not running in Craft environment\n */\n async rollback(): Promise<void> {\n if (typeof window !== 'undefined' && window.craft?.db) {\n return window.craft.db.rollback()\n }\n throw new Error('Database API not available. Must run in Craft environment.')\n }\n}\n\n/**\n * Create or open a SQLite database.\n *\n * @param name - Database name (will be stored as `{name}.sqlite` in app data directory)\n * @returns Promise resolving to Database instance\n *\n * @example\n * ```typescript\n * const myDb = await openDatabase('myapp')\n *\n * // Database will be created at app data directory as 'myapp.sqlite'\n * await myDb.createTable('notes', [\n * { name: 'id', type: 'INTEGER', primaryKey: true, autoIncrement: true },\n * { name: 'title', type: 'TEXT', notNull: true },\n * { name: 'content', type: 'TEXT' },\n * { name: 'created_at', type: 'INTEGER', default: Date.now() }\n * ])\n * ```\n */\nexport async function openDatabase(name: string): Promise<Database> {\n // Block directory traversal in database names\n const normalized = name.replace(/\\\\/g, '/')\n if (normalized.includes('/../') || normalized.startsWith('../') || normalized.endsWith('/..') || normalized === '..' || name.includes('\\0')) {\n throw new Error(`Invalid database name: \"${name}\" contains path traversal or invalid characters`)\n }\n return new Database(name)\n}\n\n/**\n * Open a database in read-only mode. `execute()` on the returned instance\n * rejects DDL/DML statements (`INSERT`, `UPDATE`, `DELETE`, `DROP`, etc.).\n * Use this for analytics / reporting code paths where there is no reason\n * for a SQL bug to be able to mutate state.\n */\nexport async function openDatabaseReadOnly(name: string): Promise<Database> {\n const normalized = name.replace(/\\\\/g, '/')\n if (normalized.includes('/../') || normalized.startsWith('../') || normalized.endsWith('/..') || normalized === '..' || name.includes('\\0')) {\n throw new Error(`Invalid database name: \"${name}\" contains path traversal or invalid characters`)\n }\n return new Database(name, { readOnly: true })\n}\n\n/**\n * SQLite database wrapper with extended functionality.\n * Provides table management, transactions, and query helpers.\n *\n * @example\n * ```typescript\n * const db = new Database('myapp')\n * await db.open()\n *\n * // Create table with schema\n * await db.createTable('tasks', [\n * { name: 'id', type: 'INTEGER', primaryKey: true, autoIncrement: true },\n * { name: 'title', type: 'TEXT', notNull: true },\n * { name: 'completed', type: 'INTEGER', default: 0 }\n * ])\n *\n * // Insert and get ID\n * const result = await db.execute('INSERT INTO tasks (title) VALUES (?)', ['Buy groceries'])\n * console.log('Created task with ID:', result.lastInsertId)\n *\n * // Query with type safety\n * interface Task { id: number; title: string; completed: number }\n * const tasks = await db.query<Task>('SELECT * FROM tasks')\n *\n * // Get single row\n * const task = await db.get<Task>('SELECT * FROM tasks WHERE id = ?', [1])\n *\n * // Transaction helper\n * await db.transaction(async () => {\n * await db.execute('UPDATE tasks SET completed = 1 WHERE id = ?', [1])\n * await db.execute('INSERT INTO activity_log (action) VALUES (?)', ['completed_task'])\n * })\n *\n * await db.close()\n * ```\n */\nexport class Database {\n private name: string\n private isOpen: boolean = false\n private readOnly: boolean\n /** True while a `db.transaction(...)` callback is on the stack. Set\n * before `BEGIN TRANSACTION` and cleared in the finally arm. Used to\n * make the inevitable mistake of calling `beginTransaction()` inside\n * `transaction()` (or vice versa) fail fast with a clear error. */\n private _inTransactionHelper: boolean = false\n\n /**\n * Create a new Database instance.\n *\n * @param name - Database name\n * @param options.readOnly - When true, `execute()` rejects DDL/DML\n * statements (anything that would mutate the schema or data).\n * `query()` is unaffected. Defaults to false.\n */\n constructor(name: string, options?: { readOnly?: boolean }) {\n this.name = name\n this.readOnly = options?.readOnly === true\n }\n\n /** Whether this Database refuses mutating statements. */\n isReadOnly(): boolean {\n return this.readOnly\n }\n\n /**\n * Open the database connection.\n * Called automatically on first query if not explicitly opened.\n *\n * @returns Promise that resolves when connection is established\n * @throws {Error} If not running in Craft environment\n */\n async open(): Promise<void> {\n if (typeof window !== 'undefined' && window.craft) {\n await callBridge('db.open', { name: this.name })\n this.isOpen = true\n return\n }\n throw new Error('Database API not available. Must run in Craft environment.')\n }\n\n /**\n * Close the database connection.\n * Should be called when done with the database to free resources.\n *\n * @returns Promise that resolves when connection is closed\n */\n async close(): Promise<void> {\n if (typeof window !== 'undefined' && window.craft) {\n await callBridge('db.close', { name: this.name })\n this.isOpen = false\n return\n }\n throw new Error('Database API not available. Must run in Craft environment.')\n }\n\n /**\n * Execute a SQL statement and get result metadata.\n *\n * @param sql - SQL statement to execute\n * @param params - Optional parameters for prepared statement\n * @returns Promise resolving to ExecuteResult with rowsAffected and lastInsertId\n *\n * @example\n * ```typescript\n * const result = await db.execute(\n * 'INSERT INTO users (name, email) VALUES (?, ?)',\n * ['John', 'john@example.com']\n * )\n * console.log(`Inserted user with ID: ${result.lastInsertId}`)\n * console.log(`Rows affected: ${result.rowsAffected}`)\n * ```\n */\n async execute(sql: string, params?: unknown[]): Promise<ExecuteResult> {\n if (!this.isOpen) {\n await this.open()\n }\n // Emit audit event before any check so subscribers see attempts even\n // when read-only mode rejects the statement. paramsCount is included\n // instead of params themselves to avoid logging secrets by default.\n dbAudit.emit('db:execute', {\n name: this.name,\n sql,\n paramsCount: params?.length ?? 0,\n readOnly: this.readOnly,\n })\n if (this.readOnly && WRITE_STATEMENT_RE.test(sql)) {\n throw new Error(\n `Database \"${this.name}\" is read-only; rejected mutating statement: ${sql.slice(0, 64)}`,\n )\n }\n if (typeof window !== 'undefined' && window.craft) {\n const result = await callBridge<{ rowsAffected: number; lastInsertId: number }>(\n 'db.execute',\n { name: this.name, sql, params: params || [] },\n )\n return {\n rowsAffected: result.rowsAffected,\n lastInsertId: result.lastInsertId,\n }\n }\n throw new Error('Database API not available. Must run in Craft environment.')\n }\n\n /**\n * Execute a query and return all matching rows.\n *\n * @typeParam T - Type of result rows\n * @param sql - SQL SELECT statement\n * @param params - Optional parameters for prepared statement\n * @returns Promise resolving to array of typed results\n *\n * @example\n * ```typescript\n * interface User {\n * id: number\n * name: string\n * email: string\n * }\n *\n * const users = await db.query<User>('SELECT * FROM users WHERE active = ?', [1])\n * users.forEach(user => console.log(user.name))\n * ```\n */\n async query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]> {\n if (!this.isOpen) {\n await this.open()\n }\n if (typeof window !== 'undefined' && window.craft) {\n return callBridge<T[]>('db.query', {\n name: this.name,\n sql,\n params: params || [],\n })\n }\n throw new Error('Database API not available. Must run in Craft environment.')\n }\n\n /**\n * Execute a query and return the first matching row.\n *\n * @typeParam T - Type of result row\n * @param sql - SQL SELECT statement\n * @param params - Optional parameters for prepared statement\n * @returns Promise resolving to first row or null if no matches\n *\n * @example\n * ```typescript\n * const user = await db.get<User>('SELECT * FROM users WHERE id = ?', [1])\n * if (user) {\n * console.log(`Found user: ${user.name}`)\n * }\nelse {\n * console.log('User not found')\n * }\n * ```\n */\n async get<T = unknown>(sql: string, params?: unknown[]): Promise<T | null> {\n const rows = await this.query<T>(sql, params)\n return rows.length > 0 ? rows[0] : null\n }\n\n /**\n * Execute a function within a transaction.\n * Automatically commits on success, rolls back on error.\n *\n * NOTE: this method drives the transaction by emitting raw SQL\n * (`BEGIN TRANSACTION` / `COMMIT` / `ROLLBACK`). The connection-level\n * helpers `db.beginTransaction()` / `db.commit()` / `db.rollback()` use\n * a separate native handler. Don't mix the two on the same connection —\n * pick one style per code path. See `docs/db-transactions.md`.\n *\n * @typeParam T - Return type of transaction function\n * @param fn - Async function containing database operations\n * @returns Promise resolving to function's return value\n * @throws Re-throws any error after rolling back\n *\n * @example\n * ```typescript\n * const orderId = await db.transaction(async () => {\n * const orderResult = await db.execute(\n * 'INSERT INTO orders (user_id, total) VALUES (?, ?)',\n * [userId, total]\n * )\n *\n * for (const item of items) {\n * await db.execute(\n * 'INSERT INTO order_items (order_id, product_id, quantity) VALUES (?, ?, ?)',\n * [orderResult.lastInsertId, item.productId, item.quantity]\n * )\n * }\n *\n * return orderResult.lastInsertId\n * })\n * ```\n */\n async transaction<T>(fn: () => Promise<T>): Promise<T> {\n if (this._inTransactionHelper) {\n throw new Error(\n '[Craft DB] transaction() is already active on this connection. '\n + 'Nested transactions are not supported — refactor inner code to take '\n + 'an existing handle, or use SAVEPOINT directly.',\n )\n }\n this._inTransactionHelper = true\n try {\n await this.execute('BEGIN TRANSACTION')\n try {\n const result = await fn()\n await this.execute('COMMIT')\n return result\n }\n catch (error) {\n // Try to roll back. If ROLLBACK itself fails (locked DB, native side\n // dead, etc.) we can't surface BOTH errors as the thrown value, but\n // dropping the rollback failure used to mask the real situation: the\n // connection is left in a transactional state and the original error\n // gives no hint why. Attach the rollback error as `.cause` so debug\n // tooling sees both, log the secondary so it shows up in console\n // output even if the consumer doesn't inspect causes.\n try {\n await this.execute('ROLLBACK')\n }\n catch (rollbackError) {\n console.error('[Craft DB] ROLLBACK failed after transaction error:', rollbackError)\n if (error instanceof Error) {\n ;(error as { cause?: unknown }).cause = rollbackError\n }\n }\n throw error\n }\n }\n finally {\n this._inTransactionHelper = false\n }\n }\n\n /**\n * Create a table with the specified schema.\n * Uses CREATE TABLE IF NOT EXISTS, so safe to call multiple times.\n *\n * @param tableName - Name of the table to create\n * @param columns - Array of column definitions\n *\n * @example\n * ```typescript\n * await db.createTable('products', [\n * { name: 'id', type: 'INTEGER', primaryKey: true, autoIncrement: true },\n * { name: 'name', type: 'TEXT', notNull: true },\n * { name: 'price', type: 'REAL', notNull: true },\n * { name: 'category', type: 'TEXT' },\n * { name: 'in_stock', type: 'INTEGER', default: 1 }\n * ])\n * ```\n */\n async createTable(tableName: string, columns: TableColumn[]): Promise<void> {\n validateIdentifier(tableName, 'table')\n const columnDefs = columns.map(col => {\n validateIdentifier(col.name, 'column')\n let def = `${col.name} ${col.type}`\n if (col.primaryKey) def += ' PRIMARY KEY'\n if (col.autoIncrement) def += ' AUTOINCREMENT'\n if (col.notNull) def += ' NOT NULL'\n if (col.unique) def += ' UNIQUE'\n if (col.default !== undefined) {\n // encodeDefaultLiteral doubles `'` for strings, ensures finite\n // numbers, encodes booleans/null safely. Without this a default\n // like `O'Brien` produced malformed and injection-prone SQL.\n def += ` DEFAULT ${encodeDefaultLiteral(col.default)}`\n }\n return def\n })\n\n const sql = `CREATE TABLE IF NOT EXISTS ${tableName} (${columnDefs.join(', ')})`\n await this.execute(sql)\n }\n\n /**\n * Drop a table if it exists.\n *\n * @param tableName - Name of the table to drop\n */\n async dropTable(tableName: string): Promise<void> {\n validateIdentifier(tableName, 'table')\n await this.execute(`DROP TABLE IF EXISTS ${tableName}`)\n }\n\n /**\n * Check if a table exists in the database.\n *\n * @param tableName - Name of the table to check\n * @returns Promise resolving to true if table exists\n */\n async tableExists(tableName: string): Promise<boolean> {\n validateIdentifier(tableName, 'table')\n const result = await this.query<{ name: string }>(\n `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,\n [tableName]\n )\n return result.length > 0\n }\n}\n\n/**\n * Result of an execute operation.\n */\nexport interface ExecuteResult {\n /** Number of rows affected by the operation */\n rowsAffected: number\n /** ID of the last inserted row (for INSERT operations) */\n lastInsertId: number\n}\n\n/**\n * Column definition for createTable.\n */\nexport interface TableColumn {\n /** Column name */\n name: string\n /** SQLite data type */\n type: 'TEXT' | 'INTEGER' | 'REAL' | 'BLOB' | 'NULL'\n /** Mark as primary key */\n primaryKey?: boolean\n /** Enable auto-increment (INTEGER PRIMARY KEY only) */\n autoIncrement?: boolean\n /** Disallow NULL values */\n notNull?: boolean\n /** Require unique values */\n unique?: boolean\n /** Default value for column */\n default?: unknown\n}\n\n/**\n * Simple key-value store backed by SQLite.\n * Useful for settings, preferences, and cached data.\n *\n * @example\n * ```typescript\n * const db = await openDatabase('settings')\n * const store = new KeyValueStore(db)\n * await store.init()\n *\n * // Store values (automatically JSON serialized)\n * await store.set('theme', 'dark')\n * await store.set('user', { name: 'John', premium: true })\n * await store.set('recentFiles', ['/doc1.txt', '/doc2.txt'])\n *\n * // Retrieve values\n * const theme = await store.get<string>('theme') // 'dark'\n * const user = await store.get<{ name: string; premium: boolean }>('user')\n *\n * // Check existence\n * if (await store.has('lastSync')) {\n * const lastSync = await store.get<number>('lastSync')\n * }\n *\n * // List all keys\n * const allKeys = await store.keys()\n *\n * // Delete and clear\n * await store.delete('tempData')\n * await store.clear() // Remove all entries\n * ```\n */\nexport class KeyValueStore {\n private db: Database\n private tableName: string\n\n /**\n * Create a new KeyValueStore.\n *\n * @param db - Database instance to use\n * @param tableName - Table name for storage (default: 'kv_store')\n */\n constructor(db: Database, tableName: string = 'kv_store') {\n this.db = db\n this.tableName = tableName\n }\n\n /**\n * Initialize the key-value store table.\n * Must be called before using other methods.\n */\n async init(): Promise<void> {\n await this.db.createTable(this.tableName, [\n { name: 'key', type: 'TEXT', primaryKey: true },\n { name: 'value', type: 'TEXT' },\n { name: 'updated_at', type: 'INTEGER' }\n ])\n }\n\n /**\n * Get a value by key.\n * Returns null if key doesn't exist.\n *\n * @typeParam T - Expected type of the value\n * @param key - Key to retrieve\n * @returns Promise resolving to value or null\n */\n async get<T = unknown>(key: string): Promise<T | null> {\n const row = await this.db.get<{ value: string }>(\n `SELECT value FROM ${this.tableName} WHERE key = ?`,\n [key]\n )\n if (row) {\n try {\n return JSON.parse(row.value) as T\n }\ncatch (err) {\n console.debug('[Craft DB] Failed to parse stored value for key, returning raw:', err)\n return row.value as unknown as T\n }\n }\n return null\n }\n\n /**\n * Set a value for a key.\n * Creates new entry or updates existing one.\n * Values are automatically JSON serialized.\n *\n * @param key - Key to set\n * @param value - Value to store (will be JSON serialized)\n */\n async set(key: string, value: unknown): Promise<void> {\n const serialized = JSON.stringify(value)\n await this.db.execute(\n `INSERT OR REPLACE INTO ${this.tableName} (key, value, updated_at) VALUES (?, ?, ?)`,\n [key, serialized, Date.now()]\n )\n }\n\n /**\n * Delete a key from the store.\n *\n * @param key - Key to delete\n */\n async delete(key: string): Promise<void> {\n await this.db.execute(`DELETE FROM ${this.tableName} WHERE key = ?`, [key])\n }\n\n /**\n * Check if a key exists.\n *\n * @param key - Key to check\n * @returns Promise resolving to true if key exists\n */\n async has(key: string): Promise<boolean> {\n const row = await this.db.get<{ key: string }>(\n `SELECT key FROM ${this.tableName} WHERE key = ?`,\n [key]\n )\n return row !== null\n }\n\n /**\n * Get all keys in the store.\n *\n * @returns Promise resolving to array of keys\n */\n async keys(): Promise<string[]> {\n const rows = await this.db.query<{ key: string }>(\n `SELECT key FROM ${this.tableName}`\n )\n return rows.map(r => r.key)\n }\n\n /**\n * Clear all entries from the store.\n */\n async clear(): Promise<void> {\n await this.db.execute(`DELETE FROM ${this.tableName}`)\n }\n}\n\nexport default db\n",
|
|
20
|
+
"/**\n * Craft HTTP Client API\n * Provides native HTTP client through the Craft bridge\n * Bypasses CORS restrictions when running in Craft\n */\n\nimport type { CraftHttpAPI } from '../types'\n\n/**\n * Result of {@link encodeRequestBody}. `kind` lets the caller decide\n * whether to default a `Content-Type: application/json` header.\n */\ntype EncodedBody =\n | { kind: 'none'; value: undefined }\n | { kind: 'string'; value: string }\n | { kind: 'binary'; value: BodyInit }\n | { kind: 'form'; value: BodyInit }\n | { kind: 'json'; value: string }\n\n/**\n * Translate a user-supplied body into something `fetch()` knows how to\n * send, without losing fidelity. The previous implementation collapsed\n * everything object-shaped through `JSON.stringify`, which produced\n * `\"[object FormData]\"` for FormData/URLSearchParams/Blob/Uint8Array.\n *\n * The mapping:\n * - `undefined` / `null` → `{ kind: 'none' }`\n * - `string` → `{ kind: 'string' }` (no auto C-T)\n * - `ArrayBuffer` / TypedArray → `{ kind: 'binary' }`\n * - `Blob` / `File` → `{ kind: 'binary' }` (preserves type)\n * - `FormData` → `{ kind: 'form' }` (browser sets boundary)\n * - `URLSearchParams` → `{ kind: 'form' }` (forces x-www-form-urlencoded)\n * - `ReadableStream` → `{ kind: 'binary' }`\n * - everything else → JSON.stringify\n */\nexport function encodeRequestBody(body: unknown): EncodedBody {\n if (body === undefined || body === null) return { kind: 'none', value: undefined }\n if (typeof body === 'string') return { kind: 'string', value: body }\n // Binary-ish types pass through unchanged.\n if (body instanceof ArrayBuffer) return { kind: 'binary', value: body }\n if (ArrayBuffer.isView(body)) return { kind: 'binary', value: body as ArrayBufferView as BodyInit }\n if (typeof Blob !== 'undefined' && body instanceof Blob) {\n return { kind: 'binary', value: body }\n }\n if (typeof FormData !== 'undefined' && body instanceof FormData) {\n return { kind: 'form', value: body }\n }\n if (typeof URLSearchParams !== 'undefined' && body instanceof URLSearchParams) {\n return { kind: 'form', value: body }\n }\n if (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) {\n return { kind: 'binary', value: body as unknown as BodyInit }\n }\n // Node's `fetch` (undici) accepts AsyncIterable<Uint8Array> as a body\n // for streaming uploads. Detecting Symbol.asyncIterator covers both\n // user generators and `Readable.toWeb()` outputs without misrouting\n // them through JSON. Browsers will still reject AsyncIterable bodies\n // at the fetch layer, where the error is the runtime's to surface.\n if (\n body !== null\n && typeof body === 'object'\n && (body as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] !== undefined\n ) {\n return { kind: 'binary', value: body as unknown as BodyInit }\n }\n // Plain object / array → JSON.\n return { kind: 'json', value: JSON.stringify(body) }\n}\n\n/**\n * Case-insensitive lookup against an HTTP header object. Returns true when\n * any key with the same lowercased name is present. Does NOT use the\n * `Headers` global directly because callers pass plain objects.\n */\nexport function hasHeader(headers: Record<string, string>, name: string): boolean {\n const want = name.toLowerCase()\n for (const k of Object.keys(headers)) {\n if (k.toLowerCase() === want) return true\n }\n return false\n}\n\n/**\n * HTTP API implementation\n * Uses native HTTP client through the Craft bridge\n */\nexport const http: CraftHttpAPI = {\n /**\n * Fetch resource (CORS-free in Craft environment)\n */\n async fetch(url: string, options?: RequestInit): Promise<Response> {\n if (typeof window !== 'undefined' && window.craft?.http) {\n return window.craft.http.fetch(url, options)\n }\n // Browser/Node fallback\n return globalThis.fetch(url, options)\n },\n\n /**\n * Download file with progress tracking. The progress callback is detached\n * (replaced with a no-op) once the underlying bridge promise settles, so\n * a lingering native reference doesn't pin caller closures forever.\n */\n async download(\n url: string,\n destination: string,\n onProgress?: (progress: { loaded: number; total: number }) => void\n ): Promise<void> {\n if (typeof window !== 'undefined' && window.craft?.http) {\n let active: typeof onProgress = onProgress\n const wrapper = onProgress\n ? (p: { loaded: number; total: number }) => active?.(p)\n : undefined\n try {\n return await window.craft.http.download(url, destination, wrapper)\n }\n finally {\n active = undefined // detach\n }\n }\n throw new Error('Download API requires Craft environment')\n },\n\n /**\n * Upload file with progress tracking. See `download` for the\n * callback-detachment contract.\n */\n async upload(\n url: string,\n filePath: string,\n onProgress?: (progress: { loaded: number; total: number }) => void\n ): Promise<Response> {\n if (typeof window !== 'undefined' && window.craft?.http) {\n let active: typeof onProgress = onProgress\n const wrapper = onProgress\n ? (p: { loaded: number; total: number }) => active?.(p)\n : undefined\n try {\n return await window.craft.http.upload(url, filePath, wrapper)\n }\n finally {\n active = undefined\n }\n }\n throw new Error('Upload API requires Craft environment')\n }\n}\n\n/**\n * Extended HTTP client with additional features\n */\nexport class HttpClient {\n private baseUrl: string\n private defaultHeaders: Record<string, string>\n private timeout: number\n\n constructor(options: HttpClientOptions = {}) {\n this.baseUrl = options.baseUrl || ''\n this.defaultHeaders = options.headers || {}\n this.timeout = options.timeout || 30000\n }\n\n /**\n * Make GET request\n */\n async get<T = unknown>(path: string, options?: RequestOptions): Promise<HttpResponse<T>> {\n return this.request<T>('GET', path, options)\n }\n\n /**\n * Make POST request\n */\n async post<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<HttpResponse<T>> {\n return this.request<T>('POST', path, { ...options, body })\n }\n\n /**\n * Make PUT request\n */\n async put<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<HttpResponse<T>> {\n return this.request<T>('PUT', path, { ...options, body })\n }\n\n /**\n * Make PATCH request\n */\n async patch<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<HttpResponse<T>> {\n return this.request<T>('PATCH', path, { ...options, body })\n }\n\n /**\n * Make DELETE request\n */\n async delete<T = unknown>(path: string, options?: RequestOptions): Promise<HttpResponse<T>> {\n return this.request<T>('DELETE', path, options)\n }\n\n /**\n * Make HEAD request\n */\n async head(path: string, options?: RequestOptions): Promise<HttpResponse<void>> {\n return this.request<void>('HEAD', path, options)\n }\n\n /**\n * General request method\n */\n private async request<T>(\n method: string,\n path: string,\n options: RequestOptions = {}\n ): Promise<HttpResponse<T>> {\n const url = this.buildUrl(path, options.params)\n const headers = { ...this.defaultHeaders, ...options.headers }\n\n // Encode the body once and only set Content-Type for JSON bodies that\n // didn't already have one. The previous version used a case-sensitive\n // `'Content-Type' in headers` check (so a caller-supplied\n // `'content-type'` was missed and a duplicate header appeared) and\n // JSON.stringify'd anything object-shaped — silently turning\n // FormData/URLSearchParams/Uint8Array/Blob into useless\n // `\"[object Foo]\"` strings.\n const encoded = encodeRequestBody(options.body)\n if (encoded.kind === 'json' && !hasHeader(headers, 'content-type')) {\n headers['Content-Type'] = 'application/json'\n }\n\n const effectiveTimeout = options.timeout || this.timeout\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout)\n\n try {\n // Forward the timeout to the native bridge as well — when the request\n // is dispatched through the Craft host, the host has no signal-aware\n // way to short-circuit a hung socket unless we tell it the deadline.\n // The custom `timeoutMs` property is ignored by browsers and\n // `globalThis.fetch` (it's not part of the WHATWG Fetch RequestInit\n // type), so this is purely a Craft-host hint and a no-op everywhere\n // else — no polyfill, no behavior change for non-Craft consumers.\n const response = await http.fetch(url, {\n method,\n headers,\n body: encoded.value as BodyInit | undefined,\n signal: controller.signal,\n ...(typeof options.timeout === 'number' || typeof this.timeout === 'number'\n ? { timeoutMs: effectiveTimeout } as { timeoutMs: number }\n : {}),\n } as RequestInit & { timeoutMs?: number })\n\n // Parse response. The previous version left `data` undefined for\n // anything that wasn't JSON or text/* and then returned `data as T`,\n // which lied to the type system: an image response would have\n // `data: undefined` typed as `T`. We now branch on Content-Type so\n // every code path produces a defined value (or null when the body\n // is genuinely empty).\n let data: T | null\n const contentType = response.headers.get('content-type') ?? ''\n\n if (contentType.includes('application/json')) {\n try {\n data = await response.json() as T\n }\n catch {\n // Response body was not valid JSON despite content-type header\n data = (await response.text()) as unknown as T\n }\n }\n else if (contentType.startsWith('text/')) {\n data = (await response.text()) as unknown as T\n }\n else if (\n contentType.includes('octet-stream')\n || contentType.startsWith('image/')\n || contentType.startsWith('audio/')\n || contentType.startsWith('video/')\n || contentType.startsWith('application/')\n ) {\n // Binary — return ArrayBuffer; callers that need a Blob/Uint8Array\n // can wrap. The cast is honest: we genuinely produced bytes.\n data = (await response.arrayBuffer()) as unknown as T\n }\n else if (response.body === null) {\n data = null\n }\n else {\n // Unknown / missing Content-Type. Default to text rather than\n // silently producing `undefined`.\n data = (await response.text()) as unknown as T\n }\n\n return {\n data: data as T,\n status: response.status,\n statusText: response.statusText,\n headers: Object.fromEntries(response.headers.entries()),\n ok: response.ok,\n }\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new HttpError('Request timeout', 0, 'TIMEOUT')\n }\n throw error\n }\n finally {\n // Always clear the timer, even when fetch throws synchronously (e.g.\n // body-stringify failure). The previous implementation cleared it in\n // both branches of try/catch and missed the synchronous-throw path.\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Build URL with query parameters\n */\n private buildUrl(path: string, params?: Record<string, string | number | boolean>): string {\n let url = path.startsWith('http') ? path : `${this.baseUrl}${path}`\n\n if (params) {\n const searchParams = new URLSearchParams()\n for (const [key, value] of Object.entries(params)) {\n searchParams.append(key, String(value))\n }\n const query = searchParams.toString()\n if (query) {\n url += (url.includes('?') ? '&' : '?') + query\n }\n }\n\n return url\n }\n\n /**\n * Set default header\n */\n setHeader(key: string, value: string): void {\n this.defaultHeaders[key] = value\n }\n\n /**\n * Remove default header\n */\n removeHeader(key: string): void {\n delete this.defaultHeaders[key]\n }\n\n /**\n * Set bearer token\n */\n setBearerToken(token: string): void {\n this.setHeader('Authorization', `Bearer ${token}`)\n }\n}\n\n/**\n * HTTP client options\n */\nexport interface HttpClientOptions {\n baseUrl?: string\n headers?: Record<string, string>\n timeout?: number\n}\n\n/**\n * Request options\n */\nexport interface RequestOptions {\n headers?: Record<string, string>\n params?: Record<string, string | number | boolean>\n body?: unknown\n timeout?: number\n}\n\n/**\n * HTTP response\n */\nexport interface HttpResponse<T> {\n data: T\n status: number\n statusText: string\n headers: Record<string, string>\n ok: boolean\n}\n\n/**\n * HTTP error class\n */\nexport class HttpError extends Error {\n status: number\n code: string\n\n constructor(message: string, status: number, code: string = 'HTTP_ERROR') {\n super(message)\n this.name = 'HttpError'\n this.status = status\n this.code = code\n }\n}\n\n/**\n * WebSocket client wrapper\n */\nexport class WebSocketClient {\n private ws: WebSocket | null = null\n private url: string\n private reconnectAttempts: number = 0\n private maxReconnectAttempts: number\n private reconnectDelay: number\n private handlers: Map<string, Set<(data: unknown) => void>> = new Map()\n private messageHandler: ((_event: MessageEvent) => void) | null = null\n\n constructor(url: string, options: WebSocketOptions = {}) {\n this.url = url\n this.maxReconnectAttempts = options.maxReconnectAttempts || 5\n this.reconnectDelay = options.reconnectDelay || 1000\n }\n\n /**\n * Connect to WebSocket server\n */\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.ws = new WebSocket(this.url)\n\n this.ws.onopen = () => {\n this.reconnectAttempts = 0\n resolve()\n }\n\n this.ws.onerror = (_event) => {\n reject(new Error('WebSocket connection failed'))\n }\n\n this.ws.onclose = () => {\n this.attemptReconnect()\n }\n\n this.messageHandler = (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data)\n const type = data.type || 'message'\n const handlers = this.handlers.get(type)\n if (handlers) {\n handlers.forEach(handler => handler(data.payload || data))\n }\n }\ncatch {\n // Handle non-JSON messages\n const handlers = this.handlers.get('message')\n if (handlers) {\n handlers.forEach(handler => handler(event.data))\n }\n }\n }\n\n this.ws.onmessage = this.messageHandler\n })\n }\n\n /**\n * Disconnect from WebSocket server\n */\n disconnect(): void {\n this.maxReconnectAttempts = 0 // Prevent reconnect on intentional disconnect\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n }\n\n /**\n * Send message\n */\n send(type: string, payload?: unknown): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not connected')\n }\n this.ws.send(JSON.stringify({ type, payload }))\n }\n\n /**\n * Send raw data\n */\n sendRaw(data: string | ArrayBuffer): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not connected')\n }\n this.ws.send(data)\n }\n\n /**\n * Subscribe to message type\n */\n on(type: string, handler: (data: unknown) => void): () => void {\n if (!this.handlers.has(type)) {\n this.handlers.set(type, new Set())\n }\n this.handlers.get(type)!.add(handler)\n\n return () => {\n this.handlers.get(type)?.delete(handler)\n }\n }\n\n /**\n * Attempt to reconnect\n */\n private attemptReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n return\n }\n\n this.reconnectAttempts++\n const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1)\n\n setTimeout(() => {\n this.connect().catch(() => {\n // Reconnection failed, will try again\n })\n }, delay)\n }\n\n /**\n * Check if connected\n */\n get connected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN\n }\n}\n\n/**\n * WebSocket options\n */\nexport interface WebSocketOptions {\n maxReconnectAttempts?: number\n reconnectDelay?: number\n}\n\n/**\n * Create a pre-configured HTTP client\n */\nexport function createClient(options?: HttpClientOptions): HttpClient {\n return new HttpClient(options)\n}\n\nexport default http\n",
|
|
21
|
+
"/**\n * Craft Crypto API\n * Provides cryptographic operations through the Craft bridge\n */\n\nimport type { CraftCryptoAPI } from '../types'\n\n/**\n * Error type for cryptographic failures (malformed input, decode errors, etc.).\n *\n * Pre-ES2022 runtimes don't support the `Error(message, { cause })`\n * overload — `super(message, options)` ignores `options.cause` and the\n * `.cause` property never gets attached. We assign it manually after\n * super() so callers can rely on `error.cause` regardless of the host.\n */\nexport class CraftCryptoError extends Error {\n override readonly name: string = 'CraftCryptoError'\n override cause?: unknown\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n if (options && 'cause' in options) {\n this.cause = options.cause\n }\n }\n}\n\n/**\n * Thrown when {@link crypto.decrypt} is given a ciphertext produced by the\n * pre-versioning format (no salt prefix). Apps that persisted secrets with\n * older Craft versions should catch this and re-encrypt the cleartext with\n * the current API.\n */\nexport class LegacyCiphertextError extends CraftCryptoError {\n override readonly name: string = 'LegacyCiphertextError'\n constructor() {\n super(\n 'Ciphertext was produced by a pre-versioning Craft crypto release. '\n + 'Re-encrypt the value with the current API to migrate to the v1 wire format.',\n )\n }\n}\n\n// Wire format (post-migration):\n//\n// [version(1) | salt(16) | iv(12) | ciphertext + auth-tag(16)]\n//\n// The leading version byte lets us detect older payloads and refuse them\n// loudly instead of silently failing AES-GCM decryption deep in the crypto\n// stack. v1 is the salt-prefixed layout from late 2025; legacy payloads\n// have no version byte and aren't decryptable with the same code path.\n//\n// The KDF is PBKDF2-SHA256 in BOTH the WebCrypto and Node fallbacks so\n// ciphertext is portable across runtimes — the previous implementation\n// used scrypt in Node and PBKDF2 in the browser, which produced different\n// keys for the same password and made the ciphertext non-portable.\nconst FORMAT_VERSION = 0x01\nconst SALT_LEN = 16\nconst IV_LEN = 12\nconst TAG_LEN = 16\n/**\n * PBKDF2-SHA256 iteration count for the AES-256-GCM data-encryption key.\n * Bumped from 100k → 600k to align with OWASP's 2023+ guidance for\n * password-stretching with PBKDF2-SHA256.\n */\nconst PBKDF2_ITERATIONS = 600_000\n\n/**\n * Crypto API implementation\n * Uses native crypto through the Craft bridge\n */\nexport const crypto: CraftCryptoAPI = {\n /**\n * Generate cryptographically secure random bytes\n */\n async randomBytes(size: number): Promise<Uint8Array> {\n if (typeof window !== 'undefined' && window.craft?.crypto) {\n return window.craft.crypto.randomBytes(size)\n }\n // Web Crypto API fallback. WebCrypto caps `getRandomValues` at 64KiB\n // per call, so chunk for large requests.\n if (typeof globalThis.crypto !== 'undefined' && typeof globalThis.crypto.getRandomValues === 'function') {\n const out = new Uint8Array(size)\n const chunk = 65_536\n for (let i = 0; i < size; i += chunk) {\n const view = out.subarray(i, Math.min(i + chunk, size))\n globalThis.crypto.getRandomValues(view)\n }\n return out\n }\n // Node.js fallback\n const { randomBytes } = await import('node:crypto')\n return new Uint8Array(randomBytes(size))\n },\n\n /**\n * Hash data using specified algorithm.\n *\n * MD5 is supported only in Node — WebCrypto does not implement it. In a\n * browser-like context (`globalThis.crypto.subtle` available, no\n * `process` global) we throw a clear error rather than letting the\n * caller fall through to a `node:crypto` import that crashes the page.\n */\n async hash(algorithm: 'sha256' | 'sha512' | 'md5', data: string): Promise<string> {\n if (typeof window !== 'undefined' && window.craft?.crypto) {\n return window.craft.crypto.hash(algorithm, data)\n }\n if (algorithm === 'md5') {\n // MD5 is reachable only through Node. Detect Node by feature\n // sniffing rather than `typeof process` (Bun and some bundlers\n // expose `process` in browser bundles).\n const hasNodeCrypto = typeof process !== 'undefined' && (process as { versions?: { node?: string } }).versions?.node\n if (!hasNodeCrypto) {\n throw new CraftCryptoError(\n 'MD5 is not available in this runtime — WebCrypto does not implement it. '\n + 'Use sha256/sha512, or call this from Node.',\n )\n }\n const { createHash } = await import('node:crypto')\n return createHash('md5').update(data).digest('hex')\n }\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n const encoder = new TextEncoder()\n const dataBuffer = encoder.encode(data)\n const hashBuffer = await globalThis.crypto.subtle.digest(\n algorithm === 'sha256' ? 'SHA-256' : 'SHA-512',\n dataBuffer,\n )\n return bufferToHex(hashBuffer)\n }\n const { createHash } = await import('node:crypto')\n return createHash(algorithm).update(data).digest('hex')\n },\n\n /**\n * Encrypt data with AES-256-GCM. Wire format:\n * `[version(1) | salt(16) | iv(12) | ciphertext+tag]`\n *\n * The KDF is PBKDF2-SHA256 in both runtimes, so ciphertext produced in\n * the browser decrypts in Node and vice versa.\n */\n async encrypt(data: string, key: string): Promise<string> {\n if (typeof window !== 'undefined' && window.craft?.crypto) {\n return window.craft.crypto.encrypt(data, key)\n }\n const salt = await crypto.randomBytes(SALT_LEN)\n const iv = await crypto.randomBytes(IV_LEN)\n const aesKey = await derivePbkdf2Key(key, salt)\n const ciphertext = await aesGcmEncrypt(aesKey, iv, new TextEncoder().encode(data))\n\n const combined = new Uint8Array(1 + salt.length + iv.length + ciphertext.length)\n combined[0] = FORMAT_VERSION\n combined.set(salt, 1)\n combined.set(iv, 1 + salt.length)\n combined.set(ciphertext, 1 + salt.length + iv.length)\n return bufferToBase64(combined.buffer)\n },\n\n /**\n * Decrypt data with AES-256-GCM. Mirrors the wire format used by\n * {@link crypto.encrypt}.\n */\n async decrypt(encryptedData: string, key: string): Promise<string> {\n if (typeof window !== 'undefined' && window.craft?.crypto) {\n return window.craft.crypto.decrypt(encryptedData, key)\n }\n const combined = base64ToBuffer(encryptedData)\n if (combined.length < 1 + SALT_LEN + IV_LEN + TAG_LEN) {\n throw new CraftCryptoError('Ciphertext too short to be valid')\n }\n const version = combined[0]\n if (version !== FORMAT_VERSION) {\n throw new LegacyCiphertextError()\n }\n const salt = combined.slice(1, 1 + SALT_LEN)\n const iv = combined.slice(1 + SALT_LEN, 1 + SALT_LEN + IV_LEN)\n const data = combined.slice(1 + SALT_LEN + IV_LEN)\n\n const aesKey = await derivePbkdf2Key(key, salt)\n try {\n const plaintext = await aesGcmDecrypt(aesKey, iv, data)\n return new TextDecoder().decode(plaintext)\n }\n catch (e) {\n throw new CraftCryptoError('Decryption failed (wrong key or corrupted data)', { cause: e })\n }\n },\n}\n\n/**\n * Convert a Uint8Array into a BufferSource that satisfies WebCrypto's\n * stricter `ArrayBufferView<ArrayBuffer>` type. The runtime value is the\n * same; the cast is purely to keep TypeScript happy in projects that\n * pin `lib: [\"DOM\"]` to the post-resizable-buffers definitions.\n */\nfunction asBufferSource(bytes: Uint8Array): BufferSource {\n return bytes as unknown as BufferSource\n}\n\n/**\n * Derive a 32-byte AES key from a password using PBKDF2-SHA256. WebCrypto\n * is preferred when available; Node `pbkdf2Sync` is used as a fallback.\n */\nasync function derivePbkdf2Key(password: string, salt: Uint8Array): Promise<CryptoKey | Uint8Array> {\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n const encoder = new TextEncoder()\n const keyMaterial = await globalThis.crypto.subtle.importKey(\n 'raw',\n encoder.encode(password),\n 'PBKDF2',\n false,\n ['deriveKey'],\n )\n return globalThis.crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: asBufferSource(salt),\n iterations: PBKDF2_ITERATIONS,\n hash: 'SHA-256',\n },\n keyMaterial,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt'],\n )\n }\n const { pbkdf2Sync } = await import('node:crypto')\n return new Uint8Array(pbkdf2Sync(password, salt, PBKDF2_ITERATIONS, 32, 'sha256'))\n}\n\nasync function aesGcmEncrypt(\n key: CryptoKey | Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n): Promise<Uint8Array> {\n if (key instanceof Uint8Array) {\n const { createCipheriv } = await import('node:crypto')\n const cipher = createCipheriv('aes-256-gcm', key, iv)\n const ct1 = cipher.update(plaintext)\n const ct2 = cipher.final()\n const tag = cipher.getAuthTag()\n const out = new Uint8Array(ct1.length + ct2.length + tag.length)\n out.set(ct1, 0)\n out.set(ct2, ct1.length)\n out.set(tag, ct1.length + ct2.length)\n return out\n }\n const out = await globalThis.crypto.subtle.encrypt(\n { name: 'AES-GCM', iv: asBufferSource(iv) },\n key,\n asBufferSource(plaintext),\n )\n return new Uint8Array(out)\n}\n\nasync function aesGcmDecrypt(\n key: CryptoKey | Uint8Array,\n iv: Uint8Array,\n ciphertextWithTag: Uint8Array,\n): Promise<Uint8Array> {\n if (key instanceof Uint8Array) {\n const { createDecipheriv } = await import('node:crypto')\n const tag = ciphertextWithTag.subarray(ciphertextWithTag.length - TAG_LEN)\n const ct = ciphertextWithTag.subarray(0, ciphertextWithTag.length - TAG_LEN)\n const decipher = createDecipheriv('aes-256-gcm', key, iv)\n decipher.setAuthTag(tag)\n const pt1 = decipher.update(ct)\n const pt2 = decipher.final()\n const out = new Uint8Array(pt1.length + pt2.length)\n out.set(pt1, 0)\n out.set(pt2, pt1.length)\n return out\n }\n const out = await globalThis.crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: asBufferSource(iv) },\n key,\n asBufferSource(ciphertextWithTag),\n )\n return new Uint8Array(out)\n}\n\n/**\n * Convert ArrayBuffer to hex string\n */\nfunction bufferToHex(buffer: ArrayBuffer): string {\n return Array.from(new Uint8Array(buffer))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Convert ArrayBuffer to base64 string\n */\nfunction bufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n const chunks: string[] = []\n const chunkSize = 8192\n for (let i = 0; i < bytes.byteLength; i += chunkSize) {\n chunks.push(String.fromCharCode(...bytes.subarray(i, i + chunkSize)))\n }\n if (typeof btoa !== 'undefined') return btoa(chunks.join(''))\n return Buffer.from(bytes).toString('base64')\n}\n\n/**\n * Convert base64 string to Uint8Array.\n * Throws CraftCryptoError on malformed input rather than DOMException.\n */\nfunction base64ToBuffer(base64: string): Uint8Array {\n if (typeof atob !== 'undefined') {\n let binary: string\n try {\n binary = atob(base64)\n }\n catch (e) {\n throw new CraftCryptoError('Invalid base64 input', { cause: e })\n }\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return bytes\n }\n return new Uint8Array(Buffer.from(base64, 'base64'))\n}\n\n/**\n * Generate a random UUID v4\n */\nexport function uuid(): string {\n if (typeof globalThis.crypto !== 'undefined' && 'randomUUID' in globalThis.crypto) {\n return globalThis.crypto.randomUUID()\n }\n // Fallback using crypto.getRandomValues for security\n const bytes = new Uint8Array(16)\n ;(globalThis.crypto as Crypto).getRandomValues(bytes)\n // Set version (4) and variant (RFC 4122)\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`\n}\n\n/**\n * Generate a random string of specified length.\n *\n * @throws {CraftCryptoError} when `charset` is empty (would otherwise loop\n * forever with `Math.random` returning a value modulo 0).\n */\nexport async function randomString(length: number, charset?: string): Promise<string> {\n const chars = charset ?? 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n if (chars.length === 0) {\n throw new CraftCryptoError('randomString: charset cannot be empty')\n }\n if (!Number.isInteger(length) || length < 0) {\n throw new CraftCryptoError('randomString: length must be a non-negative integer')\n }\n if (length === 0) return ''\n // Use rejection sampling to avoid modulo bias\n const maxValid = 256 - (256 % chars.length)\n let bytes = await crypto.randomBytes(length * 2)\n let result = ''\n let i = 0\n while (result.length < length) {\n if (i >= bytes.length) {\n bytes = await crypto.randomBytes(length * 2)\n i = 0\n }\n if (bytes[i] < maxValid) {\n result += chars[bytes[i] % chars.length]\n }\n i++\n }\n return result\n}\n\n/**\n * HMAC signature\n */\nexport async function hmac(\n algorithm: 'sha256' | 'sha512',\n key: string,\n data: string,\n): Promise<string> {\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n const encoder = new TextEncoder()\n const keyBuffer = await globalThis.crypto.subtle.importKey(\n 'raw',\n encoder.encode(key),\n { name: 'HMAC', hash: algorithm === 'sha256' ? 'SHA-256' : 'SHA-512' },\n false,\n ['sign'],\n )\n\n const signature = await globalThis.crypto.subtle.sign('HMAC', keyBuffer, encoder.encode(data))\n return bufferToHex(signature)\n }\n\n // Node.js fallback\n const nodeCrypto = await import('node:crypto')\n return nodeCrypto.createHmac(algorithm, key).update(data).digest('hex')\n}\n\n/**\n * Compare two strings in constant time (timing-safe).\n *\n * Compares the UTF-8 byte representations rather than UTF-16 code units —\n * NFC/NFD-different but visually-identical strings still come out unequal,\n * but at least byte-level comparison is what cryptographic protocols\n * actually expect.\n */\nexport function timingSafeEqual(a: string, b: string): boolean {\n const enc = new TextEncoder()\n const aBytes = enc.encode(a)\n const bBytes = enc.encode(b)\n // Always compare full length to avoid leaking length information via timing\n const maxLen = Math.max(aBytes.length, bBytes.length)\n let result = aBytes.length ^ bBytes.length\n for (let i = 0; i < maxLen; i++) {\n result |= (aBytes[i] ?? 0) ^ (bBytes[i] ?? 0)\n }\n return result === 0\n}\n\n/**\n * Generate password hash (using PBKDF2-SHA256 with 600k iterations).\n *\n * Salt encoding is unified across runtimes: the salt is always returned\n * as base64, and when supplied it is interpreted as base64 in BOTH the\n * WebCrypto and Node code paths. The previous implementation treated the\n * salt as base64 in WebCrypto and as a raw UTF-8 string in Node, so the\n * same `(password, salt)` pair gave different hashes per environment and\n * cross-environment auth was broken.\n */\nexport async function hashPassword(password: string, salt?: string): Promise<{ hash: string; salt: string }> {\n let saltBytes: Uint8Array\n if (salt) {\n try {\n saltBytes = base64ToBuffer(salt)\n }\n catch (e) {\n throw new CraftCryptoError('hashPassword: salt must be base64-encoded', { cause: e })\n }\n }\n else {\n saltBytes = await crypto.randomBytes(16)\n }\n const actualSalt = bufferToBase64(saltBytes.buffer.slice(saltBytes.byteOffset, saltBytes.byteOffset + saltBytes.byteLength) as ArrayBuffer)\n\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n const encoder = new TextEncoder()\n const keyMaterial = await globalThis.crypto.subtle.importKey(\n 'raw',\n encoder.encode(password),\n 'PBKDF2',\n false,\n ['deriveBits'],\n )\n\n const derivedBits = await globalThis.crypto.subtle.deriveBits(\n {\n name: 'PBKDF2',\n salt: asBufferSource(saltBytes),\n iterations: PBKDF2_ITERATIONS,\n hash: 'SHA-256',\n },\n keyMaterial,\n 256,\n )\n\n return {\n hash: bufferToBase64(derivedBits),\n salt: actualSalt,\n }\n }\n\n const { pbkdf2 } = await import('node:crypto')\n return new Promise((resolve, reject) => {\n pbkdf2(password, saltBytes, PBKDF2_ITERATIONS, 32, 'sha256', (err, derivedKey) => {\n if (err) reject(err)\n else resolve({\n hash: bufferToBase64(derivedKey.buffer.slice(derivedKey.byteOffset, derivedKey.byteOffset + derivedKey.byteLength) as ArrayBuffer),\n salt: actualSalt,\n })\n })\n })\n}\n\n/**\n * Verify password against hash\n */\nexport async function verifyPassword(password: string, hash: string, salt: string): Promise<boolean> {\n const result = await hashPassword(password, salt)\n return timingSafeEqual(result.hash, hash)\n}\n\nexport default crypto\n",
|
|
22
|
+
"/**\n * Craft Process API\n * Provides process management and system information\n */\n\nimport { getBridge } from '../bridge/core'\n\n/**\n * Send a request through the unified `NativeBridge`. Replaces the legacy\n * `window.craft.bridge.call(...)` hook so process API methods share the\n * same timeout/retry/error semantics as everything else in the SDK.\n */\nasync function callBridge<T = unknown>(method: string, params?: unknown): Promise<T> {\n return getBridge().request<unknown, T>(method, params)\n}\n\n/**\n * Live view of process environment variables. Implemented as a Proxy so that\n * `env.FOO = 'bar'` and `delete env.FOO` actually update `process.env`, and\n * reads always reflect the latest value rather than a snapshot taken at\n * module load time.\n *\n * In non-Node environments (e.g. inside a webview), the proxy targets an\n * empty object — reads return `undefined`, writes are local to the proxy.\n */\nconst _envBacking: Record<string, string | undefined> = typeof process !== 'undefined'\n ? (process.env as Record<string, string | undefined>)\n : {}\n\nexport const env: Record<string, string | undefined> = new Proxy(_envBacking, {\n get(_, key: string) {\n return _envBacking[key]\n },\n set(_, key: string, value) {\n _envBacking[key] = value as string | undefined\n return true\n },\n deleteProperty(_, key: string) {\n delete _envBacking[key]\n return true\n },\n ownKeys() {\n return Reflect.ownKeys(_envBacking)\n },\n getOwnPropertyDescriptor(_, key: string) {\n return Object.getOwnPropertyDescriptor(_envBacking, key)\n },\n has(_, key: string) {\n return key in _envBacking\n },\n})\n\n/**\n * Current platform\n */\nexport type Platform = 'darwin' | 'macos' | 'win32' | 'windows' | 'linux' | 'ios' | 'android' | 'unknown'\n\n/**\n * Get current platform\n */\nexport function getPlatform(): Platform {\n // Prefer native bridge platform info (most reliable)\n if (typeof globalThis !== 'undefined') {\n const w = globalThis as any\n if (w.craft?._platform) return w.craft._platform\n if (w.__CRAFT_PLATFORM__) return w.__CRAFT_PLATFORM__\n }\n\n // Fall back to Node.js process.platform\n if (typeof process !== 'undefined' && process.platform) {\n return process.platform as Platform\n }\n\n // Last resort: user-agent sniffing (unreliable). Guard `navigator` with\n // typeof — a missing global throws ReferenceError before optional\n // chaining can run.\n if (typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string') {\n const ua = navigator.userAgent.toLowerCase()\n // iPhone/iPad checks come BEFORE the broader 'mac' check because\n // iPadOS reports `Macintosh` in its UA string.\n if (ua.includes('iphone') || ua.includes('ipad')) return 'ios'\n if (ua.includes('android')) return 'android'\n if (ua.includes('mac')) return 'darwin'\n if (ua.includes('win')) return 'win32'\n if (ua.includes('linux')) return 'linux'\n }\n\n return 'unknown'\n}\n\n/**\n * Check if running on desktop\n */\nexport function isDesktop(): boolean {\n const platform = getPlatform()\n return platform === 'darwin' || platform === 'macos' || platform === 'win32' || platform === 'windows' || platform === 'linux'\n}\n\n/**\n * Check if running on mobile\n */\nexport function isMobile(): boolean {\n const platform = getPlatform()\n return platform === 'ios' || platform === 'android'\n}\n\n/**\n * Check if running in Craft environment\n */\nexport function isCraft(): boolean {\n return typeof window !== 'undefined' && typeof window.craft !== 'undefined'\n}\n\n/**\n * System information\n */\nexport interface SystemInfo {\n platform: Platform\n arch: string\n osVersion: string\n hostname: string\n cpuCount: number\n totalMemory: number\n freeMemory: number\n uptime: number\n}\n\n/**\n * Get system information\n */\nexport async function getSystemInfo(): Promise<SystemInfo> {\n if (typeof window !== 'undefined' && window.craft) {\n return callBridge<SystemInfo>('process.getSystemInfo')\n }\n\n // Node.js fallback\n if (typeof process !== 'undefined') {\n const os = await import('node:os')\n return {\n platform: process.platform as Platform,\n arch: process.arch,\n osVersion: os.release(),\n hostname: os.hostname(),\n cpuCount: os.cpus().length,\n totalMemory: os.totalmem(),\n freeMemory: os.freemem(),\n uptime: os.uptime(),\n }\n }\n\n // `navigator` is a host global; missing globals throw ReferenceError\n // before optional chaining can run, so guard with `typeof`.\n const cpuCount = typeof navigator !== 'undefined' && typeof navigator.hardwareConcurrency === 'number'\n ? navigator.hardwareConcurrency\n : 1\n\n return {\n platform: getPlatform(),\n arch: 'unknown',\n osVersion: 'unknown',\n hostname: 'unknown',\n cpuCount,\n totalMemory: 0,\n freeMemory: 0,\n uptime: 0,\n }\n}\n\n/**\n * Execute shell command (requires Craft environment)\n */\nexport interface ExecOptions {\n cwd?: string\n env?: Record<string, string>\n timeout?: number\n maxBuffer?: number\n}\n\nexport interface ExecResult {\n stdout: string\n stderr: string\n exitCode: number\n}\n\nexport async function exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n if (typeof window !== 'undefined' && window.craft) {\n return callBridge<ExecResult>('process.exec', { command, ...options })\n }\n\n // Node.js fallback\n const { exec: nodeExec } = await import('node:child_process')\n const { promisify } = await import('node:util')\n const execPromise = promisify(nodeExec)\n\n try {\n const { stdout, stderr } = await execPromise(command, {\n cwd: options?.cwd,\n env: options?.env ? { ...process.env, ...options.env } : undefined,\n timeout: options?.timeout,\n maxBuffer: options?.maxBuffer || 1024 * 1024\n })\n return { stdout, stderr, exitCode: 0 }\n }\ncatch (error: any) {\n return {\n stdout: error.stdout || '',\n stderr: error.stderr || error.message,\n exitCode: error.code || 1\n }\n }\n}\n\n/**\n * Spawn a child process\n */\nexport interface SpawnOptions {\n cwd?: string\n env?: Record<string, string>\n /**\n * Run the command through a shell. The Craft bridge translates this\n * automatically (cmd.exe on Windows, /bin/sh elsewhere). On the Node\n * fallback the command is rewritten to `cmd.exe /c <cmd>` on win32.\n */\n shell?: boolean\n}\n\nexport class ChildProcess {\n private processId: string | null = null\n private onStdoutHandlers: ((_data: string) => void)[] = []\n private onStderrHandlers: ((_data: string) => void)[] = []\n private onExitHandlers: ((_code: number) => void)[] = []\n // Tracked DOM listeners so we can detach them on exit/kill — without\n // this, every spawn leaks 3 window listeners that pin closures forever.\n private domListeners: Array<{ type: string; handler: EventListener }> = []\n private exited = false\n\n constructor(\n private command: string,\n private args: string[] = [],\n private options: SpawnOptions = {},\n ) {}\n\n private addDomListener(type: string, handler: EventListener): void {\n if (typeof window === 'undefined') return\n window.addEventListener(type, handler)\n this.domListeners.push({ type, handler })\n }\n\n private removeDomListeners(): void {\n if (typeof window === 'undefined') return\n for (const { type, handler } of this.domListeners) {\n window.removeEventListener(type, handler)\n }\n this.domListeners = []\n }\n\n /** Pid assigned by the native bridge, or null before start(). */\n get pid(): string | null {\n return this.processId\n }\n\n /**\n * Start the process\n */\n async start(): Promise<void> {\n if (typeof window !== 'undefined' && window.craft) {\n const result = await callBridge<{ pid: string }>('process.spawn', {\n command: this.command,\n args: this.args,\n ...this.options,\n })\n this.processId = result.pid\n\n const stdoutHandler = ((event: CustomEvent) => {\n if (event.detail.pid === this.processId) {\n this.onStdoutHandlers.forEach(h => h(event.detail.data))\n }\n }) as EventListener\n const stderrHandler = ((event: CustomEvent) => {\n if (event.detail.pid === this.processId) {\n this.onStderrHandlers.forEach(h => h(event.detail.data))\n }\n }) as EventListener\n const exitHandler = ((event: CustomEvent) => {\n if (event.detail.pid === this.processId) {\n this.exited = true\n this.onExitHandlers.forEach(h => h(event.detail.code))\n // Once the process has exited, our listeners can never fire\n // again — release them so the closures are GC-able.\n this.removeDomListeners()\n }\n }) as EventListener\n\n this.addDomListener('craft:process:stdout', stdoutHandler)\n this.addDomListener('craft:process:stderr', stderrHandler)\n this.addDomListener('craft:process:exit', exitHandler)\n\n return\n }\n\n throw new Error('spawn() requires Craft environment')\n }\n\n /**\n * Write to stdin\n */\n async write(data: string): Promise<void> {\n if (typeof window !== 'undefined' && window.craft && this.processId) {\n await callBridge('process.stdin', { pid: this.processId, data })\n }\n }\n\n /**\n * Kill the process\n */\n async kill(signal: string = 'SIGTERM'): Promise<void> {\n if (typeof window !== 'undefined' && window.craft && this.processId) {\n await callBridge('process.kill', { pid: this.processId, signal })\n // The native side will still emit a final `exit` event; the exit\n // handler removes listeners from there. Defensive cleanup here too\n // in case the native bridge drops the exit event.\n if (this.exited) this.removeDomListeners()\n }\n }\n\n /**\n * Listen for stdout data\n */\n onStdout(handler: (data: string) => void): () => void {\n this.onStdoutHandlers.push(handler)\n return () => {\n const idx = this.onStdoutHandlers.indexOf(handler)\n if (idx >= 0) this.onStdoutHandlers.splice(idx, 1)\n }\n }\n\n /**\n * Listen for stderr data\n */\n onStderr(handler: (data: string) => void): () => void {\n this.onStderrHandlers.push(handler)\n return () => {\n const idx = this.onStderrHandlers.indexOf(handler)\n if (idx >= 0) this.onStderrHandlers.splice(idx, 1)\n }\n }\n\n /**\n * Listen for exit\n */\n onExit(handler: (code: number) => void): () => void {\n this.onExitHandlers.push(handler)\n return () => {\n const idx = this.onExitHandlers.indexOf(handler)\n if (idx >= 0) this.onExitHandlers.splice(idx, 1)\n }\n }\n}\n\n/**\n * Spawn a child process\n */\nexport function spawn(\n command: string,\n args?: string[],\n options?: SpawnOptions\n): ChildProcess {\n return new ChildProcess(command, args, options)\n}\n\n/**\n * Get current working directory\n */\nexport function cwd(): string {\n if (typeof process !== 'undefined') {\n return process.cwd()\n }\n return '/'\n}\n\n/**\n * Get home directory\n */\nexport async function homeDir(): Promise<string> {\n if (typeof window !== 'undefined' && window.craft) {\n return callBridge<string>('process.homeDir')\n }\n\n if (typeof process !== 'undefined') {\n const os = await import('node:os')\n return os.homedir()\n }\n\n return '/'\n}\n\n/**\n * Get temp directory\n */\nexport async function tempDir(): Promise<string> {\n if (typeof window !== 'undefined' && window.craft) {\n return callBridge<string>('process.tempDir')\n }\n\n if (typeof process !== 'undefined') {\n const os = await import('node:os')\n return os.tmpdir()\n }\n\n return '/tmp'\n}\n\n/**\n * Exit the application. Prefers the native bridge's `app.quit()` so the\n * platform can flush state; falls back to `process.exit` in Node-like\n * environments. Accepts a non-zero code on the Node fallback so callers can\n * signal failure to a parent shell.\n */\nexport function exit(code: number = 0): void {\n if (typeof window !== 'undefined') {\n const app = window.craft?.app as { quit?: (code?: number) => void } | undefined\n if (app && typeof app.quit === 'function') {\n app.quit(code)\n return\n }\n }\n if (typeof process !== 'undefined' && typeof process.exit === 'function') {\n process.exit(code)\n }\n}\n\n/**\n * Get command line arguments\n */\nexport function argv(): string[] {\n if (typeof process !== 'undefined') {\n return process.argv\n }\n return []\n}\n\n/**\n * Open URL or file in default application.\n *\n * Uses `child_process.execFile` (no shell) so a target like\n * `https://example.com; rm -rf ~` cannot be reinterpreted by a shell.\n *\n * On Windows we explicitly invoke `cmd.exe /c start \"\" <target>` rather\n * than calling `start` directly — `start` is a `cmd.exe` builtin, not an\n * executable, so the previous implementation would fail with ENOENT. The\n * empty `\"\"` is the literal `start` window-title argument; `start` would\n * otherwise interpret a quoted path as the title and never open it.\n */\nexport async function open(target: string): Promise<void> {\n if (typeof window !== 'undefined' && window.craft) {\n await callBridge('process.open', { target })\n return\n }\n\n const platform = getPlatform()\n const { execFile } = await import('node:child_process')\n const { promisify } = await import('node:util')\n const exec = promisify(execFile)\n\n switch (platform) {\n case 'darwin':\n case 'macos':\n await exec('open', [target])\n return\n case 'win32':\n case 'windows':\n await exec('cmd.exe', ['/c', 'start', '\"\"', target])\n return\n case 'linux':\n await exec('xdg-open', [target])\n return\n default:\n throw new Error(`Unsupported platform: ${platform}`)\n }\n}\n\nconst processApi: {\n env: typeof env\n getPlatform: typeof getPlatform\n isDesktop: typeof isDesktop\n isMobile: typeof isMobile\n isCraft: typeof isCraft\n getSystemInfo: typeof getSystemInfo\n exec: typeof exec\n spawn: typeof spawn\n cwd: typeof cwd\n homeDir: typeof homeDir\n tempDir: typeof tempDir\n exit: typeof exit\n argv: typeof argv\n open: typeof open\n} = {\n env,\n getPlatform,\n isDesktop,\n isMobile,\n isCraft,\n getSystemInfo,\n exec,\n spawn,\n cwd,\n homeDir,\n tempDir,\n exit,\n argv,\n open,\n}\n\nexport default processApi\n",
|
|
23
|
+
"/**\n * @fileoverview Craft Mobile API\n * @description Unified cross-platform mobile API for iOS and Android.\n * Provides consistent access to device features, sensors, and native capabilities.\n * @module @craft-native/api/mobile\n *\n * @example\n * ```typescript\n * import { device, haptics, permissions, camera, biometrics, location, share } from '@craft-native/api/mobile'\n *\n * // Get device info\n * const info = await device.getInfo()\n * console.log(`Running on ${info.platform} ${info.osVersion}`)\n *\n * // Request permissions\n * const granted = await permissions.request('camera')\n *\n * // Trigger haptic feedback\n * await haptics.impact('medium')\n *\n * // Take a photo\n * const photo = await camera.takePicture()\n * ```\n */\n\nimport { secureUUID } from '../bridge/ids'\n\n/** localStorage key for the persisted web-fallback device id. */\nconst WEB_DEVICE_ID_KEY = '__craft_web_device_id__'\n\n/**\n * Internal: return a stable device id for the web fallback. Persists in\n * localStorage so two `device.getInfo()` calls in the same session (and\n * across reloads) report the *same* id. The previous implementation\n * generated a fresh `Math.random` id every call, which made\n * `deviceId`-keyed analytics impossible to tie back to a single browser.\n */\nexport function _webFallbackDeviceId(): string {\n if (typeof globalThis !== 'undefined' && (globalThis as any).localStorage) {\n try {\n const ls = (globalThis as any).localStorage as Storage\n const existing = ls.getItem(WEB_DEVICE_ID_KEY)\n if (existing && /^web-[0-9a-f-]+$/i.test(existing)) return existing\n const fresh = `web-${secureUUID()}`\n ls.setItem(WEB_DEVICE_ID_KEY, fresh)\n return fresh\n }\n catch {\n // Private-browsing modes throw on localStorage.setItem; fall through.\n }\n }\n // No localStorage → at least use a strong RNG. The id won't persist\n // between calls, but it won't pretend to either.\n return `web-${secureUUID()}`\n}\n\n/**\n * Test-only hook to clear the cached device id.\n */\nexport function _resetWebFallbackDeviceIdForTests(): void {\n if (typeof globalThis !== 'undefined' && (globalThis as any).localStorage) {\n try { ((globalThis as any).localStorage as Storage).removeItem(WEB_DEVICE_ID_KEY) }\n catch { /* ignore */ }\n }\n}\n\n// ============================================================================\n// Device Info API\n// ============================================================================\n\n/**\n * Device information.\n *\n * Optional sub-fields (`screen`, `battery`, `network`) reflect what the\n * native side might omit — e.g. desktop hosts have no battery, headless\n * environments have no screen. Consumers must defensively check before\n * accessing nested properties.\n */\nexport interface DeviceInfo {\n /** Platform: 'ios' | 'android' | 'macos' | 'windows' | 'linux' */\n platform: 'ios' | 'android' | 'macos' | 'windows' | 'linux'\n /** OS version string (e.g., \"17.0\", \"14\") */\n osVersion: string\n /** Device model (e.g., \"iPhone 15 Pro\", \"Pixel 8\") */\n model: string\n /** Device manufacturer */\n manufacturer: string\n /** Unique device identifier */\n deviceId: string\n /** Whether device is a tablet */\n isTablet: boolean\n /** Screen dimensions (omitted by headless or desktop hosts) */\n screen?: {\n width: number\n height: number\n scale: number\n }\n /** Battery info (omitted on devices without a battery) */\n battery?: {\n level: number\n isCharging: boolean\n }\n /** Network status (omitted when the host doesn't report it) */\n network?: {\n type: 'wifi' | 'cellular' | 'ethernet' | 'none'\n isConnected: boolean\n }\n}\n\n/**\n * Device capabilities.\n */\nexport interface DeviceCapabilities {\n /** Has camera */\n camera: boolean\n /** Has biometric authentication */\n biometrics: boolean\n /** Has NFC */\n nfc: boolean\n /** Has Bluetooth */\n bluetooth: boolean\n /** Has GPS */\n gps: boolean\n /** Has accelerometer */\n accelerometer: boolean\n /** Has gyroscope */\n gyroscope: boolean\n /** Has haptic feedback */\n haptics: boolean\n /** Has AR support */\n ar: boolean\n /** Has Face ID (iOS) or face unlock */\n faceId: boolean\n /** Has Touch ID (iOS) or fingerprint */\n touchId: boolean\n}\n\n/**\n * Device information and capabilities API.\n *\n * @example\n * ```typescript\n * // Get device info\n * const info = await device.getInfo()\n * console.log(`Platform: ${info.platform}`)\n * console.log(`Model: ${info.model}`)\n * console.log(`Battery: ${info.battery.level}%`)\n *\n * // Check capabilities\n * const caps = await device.getCapabilities()\n * if (caps.biometrics) {\n * // Enable biometric login\n * }\n *\n * // Check if running on mobile\n * if (device.isMobile()) {\n * // Show mobile-specific UI\n * }\n * ```\n */\nexport const device = {\n /**\n * Get comprehensive device information.\n *\n * @returns Promise resolving to DeviceInfo\n */\n async getInfo(): Promise<DeviceInfo> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.device) {\n return craft.device.getInfo()\n }\n // Return web defaults\n return {\n platform: detectPlatform(),\n osVersion: 'unknown',\n model: 'unknown',\n manufacturer: 'unknown',\n deviceId: _webFallbackDeviceId(),\n isTablet: false,\n screen: {\n width: typeof window !== 'undefined' ? window.innerWidth || 0 : 0,\n height: typeof window !== 'undefined' ? window.innerHeight || 0 : 0,\n scale: typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1\n },\n battery: { level: 100, isCharging: false },\n network: { type: 'wifi', isConnected: typeof navigator !== 'undefined' ? navigator.onLine ?? true : true }\n }\n },\n\n /**\n * Get device capabilities.\n *\n * @returns Promise resolving to DeviceCapabilities\n */\n async getCapabilities(): Promise<DeviceCapabilities> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.device) {\n return craft.device.getCapabilities()\n }\n return {\n camera: true,\n biometrics: false,\n nfc: false,\n bluetooth: false,\n gps: 'geolocation' in navigator,\n accelerometer: false,\n gyroscope: false,\n haptics: 'vibrate' in navigator,\n ar: false,\n faceId: false,\n touchId: false\n }\n },\n\n /**\n * Check if running on a mobile device.\n */\n isMobile(): boolean {\n const platform = detectPlatform()\n return platform === 'ios' || platform === 'android'\n },\n\n /**\n * Check if running on iOS.\n */\n isIOS(): boolean {\n return detectPlatform() === 'ios'\n },\n\n /**\n * Check if running on Android.\n */\n isAndroid(): boolean {\n return detectPlatform() === 'android'\n },\n\n /**\n * Get current locale.\n */\n getLocale(): string {\n return navigator?.language || 'en-US'\n },\n\n /**\n * Get timezone.\n */\n getTimezone(): string {\n return Intl.DateTimeFormat().resolvedOptions().timeZone\n }\n}\n\n// ============================================================================\n// Haptics API\n// ============================================================================\n\n/**\n * Haptic feedback style.\n */\nexport type HapticStyle = 'light' | 'medium' | 'heavy' | 'soft' | 'rigid'\n\n/**\n * Haptic notification type.\n */\nexport type HapticNotificationType = 'success' | 'warning' | 'error'\n\n/**\n * Haptic feedback API.\n * Provides tactile feedback on supported devices.\n *\n * @example\n * ```typescript\n * // Impact feedback\n * await haptics.impact('medium')\n *\n * // Notification feedback\n * await haptics.notification('success')\n *\n * // Selection feedback (for UI selection changes)\n * await haptics.selection()\n *\n * // Custom vibration pattern (Android)\n * await haptics.vibrate([100, 50, 100])\n * ```\n */\nexport const haptics = {\n /**\n * Trigger impact haptic feedback.\n *\n * @param style - Impact style intensity\n */\n async impact(style: HapticStyle = 'medium'): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.haptics) {\n return craft.haptics.impact(style)\n }\n // Web fallback using Vibration API\n if ('vibrate' in navigator) {\n const duration = { light: 10, medium: 20, heavy: 30, soft: 5, rigid: 25 }[style]\n navigator.vibrate(duration)\n }\n },\n\n /**\n * Trigger notification haptic feedback.\n *\n * @param type - Notification type\n */\n async notification(type: HapticNotificationType = 'success'): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.haptics) {\n return craft.haptics.notification(type)\n }\n if ('vibrate' in navigator) {\n const patterns = {\n success: [10, 30, 10],\n warning: [30, 30, 30],\n error: [50, 50, 50, 50, 50]\n }\n navigator.vibrate(patterns[type])\n }\n },\n\n /**\n * Trigger selection haptic feedback.\n * Use when a selection changes (e.g., picker value change).\n */\n async selection(): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.haptics) {\n return craft.haptics.selection()\n }\n if ('vibrate' in navigator) {\n navigator.vibrate(5)\n }\n },\n\n /**\n * Vibrate with a custom pattern.\n *\n * @param pattern - Array of durations in ms [vibrate, pause, vibrate, ...]\n */\n async vibrate(pattern: number[]): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.haptics) {\n return craft.haptics.vibrate(pattern)\n }\n if ('vibrate' in navigator) {\n navigator.vibrate(pattern)\n }\n }\n}\n\n// ============================================================================\n// Permissions API\n// ============================================================================\n\n/**\n * Permission types.\n */\nexport type PermissionType =\n | 'camera'\n | 'microphone'\n | 'photos'\n | 'location'\n | 'locationAlways'\n | 'notifications'\n | 'contacts'\n | 'calendar'\n | 'reminders'\n | 'bluetooth'\n | 'motion'\n | 'health'\n\n/**\n * Permission status.\n */\nexport type PermissionStatus = 'granted' | 'denied' | 'undetermined' | 'restricted'\n\n/**\n * Permissions API.\n * Request and check native permissions.\n *\n * @example\n * ```typescript\n * // Check permission status\n * const status = await permissions.check('camera')\n *\n * // Request permission\n * if (status !== 'granted') {\n * const newStatus = await permissions.request('camera')\n * if (newStatus === 'granted') {\n * // Permission granted, proceed\n * }\n * }\n *\n * // Check multiple permissions\n * const statuses = await permissions.checkMultiple(['camera', 'microphone'])\n *\n * // Request multiple permissions\n * const results = await permissions.requestMultiple(['camera', 'microphone', 'photos'])\n * ```\n */\nexport const permissions = {\n /**\n * Check the status of a permission.\n *\n * @param permission - Permission to check\n * @returns Promise resolving to PermissionStatus\n */\n async check(permission: PermissionType): Promise<PermissionStatus> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.permissions) {\n return craft.permissions.check(permission)\n }\n // Web fallback using Permissions API\n try {\n const webPermission = mapToWebPermission(permission)\n if (webPermission && navigator.permissions) {\n const result = await navigator.permissions.query({ name: webPermission as PermissionName })\n return mapWebPermissionStatus(result.state)\n }\n }\ncatch {\n // Permissions API not supported\n }\n return 'undetermined'\n },\n\n /**\n * Request a permission.\n *\n * @param permission - Permission to request\n * @returns Promise resolving to new PermissionStatus\n */\n async request(permission: PermissionType): Promise<PermissionStatus> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.permissions) {\n return craft.permissions.request(permission)\n }\n // Web fallback - trigger permission request through relevant API\n try {\n if (permission === 'camera' || permission === 'microphone') {\n const constraints: MediaStreamConstraints = {}\n if (permission === 'camera') constraints.video = true\n if (permission === 'microphone') constraints.audio = true\n const stream = await navigator.mediaDevices.getUserMedia(constraints)\n stream.getTracks().forEach(track => track.stop())\n return 'granted'\n }\n if (permission === 'location') {\n return new Promise((resolve) => {\n navigator.geolocation.getCurrentPosition(\n () => resolve('granted'),\n () => resolve('denied')\n )\n })\n }\n if (permission === 'notifications') {\n const result = await Notification.requestPermission()\n return result === 'granted' ? 'granted' : 'denied'\n }\n }\ncatch {\n return 'denied'\n }\n return 'undetermined'\n },\n\n /**\n * Check multiple permissions.\n *\n * @param permissionList - Array of permissions to check\n * @returns Promise resolving to object mapping permissions to statuses\n */\n async checkMultiple(permissionList: PermissionType[]): Promise<Record<PermissionType, PermissionStatus>> {\n const results: Record<string, PermissionStatus> = {}\n for (const perm of permissionList) {\n results[perm] = await this.check(perm)\n }\n return results as Record<PermissionType, PermissionStatus>\n },\n\n /**\n * Request multiple permissions.\n *\n * @param permissionList - Array of permissions to request\n * @returns Promise resolving to object mapping permissions to statuses\n */\n async requestMultiple(permissionList: PermissionType[]): Promise<Record<PermissionType, PermissionStatus>> {\n const results: Record<string, PermissionStatus> = {}\n for (const perm of permissionList) {\n results[perm] = await this.request(perm)\n }\n return results as Record<PermissionType, PermissionStatus>\n },\n\n /**\n * Open app settings (to change permissions manually).\n */\n async openSettings(): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.permissions) {\n return craft.permissions.openSettings()\n }\n }\n}\n\n// ============================================================================\n// Camera API\n// ============================================================================\n\n/**\n * Camera options.\n */\nexport interface CameraOptions {\n /** Camera to use: 'front' | 'back' */\n camera?: 'front' | 'back'\n /** Photo quality: 0-100 */\n quality?: number\n /** Max width in pixels */\n maxWidth?: number\n /** Max height in pixels */\n maxHeight?: number\n /** Save to camera roll */\n saveToGallery?: boolean\n}\n\n/**\n * Photo result.\n */\nexport interface PhotoResult {\n /** Base64 encoded image data */\n base64: string\n /** Image URI/path */\n uri: string\n /** Image width */\n width: number\n /** Image height */\n height: number\n /** MIME type */\n mimeType: string\n}\n\n/**\n * Camera and image picker API.\n *\n * @example\n * ```typescript\n * // Take a photo\n * const photo = await camera.takePicture({ camera: 'back', quality: 80 })\n *\n * // Pick from gallery\n * const image = await camera.pickImage()\n *\n * // Pick multiple images\n * const images = await camera.pickMultiple({ maxCount: 5 })\n * ```\n */\nexport const camera = {\n /**\n * Take a photo with the device camera.\n *\n * @param options - Camera options\n * @returns Promise resolving to PhotoResult\n */\n async takePicture(options: CameraOptions = {}): Promise<PhotoResult> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.camera) {\n return craft.camera.takePicture(options)\n }\n throw new Error('Camera API not available. Must run in Craft environment.')\n },\n\n /**\n * Pick an image from the gallery.\n *\n * @returns Promise resolving to PhotoResult\n */\n async pickImage(): Promise<PhotoResult> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.camera) {\n return craft.camera.pickImage()\n }\n // Web fallback using file input\n return new Promise((resolve, reject) => {\n const input = document.createElement('input')\n input.type = 'file'\n input.accept = 'image/*'\n input.onchange = async () => {\n const file = input.files?.[0]\n if (file) {\n const reader = new FileReader()\n reader.onload = () => {\n const base64 = (reader.result as string).split(',')[1]\n resolve({\n base64,\n uri: URL.createObjectURL(file),\n width: 0,\n height: 0,\n mimeType: file.type\n })\n }\n reader.onerror = () => reject(new Error('Failed to read file'))\n reader.readAsDataURL(file)\n }\nelse {\n reject(new Error('No file selected'))\n }\n }\n input.click()\n })\n },\n\n /**\n * Pick multiple images from the gallery.\n *\n * @param options - Options including maxCount\n * @returns Promise resolving to array of PhotoResults\n */\n async pickMultiple(options: { maxCount?: number } = {}): Promise<PhotoResult[]> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.camera) {\n return craft.camera.pickMultiple(options)\n }\n throw new Error('Camera API not available. Must run in Craft environment.')\n },\n\n /**\n * Check if camera is available.\n */\n async isAvailable(): Promise<boolean> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.camera) {\n return craft.camera.isAvailable()\n }\n try {\n const devices = await navigator.mediaDevices.enumerateDevices()\n return devices.some(d => d.kind === 'videoinput')\n }\ncatch {\n return false\n }\n }\n}\n\n// ============================================================================\n// Biometrics API\n// ============================================================================\n\n/**\n * Biometric type.\n */\nexport type BiometricType = 'faceId' | 'touchId' | 'fingerprint' | 'face' | 'iris'\n\n/**\n * Biometric authentication API.\n *\n * @example\n * ```typescript\n * // Check availability\n * const available = await biometrics.isAvailable()\n * const type = await biometrics.getBiometricType()\n *\n * // Authenticate\n * try {\n * const success = await biometrics.authenticate('Verify your identity')\n * if (success) {\n * // Proceed with authenticated action\n * }\n * }\ncatch (error) {\n * console.log('Authentication failed:', error)\n * }\n * ```\n */\nexport const biometrics = {\n /**\n * Check if biometric authentication is available.\n */\n async isAvailable(): Promise<boolean> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.biometrics) {\n return craft.biometrics.isAvailable()\n }\n return false\n },\n\n /**\n * Get the type of biometric authentication available.\n */\n async getBiometricType(): Promise<BiometricType | null> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.biometrics) {\n return craft.biometrics.getBiometricType()\n }\n return null\n },\n\n /**\n * Authenticate using biometrics.\n *\n * @param reason - Reason shown to user for authentication\n * @returns Promise resolving to true if authenticated\n * @throws Error if authentication fails or is cancelled\n */\n async authenticate(reason: string): Promise<boolean> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.biometrics) {\n return craft.biometrics.authenticate(reason)\n }\n throw new Error('Biometrics not available')\n }\n}\n\n// ============================================================================\n// Secure Storage API\n// ============================================================================\n\n/**\n * Secure storage API for sensitive data.\n * Uses Keychain (iOS) or Keystore (Android).\n *\n * @example\n * ```typescript\n * // Store sensitive data\n * await secureStorage.set('authToken', 'secret-token-123')\n * await secureStorage.set('userCredentials', JSON.stringify({ user: 'john', pass: '***' }))\n *\n * // Retrieve data\n * const token = await secureStorage.get('authToken')\n *\n * // Delete data\n * await secureStorage.delete('authToken')\n *\n * // Clear all secure storage\n * await secureStorage.clear()\n * ```\n */\nexport const secureStorage = {\n /**\n * Store a value securely.\n *\n * @param key - Storage key\n * @param value - Value to store\n */\n async set(key: string, value: string): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.secureStorage) {\n return craft.secureStorage.set(key, value)\n }\n // Fallback to localStorage (not secure, but functional for development)\n localStorage.setItem(`secure_${key}`, value)\n },\n\n /**\n * Retrieve a securely stored value.\n *\n * @param key - Storage key\n * @returns Promise resolving to value or null\n */\n async get(key: string): Promise<string | null> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.secureStorage) {\n return craft.secureStorage.get(key)\n }\n return localStorage.getItem(`secure_${key}`)\n },\n\n /**\n * Delete a securely stored value.\n *\n * @param key - Storage key\n */\n async delete(key: string): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.secureStorage) {\n return craft.secureStorage.delete(key)\n }\n localStorage.removeItem(`secure_${key}`)\n },\n\n /**\n * Clear all securely stored values.\n */\n async clear(): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.secureStorage) {\n return craft.secureStorage.clear()\n }\n Object.keys(localStorage)\n .filter(k => k.startsWith('secure_'))\n .forEach(k => localStorage.removeItem(k))\n }\n}\n\n// ============================================================================\n// Location API\n// ============================================================================\n\n/**\n * Location coordinates.\n */\nexport interface Location {\n latitude: number\n longitude: number\n altitude?: number\n accuracy: number\n heading?: number\n speed?: number\n timestamp: number\n}\n\n/**\n * Location options.\n */\nexport interface LocationOptions {\n /** Enable high accuracy (uses more battery) */\n enableHighAccuracy?: boolean\n /** Timeout in milliseconds */\n timeout?: number\n /** Maximum age of cached position in milliseconds */\n maximumAge?: number\n}\n\n/**\n * Location API.\n *\n * @example\n * ```typescript\n * // Get current location\n * const loc = await location.getCurrentPosition()\n * console.log(`Lat: ${loc.latitude}, Lng: ${loc.longitude}`)\n *\n * // Watch location changes\n * const watchId = location.watchPosition((loc) => {\n * console.log('New position:', loc)\n * })\n *\n * // Stop watching\n * location.clearWatch(watchId)\n * ```\n */\nexport const location = {\n /**\n * Get current position.\n *\n * @param options - Location options\n * @returns Promise resolving to Location\n */\n async getCurrentPosition(options: LocationOptions = {}): Promise<Location> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.location) {\n return craft.location.getCurrentPosition(options)\n }\n return new Promise((resolve, reject) => {\n navigator.geolocation.getCurrentPosition(\n (pos) => resolve({\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? undefined,\n accuracy: pos.coords.accuracy,\n heading: pos.coords.heading ?? undefined,\n speed: pos.coords.speed ?? undefined,\n timestamp: pos.timestamp\n }),\n reject,\n {\n enableHighAccuracy: options.enableHighAccuracy,\n timeout: options.timeout,\n maximumAge: options.maximumAge\n }\n )\n })\n },\n\n /**\n * Watch position changes.\n *\n * @param callback - Function called on position change\n * @param options - Location options\n * @returns Watch ID to use with clearWatch\n */\n watchPosition(callback: (location: Location) => void, options: LocationOptions = {}): number {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.location) {\n return craft.location.watchPosition(callback, options)\n }\n return navigator.geolocation.watchPosition(\n (pos) => callback({\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n altitude: pos.coords.altitude ?? undefined,\n accuracy: pos.coords.accuracy,\n heading: pos.coords.heading ?? undefined,\n speed: pos.coords.speed ?? undefined,\n timestamp: pos.timestamp\n }),\n console.error,\n {\n enableHighAccuracy: options.enableHighAccuracy,\n timeout: options.timeout,\n maximumAge: options.maximumAge\n }\n )\n },\n\n /**\n * Stop watching position.\n *\n * @param watchId - Watch ID returned from watchPosition\n */\n clearWatch(watchId: number): void {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.location) {\n return craft.location.clearWatch(watchId)\n }\n navigator.geolocation.clearWatch(watchId)\n }\n}\n\n// ============================================================================\n// Share API\n// ============================================================================\n\n/**\n * Share options.\n */\nexport interface ShareOptions {\n /** Text to share */\n text?: string\n /** URL to share */\n url?: string\n /** Title for the share */\n title?: string\n /** File paths/URIs to share */\n files?: string[]\n}\n\n/**\n * Share API.\n *\n * @example\n * ```typescript\n * // Share text\n * await share.share({ text: 'Check out this app!' })\n *\n * // Share URL\n * await share.share({ url: 'https://example.com', title: 'Cool Website' })\n *\n * // Share file\n * await share.share({ files: ['/path/to/image.png'] })\n * ```\n */\nexport const share = {\n /**\n * Open native share dialog.\n *\n * @param options - Share options\n */\n async share(options: ShareOptions): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.share) {\n return craft.share.share(options)\n }\n // Web Share API fallback\n if (navigator.share) {\n await navigator.share({\n title: options.title,\n text: options.text,\n url: options.url\n })\n }\nelse {\n throw new Error('Share API not available')\n }\n },\n\n /**\n * Check if sharing is available.\n */\n isAvailable(): boolean {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.share) {\n return true\n }\n return 'share' in navigator\n }\n}\n\n// ============================================================================\n// App Lifecycle API\n// ============================================================================\n\n/**\n * App state.\n */\nexport type AppState = 'active' | 'inactive' | 'background'\n\n/**\n * App lifecycle events API.\n *\n * @example\n * ```typescript\n * // Listen for app state changes\n * const removeListener = lifecycle.onStateChange((state) => {\n * if (state === 'background') {\n * // Save data, pause tasks\n * }\nelse if (state === 'active') {\n * // Refresh data\n * }\n * })\n *\n * // Get current state\n * const state = lifecycle.getState()\n *\n * // Remove listener\n * removeListener()\n * ```\n */\nexport const lifecycle = {\n /**\n * Get current app state.\n */\n getState(): AppState {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.lifecycle) {\n return craft.lifecycle.getState()\n }\n return document.visibilityState === 'visible' ? 'active' : 'background'\n },\n\n /**\n * Listen for app state changes.\n *\n * @param callback - Function called when state changes\n * @returns Function to remove listener\n */\n onStateChange(callback: (state: AppState) => void): () => void {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.lifecycle) {\n return craft.lifecycle.onStateChange(callback)\n }\n const handler = () => {\n callback(document.visibilityState === 'visible' ? 'active' : 'background')\n }\n document.addEventListener('visibilitychange', handler)\n return () => document.removeEventListener('visibilitychange', handler)\n }\n}\n\n// ============================================================================\n// Notifications API\n// ============================================================================\n\n/**\n * Notification options.\n */\nexport interface NotificationOptions {\n /** Notification title */\n title: string\n /** Notification body */\n body?: string\n /** Badge count (iOS) */\n badge?: number\n /** Sound name */\n sound?: string\n /** Custom data payload */\n data?: Record<string, unknown>\n /** Schedule for future (timestamp) */\n scheduleAt?: number\n}\n\n/**\n * Local notifications API.\n *\n * @example\n * ```typescript\n * // Show immediate notification\n * await notifications.show({\n * title: 'Hello!',\n * body: 'This is a notification'\n * })\n *\n * // Schedule notification\n * await notifications.schedule({\n * title: 'Reminder',\n * body: 'Time to take a break',\n * scheduleAt: Date.now() + 3600000 // 1 hour from now\n * })\n *\n * // Cancel all notifications\n * await notifications.cancelAll()\n * ```\n */\nexport const notifications = {\n /**\n * Show a local notification immediately.\n *\n * @param options - Notification options\n */\n async show(options: NotificationOptions): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.notifications) {\n return craft.notifications.show(options)\n }\n // Web Notifications API fallback\n if ('Notification' in window && Notification.permission === 'granted') {\n new Notification(options.title, { body: options.body })\n }\n },\n\n /**\n * Schedule a notification for the future.\n *\n * @param options - Notification options with scheduleAt\n */\n async schedule(options: NotificationOptions): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.notifications) {\n return craft.notifications.schedule(options)\n }\n throw new Error('Scheduled notifications not available in web')\n },\n\n /**\n * Cancel all scheduled notifications.\n */\n async cancelAll(): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.notifications) {\n return craft.notifications.cancelAll()\n }\n },\n\n /**\n * Set app badge count (iOS).\n *\n * @param count - Badge count (0 to clear)\n */\n async setBadge(count: number): Promise<void> {\n const craft = getCraftMobile()\n if (typeof window !== 'undefined' && craft?.notifications) {\n return craft.notifications.setBadge(count)\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\nfunction detectPlatform(): DeviceInfo['platform'] {\n if (typeof window === 'undefined') return 'linux'\n const ua = navigator.userAgent.toLowerCase()\n if (/iphone|ipad|ipod/.test(ua)) return 'ios'\n if (/android/.test(ua)) return 'android'\n if (/macintosh|mac os x/.test(ua)) return 'macos'\n if (/windows/.test(ua)) return 'windows'\n return 'linux'\n}\n\nfunction mapToWebPermission(permission: PermissionType): string | null {\n const mapping: Record<string, string> = {\n camera: 'camera',\n microphone: 'microphone',\n location: 'geolocation',\n notifications: 'notifications'\n }\n return mapping[permission] || null\n}\n\nfunction mapWebPermissionStatus(state: PermissionState): PermissionStatus {\n const mapping: Record<PermissionState, PermissionStatus> = {\n granted: 'granted',\n denied: 'denied',\n prompt: 'undetermined'\n }\n return mapping[state]\n}\n\n// Mobile bridge type for window.craft with mobile-specific properties\ninterface CraftMobileBridge {\n device?: {\n getInfo(): Promise<DeviceInfo>\n getCapabilities(): Promise<DeviceCapabilities>\n }\n haptics?: {\n impact(style: HapticStyle): Promise<void>\n notification(type: HapticNotificationType): Promise<void>\n selection(): Promise<void>\n vibrate(pattern: number[]): Promise<void>\n }\n permissions?: {\n check(permission: PermissionType): Promise<PermissionStatus>\n request(permission: PermissionType): Promise<PermissionStatus>\n openSettings(): Promise<void>\n }\n camera?: {\n takePicture(options: CameraOptions): Promise<PhotoResult>\n pickImage(): Promise<PhotoResult>\n pickMultiple(options: { maxCount?: number }): Promise<PhotoResult[]>\n isAvailable(): Promise<boolean>\n }\n biometrics?: {\n isAvailable(): Promise<boolean>\n getBiometricType(): Promise<BiometricType | null>\n authenticate(reason: string): Promise<boolean>\n }\n secureStorage?: {\n set(key: string, value: string): Promise<void>\n get(key: string): Promise<string | null>\n delete(key: string): Promise<void>\n clear(): Promise<void>\n }\n location?: {\n getCurrentPosition(options: LocationOptions): Promise<Location>\n watchPosition(callback: (location: Location) => void, options: LocationOptions): number\n clearWatch(watchId: number): void\n }\n share?: {\n share(options: ShareOptions): Promise<void>\n }\n lifecycle?: {\n getState(): AppState\n onStateChange(callback: (state: AppState) => void): () => void\n }\n notifications?: {\n show(options: NotificationOptions): Promise<void>\n schedule(options: NotificationOptions): Promise<void>\n cancelAll(): Promise<void>\n setBadge(count: number): Promise<void>\n }\n}\n\n/**\n * Helper to access window.craft with mobile-specific type extensions.\n * This avoids conflicts with the CraftBridgeAPI declaration in types.ts.\n */\nfunction getCraftMobile(): CraftMobileBridge | undefined {\n if (typeof window !== 'undefined') {\n return (window as any).craft as CraftMobileBridge | undefined\n }\n return undefined\n}\n\nconst mobile: {\n device: typeof device\n haptics: typeof haptics\n permissions: typeof permissions\n camera: typeof camera\n biometrics: typeof biometrics\n secureStorage: typeof secureStorage\n location: typeof location\n share: typeof share\n lifecycle: typeof lifecycle\n notifications: typeof notifications\n} = {\n device: device,\n haptics: haptics,\n permissions: permissions,\n camera: camera,\n biometrics: biometrics,\n secureStorage: secureStorage,\n location: location,\n share: share,\n lifecycle: lifecycle,\n notifications: notifications\n}\n\nexport default mobile\n",
|
|
24
|
+
"/**\n * @fileoverview iOS Advanced Features API\n * @description Advanced iOS-specific features including CarPlay, App Clips, Live Activities,\n * SharePlay, StoreKit 2, App Intents, TipKit, and Focus Filters.\n * @module @craft-native/api/ios-advanced\n */\n\nimport { isCraft, getPlatform } from './process'\n\n// ============================================================================\n// CarPlay Support\n// ============================================================================\n\n/**\n * CarPlay template types.\n */\nexport type CarPlayTemplateType =\n | 'list'\n | 'grid'\n | 'information'\n | 'point-of-interest'\n | 'tab-bar'\n | 'alert'\n | 'action-sheet'\n | 'now-playing'\n | 'voice-control'\n | 'search'\n | 'map'\n\n/**\n * CarPlay list item.\n */\nexport interface CarPlayListItem {\n /** Unique identifier */\n id: string\n /** Display text */\n text: string\n /** Detail text */\n detailText?: string\n /** Image name or URL */\n image?: string\n /** Whether item shows disclosure indicator */\n showsDisclosureIndicator?: boolean\n /** Whether item is playing */\n isPlaying?: boolean\n /** Playback progress (0-1) */\n playbackProgress?: number\n}\n\n/**\n * CarPlay grid item.\n */\nexport interface CarPlayGridItem {\n /** Unique identifier */\n id: string\n /** Display title */\n title: string\n /** Image name or URL */\n image: string\n}\n\n/**\n * CarPlay template configuration.\n */\nexport interface CarPlayTemplate {\n /** Template type */\n type: CarPlayTemplateType\n /** Template title */\n title?: string\n /** List items (for list template) */\n listItems?: CarPlayListItem[]\n /** Grid items (for grid template) */\n gridItems?: CarPlayGridItem[]\n /** Sections for grouped lists */\n sections?: Array<{\n header?: string\n items: CarPlayListItem[]\n }>\n /** Tab bar items */\n tabs?: Array<{\n title: string\n image: string\n template: CarPlayTemplate\n }>\n}\n\n/**\n * CarPlay API for automotive integration.\n *\n * @example\n * // Set up CarPlay scene\n * carplay.onConnect((_window) => {\n * carplay.pushTemplate({\n * type: 'list',\n * title: 'My Music',\n * listItems: [\n * { id: '1', text: 'Favorites', showsDisclosureIndicator: true },\n * { id: '2', text: 'Recently Played', showsDisclosureIndicator: true }\n * ]\n * })\n * })\n *\n * carplay.onSelectListItem((item, _template) => {\n * console.log('Selected:', item.text)\n * })\n */\nexport const carplay = {\n /**\n * Check if CarPlay is available.\n */\n async isAvailable(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.carplay?.isAvailable?.() ?? false\n },\n\n /**\n * Check if CarPlay is currently connected.\n */\n async isConnected(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.carplay?.isConnected?.() ?? false\n },\n\n /**\n * Register CarPlay connection handler.\n */\n onConnect(handler: (window: any) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.carplay?.onConnect?.(handler)\n },\n\n /**\n * Register CarPlay disconnection handler.\n */\n onDisconnect(handler: () => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.carplay?.onDisconnect?.(handler)\n },\n\n /**\n * Push a template to the CarPlay screen.\n */\n async pushTemplate(template: CarPlayTemplate, animated = true): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.carplay?.pushTemplate?.(template, animated)\n },\n\n /**\n * Pop the current template.\n */\n async popTemplate(animated = true): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.carplay?.popTemplate?.(animated)\n },\n\n /**\n * Pop to root template.\n */\n async popToRootTemplate(animated = true): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.carplay?.popToRootTemplate?.(animated)\n },\n\n /**\n * Present a template modally.\n */\n async presentTemplate(template: CarPlayTemplate, animated = true): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.carplay?.presentTemplate?.(template, animated)\n },\n\n /**\n * Dismiss presented template.\n */\n async dismissTemplate(animated = true): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.carplay?.dismissTemplate?.(animated)\n },\n\n /**\n * Register list item selection handler.\n */\n onSelectListItem(handler: (item: CarPlayListItem, template: CarPlayTemplate) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.carplay?.onSelectListItem?.(handler)\n },\n\n /**\n * Register grid item selection handler.\n */\n onSelectGridItem(handler: (item: CarPlayGridItem, template: CarPlayTemplate) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.carplay?.onSelectGridItem?.(handler)\n },\n\n /**\n * Update now playing information.\n */\n async updateNowPlaying(info: {\n title: string\n artist?: string\n album?: string\n artwork?: string\n duration?: number\n elapsedTime?: number\n playbackRate?: number\n isPlaying?: boolean\n }): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.carplay?.updateNowPlaying?.(info)\n }\n}\n\n// ============================================================================\n// App Clips\n// ============================================================================\n\n/**\n * App Clip invocation context.\n */\nexport interface AppClipInvocation {\n /** Invocation URL */\n url: string\n /** URL parameters */\n parameters: Record<string, string>\n /** Physical location (if available) */\n location?: {\n latitude: number\n longitude: number\n }\n /** Invocation source */\n source: 'qr-code' | 'nfc' | 'safari' | 'messages' | 'maps' | 'smart-banner'\n}\n\n/**\n * App Clips API for lightweight app experiences.\n *\n * @example\n * // Handle App Clip launch\n * appClips.onInvoke((invocation) => {\n * console.log('Launched from:', invocation.source)\n * console.log('URL:', invocation.url)\n * })\n *\n * // Prompt to install full app\n * await appClips.promptToInstallFullApp()\n */\nexport const appClips = {\n /**\n * Check if running as App Clip.\n */\n isAppClip(): boolean {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.appClips?.isAppClip?.() ?? false\n },\n\n /**\n * Register App Clip invocation handler.\n */\n onInvoke(handler: (invocation: AppClipInvocation) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.appClips?.onInvoke?.(handler)\n },\n\n /**\n * Get the invocation context.\n */\n async getInvocation(): Promise<AppClipInvocation | null> {\n if (!isCraft() || getPlatform() !== 'ios') return null\n return (window as any).craft?.appClips?.getInvocation?.()\n },\n\n /**\n * Prompt user to install the full app.\n */\n async promptToInstallFullApp(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.appClips?.promptToInstallFullApp?.()\n },\n\n /**\n * Request ephemeral notification permission.\n */\n async requestEphemeralNotificationPermission(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.appClips?.requestEphemeralNotificationPermission?.() ?? false\n },\n\n /**\n * Request location confirmation.\n * Used to verify user is at a specific location for App Clip experiences.\n */\n async confirmLocation(regionIdentifier: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.appClips?.confirmLocation?.(regionIdentifier) ?? false\n }\n}\n\n// ============================================================================\n// Live Activities (Dynamic Island)\n// ============================================================================\n\n/**\n * Live Activity content state.\n */\nexport interface LiveActivityContentState {\n [key: string]: string | number | boolean\n}\n\n/**\n * Live Activity attributes (static content).\n */\nexport interface LiveActivityAttributes {\n [key: string]: string | number | boolean\n}\n\n/**\n * Live Activity configuration.\n */\nexport interface LiveActivityConfig {\n /** Activity type identifier */\n activityType: string\n /** Static attributes */\n attributes: LiveActivityAttributes\n /** Initial content state */\n contentState: LiveActivityContentState\n /** Stale date (when content becomes outdated) */\n staleDate?: Date\n /** Relevance score (0-100) */\n relevanceScore?: number\n}\n\n/**\n * Live Activities API for Dynamic Island and Lock Screen.\n *\n * @example\n * // Start a delivery tracking activity\n * const activity = await liveActivities.start({\n * activityType: 'DeliveryActivity',\n * attributes: { orderNumber: '12345', restaurant: 'Pizza Place' },\n * contentState: { status: 'preparing', eta: '15 min' }\n * })\n *\n * // Update the activity\n * await liveActivities.update(activity.id, {\n * status: 'on-the-way',\n * eta: '5 min',\n * driverName: 'John'\n * })\n *\n * // End the activity\n * await liveActivities.end(activity.id, { status: 'delivered' })\n */\nexport const liveActivities = {\n /**\n * Check if Live Activities are supported.\n */\n async areSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.liveActivities?.areSupported?.() ?? false\n },\n\n /**\n * Check if Live Activities are enabled by user.\n */\n async areEnabled(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.liveActivities?.areEnabled?.() ?? false\n },\n\n /**\n * Start a new Live Activity.\n */\n async start(config: LiveActivityConfig): Promise<{ id: string }> {\n if (!isCraft() || getPlatform() !== 'ios') {\n return { id: `mock-${Date.now()}` }\n }\n return (window as any).craft?.liveActivities?.start?.(config) ?? { id: `mock-${Date.now()}` }\n },\n\n /**\n * Update an existing Live Activity.\n */\n async update(\n activityId: string,\n contentState: LiveActivityContentState,\n alertConfig?: {\n title: string\n body: string\n sound?: string\n }\n ): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.liveActivities?.update?.(activityId, contentState, alertConfig)\n },\n\n /**\n * End a Live Activity.\n */\n async end(\n activityId: string,\n finalContentState?: LiveActivityContentState,\n dismissalPolicy?: 'immediate' | 'default' | 'after'\n ): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.liveActivities?.end?.(activityId, finalContentState, dismissalPolicy)\n },\n\n /**\n * Get all active Live Activities.\n */\n async getAll(): Promise<Array<{ id: string; activityType: string; contentState: LiveActivityContentState }>> {\n if (!isCraft() || getPlatform() !== 'ios') return []\n return (window as any).craft?.liveActivities?.getAll?.() ?? []\n },\n\n /**\n * Request push token for remote Live Activity updates.\n */\n async requestPushToken(activityId: string): Promise<string | null> {\n if (!isCraft() || getPlatform() !== 'ios') return null\n return (window as any).craft?.liveActivities?.requestPushToken?.(activityId)\n }\n}\n\n// ============================================================================\n// SharePlay\n// ============================================================================\n\n/**\n * SharePlay session state.\n */\nexport type SharePlaySessionState = 'waiting' | 'joined' | 'invalidated'\n\n/**\n * SharePlay participant info.\n */\nexport interface SharePlayParticipant {\n /** Participant identifier */\n id: string\n /** Whether this is the local participant */\n isLocal: boolean\n}\n\n/**\n * SharePlay activity configuration.\n */\nexport interface SharePlayActivity {\n /** Activity identifier */\n id: string\n /** Activity title */\n title: string\n /** Activity subtitle */\n subtitle?: string\n /** Activity image */\n image?: string\n /** Whether activity supports picture-in-picture */\n supportsPictureInPicture?: boolean\n}\n\n/**\n * SharePlay API for shared experiences during FaceTime calls.\n *\n * @example\n * // Start a SharePlay activity\n * await sharePlay.startActivity({\n * id: 'watch-together',\n * title: 'Watch Movie Together',\n * subtitle: 'Synchronized playback'\n * })\n *\n * // Send synchronized message to all participants\n * sharePlay.broadcast({ action: 'play', timestamp: 1234 })\n *\n * // Receive messages from other participants\n * sharePlay.onMessage((message, participant) => {\n * console.log(`${participant.id}: ${message.action}`)\n * })\n */\nexport const sharePlay = {\n /**\n * Check if SharePlay is available.\n */\n async isAvailable(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.sharePlay?.isAvailable?.() ?? false\n },\n\n /**\n * Get the current session state.\n */\n async getSessionState(): Promise<SharePlaySessionState | null> {\n if (!isCraft() || getPlatform() !== 'ios') return null\n return (window as any).craft?.sharePlay?.getSessionState?.()\n },\n\n /**\n * Get all participants in the current session.\n */\n async getParticipants(): Promise<SharePlayParticipant[]> {\n if (!isCraft() || getPlatform() !== 'ios') return []\n return (window as any).craft?.sharePlay?.getParticipants?.() ?? []\n },\n\n /**\n * Start a SharePlay activity.\n */\n async startActivity(activity: SharePlayActivity): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.sharePlay?.startActivity?.(activity) ?? false\n },\n\n /**\n * End the current SharePlay activity.\n */\n async endActivity(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.sharePlay?.endActivity?.()\n },\n\n /**\n * Broadcast a message to all participants.\n */\n async broadcast(message: Record<string, any>): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.sharePlay?.broadcast?.(message)\n },\n\n /**\n * Send a message to a specific participant.\n */\n async send(participantId: string, message: Record<string, any>): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.sharePlay?.send?.(participantId, message)\n },\n\n /**\n * Register message handler.\n */\n onMessage(handler: (message: Record<string, any>, participant: SharePlayParticipant) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.sharePlay?.onMessage?.(handler)\n },\n\n /**\n * Register session state change handler.\n */\n onSessionStateChange(handler: (state: SharePlaySessionState) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.sharePlay?.onSessionStateChange?.(handler)\n },\n\n /**\n * Register participant change handler.\n */\n onParticipantsChange(handler: (participants: SharePlayParticipant[]) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.sharePlay?.onParticipantsChange?.(handler)\n },\n\n /**\n * Coordinate playback state across participants.\n */\n async coordinatePlayback(state: {\n isPlaying: boolean\n playbackRate: number\n currentTime: number\n }): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.sharePlay?.coordinatePlayback?.(state)\n }\n}\n\n// ============================================================================\n// StoreKit 2\n// ============================================================================\n\n/**\n * Product type.\n */\nexport type ProductType = 'consumable' | 'non-consumable' | 'auto-renewable' | 'non-renewable'\n\n/**\n * Product information.\n */\nexport interface Product {\n /** Product identifier */\n id: string\n /** Product type */\n type: ProductType\n /** Display name */\n displayName: string\n /** Description */\n description: string\n /** Formatted price */\n displayPrice: string\n /** Price in decimal */\n price: number\n /** Currency code */\n currencyCode: string\n /** Subscription info (for subscription products) */\n subscription?: {\n /** Subscription period */\n subscriptionPeriod: {\n unit: 'day' | 'week' | 'month' | 'year'\n value: number\n }\n /** Introductory offer */\n introductoryOffer?: {\n displayPrice: string\n period: { unit: string; value: number }\n periodCount: number\n paymentMode: 'freeTrial' | 'payAsYouGo' | 'payUpFront'\n }\n }\n}\n\n/**\n * Transaction information.\n */\nexport interface Transaction {\n /** Transaction identifier */\n id: string\n /** Original transaction ID (for renewals) */\n originalId: string\n /** Product identifier */\n productId: string\n /** Purchase date */\n purchaseDate: Date\n /** Expiration date (for subscriptions) */\n expirationDate?: Date\n /** Whether transaction is upgraded */\n isUpgraded: boolean\n /** Revocation date (if revoked) */\n revocationDate?: Date\n /** Revocation reason */\n revocationReason?: 'developerIssue' | 'other'\n /** Environment */\n environment: 'production' | 'sandbox' | 'xcode'\n}\n\n/**\n * StoreKit 2 API for in-app purchases and subscriptions.\n *\n * @example\n * // Load products\n * const products = await storeKit.getProducts(['premium_monthly', 'premium_yearly'])\n *\n * // Purchase a product\n * const result = await storeKit.purchase(products[0].id)\n * if (result.success) {\n * console.log('Purchase successful!')\n * }\n *\n * // Check entitlements\n * const hasAccess = await storeKit.isEntitled('premium')\n */\nexport const storeKit = {\n /**\n * Get products by identifiers.\n */\n async getProducts(productIds: string[]): Promise<Product[]> {\n if (!isCraft() || getPlatform() !== 'ios') return []\n return (window as any).craft?.storeKit?.getProducts?.(productIds) ?? []\n },\n\n /**\n * Purchase a product.\n */\n async purchase(productId: string, options?: {\n quantity?: number\n appAccountToken?: string\n simulatesAskToBuyInSandbox?: boolean\n }): Promise<{ success: boolean; transaction?: Transaction; error?: string }> {\n if (!isCraft() || getPlatform() !== 'ios') {\n return { success: false, error: 'StoreKit not available' }\n }\n return (window as any).craft?.storeKit?.purchase?.(productId, options) ?? { success: false }\n },\n\n /**\n * Check if user is entitled to a product/feature.\n */\n async isEntitled(productId: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.storeKit?.isEntitled?.(productId) ?? false\n },\n\n /**\n * Get current entitlements.\n */\n async getCurrentEntitlements(): Promise<Transaction[]> {\n if (!isCraft() || getPlatform() !== 'ios') return []\n return (window as any).craft?.storeKit?.getCurrentEntitlements?.() ?? []\n },\n\n /**\n * Get transaction history.\n */\n async getTransactionHistory(productId?: string): Promise<Transaction[]> {\n if (!isCraft() || getPlatform() !== 'ios') return []\n return (window as any).craft?.storeKit?.getTransactionHistory?.(productId) ?? []\n },\n\n /**\n * Restore purchases.\n */\n async restorePurchases(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.storeKit?.restorePurchases?.()\n },\n\n /**\n * Finish a transaction (required after delivering content).\n */\n async finishTransaction(transactionId: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.storeKit?.finishTransaction?.(transactionId)\n },\n\n /**\n * Get subscription status.\n */\n async getSubscriptionStatus(groupId: string): Promise<{\n state: 'subscribed' | 'expired' | 'inBillingRetry' | 'inGracePeriod' | 'revoked'\n renewalInfo?: {\n willAutoRenew: boolean\n autoRenewProductId: string\n expirationIntent?: 'cancelled' | 'billingError' | 'priceIncrease' | 'productNotAvailable'\n }\n } | null> {\n if (!isCraft() || getPlatform() !== 'ios') return null\n return (window as any).craft?.storeKit?.getSubscriptionStatus?.(groupId)\n },\n\n /**\n * Present offer code redemption sheet.\n */\n async presentOfferCodeRedemption(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.storeKit?.presentOfferCodeRedemption?.()\n },\n\n /**\n * Present manage subscriptions sheet.\n */\n async presentManageSubscriptions(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.storeKit?.presentManageSubscriptions?.()\n },\n\n /**\n * Present refund request sheet.\n */\n async beginRefundRequest(transactionId: string): Promise<'success' | 'userCancelled' | 'failed'> {\n if (!isCraft() || getPlatform() !== 'ios') return 'failed'\n return (window as any).craft?.storeKit?.beginRefundRequest?.(transactionId) ?? 'failed'\n },\n\n /**\n * Listen for transaction updates.\n */\n onTransactionUpdate(handler: (transaction: Transaction) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.storeKit?.onTransactionUpdate?.(handler)\n },\n\n /**\n * Show price consent sheet if needed.\n */\n async showPriceConsentIfNeeded(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.storeKit?.showPriceConsentIfNeeded?.()\n }\n}\n\n// ============================================================================\n// App Intents (Siri Shortcuts)\n// ============================================================================\n\n/**\n * App Intent parameter type.\n */\nexport type IntentParameterType = 'string' | 'integer' | 'double' | 'boolean' | 'date' | 'url' | 'enum'\n\n/**\n * App Intent parameter definition.\n */\nexport interface IntentParameter {\n /** Parameter name */\n name: string\n /** Parameter type */\n type: IntentParameterType\n /** Display title */\n title: string\n /** Description */\n description?: string\n /** Whether required */\n required?: boolean\n /** Default value */\n defaultValue?: any\n /** Enum values (for enum type) */\n enumValues?: Array<{ value: string; displayName: string }>\n}\n\n/**\n * App Intent definition.\n */\nexport interface AppIntent {\n /** Intent identifier */\n id: string\n /** Display title */\n title: string\n /** Description */\n description: string\n /** Parameters */\n parameters?: IntentParameter[]\n /** Suggested invocation phrase */\n suggestedInvocationPhrase?: string\n}\n\n/**\n * App Intents API for Siri Shortcuts and Spotlight.\n *\n * @example\n * // Register an intent\n * appIntents.register({\n * id: 'com.myapp.order-coffee',\n * title: 'Order Coffee',\n * description: 'Order your favorite coffee',\n * parameters: [\n * { name: 'size', type: 'enum', title: 'Size', enumValues: [\n * { value: 'small', displayName: 'Small' },\n * { value: 'medium', displayName: 'Medium' },\n * { value: 'large', displayName: 'Large' }\n * ]}\n * ],\n * suggestedInvocationPhrase: 'Order my coffee'\n * })\n *\n * // Handle intent execution\n * appIntents.onPerform('com.myapp.order-coffee', async (params) => {\n * await orderCoffee(params.size)\n * return { success: true, message: 'Coffee ordered!' }\n * })\n */\nexport const appIntents = {\n /**\n * Register an App Intent.\n */\n register(intent: AppIntent): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.appIntents?.register?.(intent)\n },\n\n /**\n * Unregister an App Intent.\n */\n unregister(intentId: string): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.appIntents?.unregister?.(intentId)\n },\n\n /**\n * Register intent execution handler.\n */\n onPerform(\n intentId: string,\n handler: (parameters: Record<string, any>) => Promise<{ success: boolean; message?: string; value?: any }>\n ): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.appIntents?.onPerform?.(intentId, handler)\n },\n\n /**\n * Donate an intent for Siri suggestions.\n */\n async donate(intentId: string, parameters?: Record<string, any>): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.appIntents?.donate?.(intentId, parameters)\n },\n\n /**\n * Delete donated intents.\n */\n async deleteDonations(intentId?: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.appIntents?.deleteDonations?.(intentId)\n },\n\n /**\n * Update Spotlight index for intent.\n */\n async updateSpotlightIndex(intentId: string, searchableItems: Array<{\n uniqueIdentifier: string\n title: string\n contentDescription?: string\n keywords?: string[]\n thumbnailUrl?: string\n }>): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.appIntents?.updateSpotlightIndex?.(intentId, searchableItems)\n }\n}\n\n// ============================================================================\n// TipKit\n// ============================================================================\n\n/**\n * Tip display frequency.\n */\nexport type TipDisplayFrequency = 'immediate' | 'hourly' | 'daily' | 'weekly' | 'monthly'\n\n/**\n * Tip configuration.\n */\nexport interface Tip {\n /** Tip identifier */\n id: string\n /** Title */\n title: string\n /** Message */\n message: string\n /** Image name (SF Symbol or asset) */\n image?: string\n /** Action buttons */\n actions?: Array<{\n id: string\n title: string\n }>\n /** Display rules */\n rules?: {\n /** Show after event count */\n eventCount?: { event: string; count: number }\n /** Show after duration */\n duration?: { seconds: number }\n /** Parameter-based conditions */\n parameters?: Record<string, any>\n }\n /** Display options */\n options?: {\n /** Maximum display count */\n maxDisplayCount?: number\n /** Ignore display frequency */\n ignoreDisplayFrequency?: boolean\n }\n}\n\n/**\n * TipKit API for contextual hints and feature discovery.\n *\n * @example\n * // Configure TipKit\n * await tipKit.configure({ displayFrequency: 'daily' })\n *\n * // Register a tip\n * tipKit.register({\n * id: 'new-feature-tip',\n * title: 'New Feature!',\n * message: 'Try our new sharing feature',\n * image: 'square.and.arrow.up',\n * rules: {\n * eventCount: { event: 'app-opened', count: 3 }\n * }\n * })\n *\n * // Track events for tip rules\n * tipKit.trackEvent('app-opened')\n *\n * // Show tip inline\n * const shouldShow = await tipKit.shouldShow('new-feature-tip')\n */\nexport const tipKit = {\n /**\n * Configure TipKit.\n */\n async configure(options: {\n displayFrequency?: TipDisplayFrequency\n datastoreLocation?: 'applicationDefault' | 'groupContainer'\n }): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.tipKit?.configure?.(options)\n },\n\n /**\n * Register a tip.\n */\n register(tip: Tip): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.tipKit?.register?.(tip)\n },\n\n /**\n * Check if a tip should be displayed.\n */\n async shouldShow(tipId: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.tipKit?.shouldShow?.(tipId) ?? false\n },\n\n /**\n * Invalidate a tip (permanently hide).\n */\n async invalidate(tipId: string, reason?: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.tipKit?.invalidate?.(tipId, reason)\n },\n\n /**\n * Track an event for tip rules.\n */\n async trackEvent(eventId: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.tipKit?.trackEvent?.(eventId)\n },\n\n /**\n * Set a parameter value for tip rules.\n */\n async setParameter(name: string, value: any): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.tipKit?.setParameter?.(name, value)\n },\n\n /**\n * Show a tip as a popover.\n */\n async showPopover(tipId: string, sourceElement: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.tipKit?.showPopover?.(tipId, sourceElement)\n },\n\n /**\n * Register tip action handler.\n */\n onAction(tipId: string, handler: (actionId: string) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.tipKit?.onAction?.(tipId, handler)\n },\n\n /**\n * Reset all tips (for testing).\n */\n async resetDatastore(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'ios') return\n return (window as any).craft?.tipKit?.resetDatastore?.()\n }\n}\n\n// ============================================================================\n// Focus Filters\n// ============================================================================\n\n/**\n * Focus status.\n */\nexport interface FocusStatus {\n /** Whether Focus is active */\n isFocusActive: boolean\n /** Current Focus name (if authorized) */\n focusName?: string\n}\n\n/**\n * Focus filter configuration.\n */\nexport interface FocusFilter {\n /** Filter identifier */\n id: string\n /** Display name */\n name: string\n /** Description */\n description: string\n /** Filter parameters */\n parameters?: Array<{\n name: string\n type: 'boolean' | 'string' | 'selection'\n displayName: string\n options?: string[]\n }>\n}\n\n/**\n * Focus Filters API for Focus mode integration.\n *\n * @example\n * // Register a focus filter\n * focusFilters.register({\n * id: 'work-mode',\n * name: 'Work Mode',\n * description: 'Show only work-related content',\n * parameters: [\n * { name: 'showNotifications', type: 'boolean', displayName: 'Show Notifications' }\n * ]\n * })\n *\n * // Handle filter changes\n * focusFilters.onFilterChange((filterSettings) => {\n * if (filterSettings.showNotifications === false) {\n * disableNotifications()\n * }\n * })\n */\nexport const focusFilters = {\n /**\n * Check Focus authorization status.\n */\n async getAuthorizationStatus(): Promise<'notDetermined' | 'denied' | 'authorized'> {\n if (!isCraft() || getPlatform() !== 'ios') return 'notDetermined'\n return (window as any).craft?.focusFilters?.getAuthorizationStatus?.() ?? 'notDetermined'\n },\n\n /**\n * Request Focus authorization.\n */\n async requestAuthorization(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'ios') return false\n return (window as any).craft?.focusFilters?.requestAuthorization?.() ?? false\n },\n\n /**\n * Get current Focus status.\n */\n async getFocusStatus(): Promise<FocusStatus> {\n if (!isCraft() || getPlatform() !== 'ios') {\n return { isFocusActive: false }\n }\n return (window as any).craft?.focusFilters?.getFocusStatus?.() ?? { isFocusActive: false }\n },\n\n /**\n * Register a Focus filter.\n */\n register(filter: FocusFilter): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.focusFilters?.register?.(filter)\n },\n\n /**\n * Get current filter settings.\n */\n async getCurrentFilterSettings(): Promise<Record<string, any> | null> {\n if (!isCraft() || getPlatform() !== 'ios') return null\n return (window as any).craft?.focusFilters?.getCurrentFilterSettings?.()\n },\n\n /**\n * Register Focus status change handler.\n */\n onFocusChange(handler: (status: FocusStatus) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.focusFilters?.onFocusChange?.(handler)\n },\n\n /**\n * Register filter settings change handler.\n */\n onFilterChange(handler: (settings: Record<string, any>) => void): void {\n if (!isCraft() || getPlatform() !== 'ios') return\n ;(window as any).craft?.focusFilters?.onFilterChange?.(handler)\n }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nconst iosAdvanced: {\n carplay: typeof carplay\n appClips: typeof appClips\n liveActivities: typeof liveActivities\n sharePlay: typeof sharePlay\n storeKit: typeof storeKit\n appIntents: typeof appIntents\n tipKit: typeof tipKit\n focusFilters: typeof focusFilters\n} = {\n carplay: carplay,\n appClips: appClips,\n liveActivities: liveActivities,\n sharePlay: sharePlay,\n storeKit: storeKit,\n appIntents: appIntents,\n tipKit: tipKit,\n focusFilters: focusFilters\n}\n\nexport default iosAdvanced\n",
|
|
25
|
+
"/**\n * @fileoverview Android Advanced Features API\n * @description Advanced Android-specific features including Jetpack Compose integration,\n * Material You dynamic colors, Photo Picker, Work Manager, Foreground Services, and more.\n * @module @craft-native/api/android-advanced\n */\n\nimport { isCraft, getPlatform } from './process'\n\n// ============================================================================\n// Material You / Dynamic Colors\n// ============================================================================\n\n/**\n * Material You color scheme.\n */\nexport interface MaterialYouColors {\n /** Primary color */\n primary: string\n /** On primary color */\n onPrimary: string\n /** Primary container */\n primaryContainer: string\n /** On primary container */\n onPrimaryContainer: string\n /** Secondary color */\n secondary: string\n /** On secondary */\n onSecondary: string\n /** Secondary container */\n secondaryContainer: string\n /** On secondary container */\n onSecondaryContainer: string\n /** Tertiary color */\n tertiary: string\n /** On tertiary */\n onTertiary: string\n /** Tertiary container */\n tertiaryContainer: string\n /** On tertiary container */\n onTertiaryContainer: string\n /** Error color */\n error: string\n /** On error */\n onError: string\n /** Error container */\n errorContainer: string\n /** On error container */\n onErrorContainer: string\n /** Background */\n background: string\n /** On background */\n onBackground: string\n /** Surface */\n surface: string\n /** On surface */\n onSurface: string\n /** Surface variant */\n surfaceVariant: string\n /** On surface variant */\n onSurfaceVariant: string\n /** Outline */\n outline: string\n /** Outline variant */\n outlineVariant: string\n}\n\n/**\n * Material You API for dynamic theming.\n *\n * @example\n * // Get current dynamic colors\n * const colors = await materialYou.getColors()\n * document.body.style.backgroundColor = colors.background\n *\n * // Listen for wallpaper changes\n * materialYou.onColorsChange((colors) => {\n * applyTheme(colors)\n * })\n */\nexport const materialYou = {\n /**\n * Check if Material You is supported.\n */\n async isSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.materialYou?.isSupported?.() ?? false\n },\n\n /**\n * Get current dynamic colors.\n */\n async getColors(darkMode = false): Promise<MaterialYouColors | null> {\n if (!isCraft() || getPlatform() !== 'android') return null\n return (window as any).craft?.materialYou?.getColors?.(darkMode)\n },\n\n /**\n * Get colors from a specific source.\n */\n async getColorsFromSource(source: 'wallpaper' | 'content'): Promise<MaterialYouColors | null> {\n if (!isCraft() || getPlatform() !== 'android') return null\n return (window as any).craft?.materialYou?.getColorsFromSource?.(source)\n },\n\n /**\n * Listen for color changes.\n */\n onColorsChange(handler: (colors: MaterialYouColors) => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.materialYou?.onColorsChange?.(handler)\n },\n\n /**\n * Apply dynamic colors to system bars.\n */\n async applyToSystemBars(colors?: {\n statusBarColor?: string\n navigationBarColor?: string\n lightStatusBar?: boolean\n lightNavigationBar?: boolean\n }): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.materialYou?.applyToSystemBars?.(colors)\n },\n\n /**\n * Generate color scheme from seed color.\n */\n async generateScheme(seedColor: string, darkMode = false): Promise<MaterialYouColors | null> {\n if (!isCraft() || getPlatform() !== 'android') return null\n return (window as any).craft?.materialYou?.generateScheme?.(seedColor, darkMode)\n }\n}\n\n// ============================================================================\n// Photo Picker (Android 13+)\n// ============================================================================\n\n/**\n * Photo picker media type.\n */\nexport type PhotoPickerMediaType = 'images' | 'videos' | 'all'\n\n/**\n * Selected media item.\n */\nexport interface PhotoPickerResult {\n /** Content URI */\n uri: string\n /** MIME type */\n mimeType: string\n /** File name */\n name: string\n /** File size in bytes */\n size: number\n /** Width (for images/videos) */\n width?: number\n /** Height (for images/videos) */\n height?: number\n /** Duration in ms (for videos) */\n duration?: number\n /** Date taken */\n dateTaken?: Date\n}\n\n/**\n * Photo Picker API for Android 13+ privacy-preserving media selection.\n *\n * @example\n * // Pick a single image\n * const photo = await photoPicker.pickImage()\n *\n * // Pick multiple images (up to 10)\n * const photos = await photoPicker.pickImages(10)\n *\n * // Pick a video\n * const video = await photoPicker.pickVideo()\n */\nexport const photoPicker = {\n /**\n * Check if Photo Picker is available (Android 13+).\n */\n async isAvailable(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.photoPicker?.isAvailable?.() ?? false\n },\n\n /**\n * Pick a single image.\n */\n async pickImage(): Promise<PhotoPickerResult | null> {\n if (!isCraft() || getPlatform() !== 'android') return null\n return (window as any).craft?.photoPicker?.pickImage?.()\n },\n\n /**\n * Pick multiple images.\n */\n async pickImages(maxCount = 10): Promise<PhotoPickerResult[]> {\n if (!isCraft() || getPlatform() !== 'android') return []\n return (window as any).craft?.photoPicker?.pickImages?.(maxCount) ?? []\n },\n\n /**\n * Pick a single video.\n */\n async pickVideo(): Promise<PhotoPickerResult | null> {\n if (!isCraft() || getPlatform() !== 'android') return null\n return (window as any).craft?.photoPicker?.pickVideo?.()\n },\n\n /**\n * Pick multiple videos.\n */\n async pickVideos(maxCount = 10): Promise<PhotoPickerResult[]> {\n if (!isCraft() || getPlatform() !== 'android') return []\n return (window as any).craft?.photoPicker?.pickVideos?.(maxCount) ?? []\n },\n\n /**\n * Pick mixed media (images and videos).\n */\n async pickMedia(options?: {\n maxCount?: number\n mediaType?: PhotoPickerMediaType\n }): Promise<PhotoPickerResult[]> {\n if (!isCraft() || getPlatform() !== 'android') return []\n return (window as any).craft?.photoPicker?.pickMedia?.(options) ?? []\n },\n\n /**\n * Get a persistent URI for the selected media.\n * Takes a content URI and returns a file path that can be used after app restart.\n */\n async getPersistedUri(uri: string): Promise<string | null> {\n if (!isCraft() || getPlatform() !== 'android') return null\n return (window as any).craft?.photoPicker?.getPersistedUri?.(uri)\n }\n}\n\n// ============================================================================\n// Work Manager\n// ============================================================================\n\n/**\n * Work request constraints.\n */\nexport interface WorkConstraints {\n /** Require network connectivity */\n requiresNetwork?: 'connected' | 'unmetered' | 'not_roaming' | 'metered'\n /** Require charging */\n requiresCharging?: boolean\n /** Require device idle */\n requiresDeviceIdle?: boolean\n /** Require battery not low */\n requiresBatteryNotLow?: boolean\n /** Require storage not low */\n requiresStorageNotLow?: boolean\n}\n\n/**\n * Work request configuration.\n */\nexport interface WorkRequest {\n /** Unique work name */\n name: string\n /** Work type */\n type: 'oneTime' | 'periodic'\n /** Input data */\n inputData?: Record<string, string | number | boolean>\n /** Constraints */\n constraints?: WorkConstraints\n /** Initial delay in milliseconds */\n initialDelay?: number\n /** Repeat interval in milliseconds (for periodic work) */\n repeatInterval?: number\n /** Flex interval in milliseconds (for periodic work) */\n flexInterval?: number\n /** Backoff policy */\n backoffPolicy?: {\n policy: 'linear' | 'exponential'\n delayMs: number\n }\n /** Tags for grouping */\n tags?: string[]\n /** Expedited work (Android 12+) */\n expedited?: boolean\n}\n\n/**\n * Work info.\n */\nexport interface WorkInfo {\n /** Work ID */\n id: string\n /** Work name */\n name: string\n /** Current state */\n state: 'enqueued' | 'running' | 'succeeded' | 'failed' | 'blocked' | 'cancelled'\n /** Output data */\n outputData?: Record<string, any>\n /** Run attempt count */\n runAttemptCount: number\n /** Tags */\n tags: string[]\n /** Progress (0-100) */\n progress?: number\n}\n\n/**\n * Work Manager API for background task scheduling.\n *\n * @example\n * // Schedule a one-time sync task\n * await workManager.enqueue({\n * name: 'sync-data',\n * type: 'oneTime',\n * constraints: {\n * requiresNetwork: 'connected'\n * },\n * inputData: { userId: '123' }\n * })\n *\n * // Schedule periodic cleanup\n * await workManager.enqueue({\n * name: 'cleanup',\n * type: 'periodic',\n * repeatInterval: 24 * 60 * 60 * 1000, // Daily\n * constraints: {\n * requiresCharging: true,\n * requiresDeviceIdle: true\n * }\n * })\n *\n * // Monitor work progress\n * workManager.observeWork('sync-data', (info) => {\n * console.log('State:', info.state, 'Progress:', info.progress)\n * })\n */\nexport const workManager = {\n /**\n * Enqueue a work request.\n */\n async enqueue(request: WorkRequest): Promise<string> {\n if (!isCraft() || getPlatform() !== 'android') {\n return `mock-${Date.now()}`\n }\n return (window as any).craft?.workManager?.enqueue?.(request) ?? `mock-${Date.now()}`\n },\n\n /**\n * Enqueue unique work (replaces existing work with same name).\n */\n async enqueueUnique(\n request: WorkRequest,\n existingWorkPolicy: 'replace' | 'keep' | 'append' | 'update'\n ): Promise<string> {\n if (!isCraft() || getPlatform() !== 'android') {\n return `mock-${Date.now()}`\n }\n return (window as any).craft?.workManager?.enqueueUnique?.(request, existingWorkPolicy) ?? `mock-${Date.now()}`\n },\n\n /**\n * Cancel work by name.\n */\n async cancelByName(name: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.workManager?.cancelByName?.(name)\n },\n\n /**\n * Cancel work by ID.\n */\n async cancelById(id: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.workManager?.cancelById?.(id)\n },\n\n /**\n * Cancel work by tag.\n */\n async cancelByTag(tag: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.workManager?.cancelByTag?.(tag)\n },\n\n /**\n * Cancel all work.\n */\n async cancelAll(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.workManager?.cancelAll?.()\n },\n\n /**\n * Get work info by name.\n */\n async getWorkInfo(name: string): Promise<WorkInfo | null> {\n if (!isCraft() || getPlatform() !== 'android') return null\n return (window as any).craft?.workManager?.getWorkInfo?.(name)\n },\n\n /**\n * Get work info by ID.\n */\n async getWorkInfoById(id: string): Promise<WorkInfo | null> {\n if (!isCraft() || getPlatform() !== 'android') return null\n return (window as any).craft?.workManager?.getWorkInfoById?.(id)\n },\n\n /**\n * Get work info by tag.\n */\n async getWorkInfoByTag(tag: string): Promise<WorkInfo[]> {\n if (!isCraft() || getPlatform() !== 'android') return []\n return (window as any).craft?.workManager?.getWorkInfoByTag?.(tag) ?? []\n },\n\n /**\n * Observe work by name.\n */\n observeWork(name: string, handler: (info: WorkInfo) => void): () => void {\n if (!isCraft() || getPlatform() !== 'android') return () => {}\n return (window as any).craft?.workManager?.observeWork?.(name, handler) ?? (() => {})\n },\n\n /**\n * Prune finished work from database.\n */\n async pruneWork(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.workManager?.pruneWork?.()\n },\n\n /**\n * Register work handler (called when work executes).\n */\n onWork(name: string, handler: (\n inputData: Record<string, any>,\n setProgress: (progress: number) => void\n ) => Promise<{ success: boolean; outputData?: Record<string, any> }>): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.workManager?.onWork?.(name, handler)\n }\n}\n\n// ============================================================================\n// Foreground Services\n// ============================================================================\n\n/**\n * Foreground service type.\n */\nexport type ForegroundServiceType =\n | 'camera'\n | 'connectedDevice'\n | 'dataSync'\n | 'health'\n | 'location'\n | 'mediaPlayback'\n | 'mediaProjection'\n | 'microphone'\n | 'phoneCall'\n | 'remoteMessaging'\n | 'shortService'\n | 'specialUse'\n | 'systemExempted'\n\n/**\n * Notification configuration for foreground service.\n */\nexport interface ForegroundNotification {\n /** Notification channel ID */\n channelId: string\n /** Notification ID */\n notificationId: number\n /** Title */\n title: string\n /** Content text */\n content: string\n /** Small icon resource name */\n smallIcon: string\n /** Large icon URL */\n largeIcon?: string\n /** Ongoing (can't be dismissed) */\n ongoing?: boolean\n /** Actions */\n actions?: Array<{\n id: string\n title: string\n icon?: string\n }>\n /** Progress (for determinate progress) */\n progress?: {\n max: number\n current: number\n indeterminate?: boolean\n }\n}\n\n/**\n * Foreground Services API for long-running operations.\n *\n * @example\n * // Start a media playback service\n * await foregroundService.start({\n * type: 'mediaPlayback',\n * notification: {\n * channelId: 'playback',\n * notificationId: 1,\n * title: 'Now Playing',\n * content: 'Song Name - Artist',\n * smallIcon: 'ic_music_note',\n * actions: [\n * { id: 'pause', title: 'Pause', icon: 'ic_pause' },\n * { id: 'next', title: 'Next', icon: 'ic_skip_next' }\n * ]\n * }\n * })\n *\n * // Handle notification actions\n * foregroundService.onAction((actionId) => {\n * if (actionId === 'pause') pausePlayback()\n * })\n *\n * // Stop the service\n * await foregroundService.stop()\n */\nexport const foregroundService = {\n /**\n * Start a foreground service.\n */\n async start(config: {\n type: ForegroundServiceType\n notification: ForegroundNotification\n }): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.foregroundService?.start?.(config)\n },\n\n /**\n * Stop the foreground service.\n */\n async stop(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.foregroundService?.stop?.()\n },\n\n /**\n * Update notification.\n */\n async updateNotification(notification: Partial<ForegroundNotification>): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.foregroundService?.updateNotification?.(notification)\n },\n\n /**\n * Check if service is running.\n */\n async isRunning(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.foregroundService?.isRunning?.() ?? false\n },\n\n /**\n * Register notification action handler.\n */\n onAction(handler: (actionId: string) => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.foregroundService?.onAction?.(handler)\n }\n}\n\n// ============================================================================\n// Predictive Back Gesture\n// ============================================================================\n\n/**\n * Back event info.\n */\nexport interface BackEvent {\n /** Touch X position */\n touchX: number\n /** Touch Y position */\n touchY: number\n /** Progress of the back gesture (0-1) */\n progress: number\n /** Swipe edge: 0 = left, 1 = right */\n swipeEdge: 0 | 1\n}\n\n/**\n * Predictive Back API for Android 13+ back gesture handling.\n *\n * @example\n * // Enable predictive back\n * predictiveBack.enable()\n *\n * // Handle back progress for animations\n * predictiveBack.onProgress((event) => {\n * // Animate UI based on progress\n * element.style.transform = `translateX(${event.progress * -100}px)`\n * })\n *\n * // Handle back committed\n * predictiveBack.onCommit(() => {\n * navigateBack()\n * })\n */\nexport const predictiveBack = {\n /**\n * Check if predictive back is supported.\n */\n async isSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.predictiveBack?.isSupported?.() ?? false\n },\n\n /**\n * Enable predictive back handling.\n */\n enable(): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.predictiveBack?.enable?.()\n },\n\n /**\n * Disable predictive back handling.\n */\n disable(): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.predictiveBack?.disable?.()\n },\n\n /**\n * Register back started handler.\n */\n onStart(handler: (event: BackEvent) => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.predictiveBack?.onStart?.(handler)\n },\n\n /**\n * Register back progress handler.\n */\n onProgress(handler: (event: BackEvent) => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.predictiveBack?.onProgress?.(handler)\n },\n\n /**\n * Register back committed handler.\n */\n onCommit(handler: () => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.predictiveBack?.onCommit?.()\n },\n\n /**\n * Register back cancelled handler.\n */\n onCancel(handler: () => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.predictiveBack?.onCancel?.(handler)\n }\n}\n\n// ============================================================================\n// Per-App Language Preferences\n// ============================================================================\n\n/**\n * Language Preferences API for per-app language settings (Android 13+).\n *\n * @example\n * // Get available languages\n * const languages = await appLanguage.getAvailableLanguages()\n *\n * // Set app language\n * await appLanguage.setLanguage('es')\n *\n * // Get current language\n * const current = await appLanguage.getCurrentLanguage()\n */\nexport const appLanguage = {\n /**\n * Check if per-app language is supported.\n */\n async isSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.appLanguage?.isSupported?.() ?? false\n },\n\n /**\n * Get available languages defined in app.\n */\n async getAvailableLanguages(): Promise<string[]> {\n if (!isCraft() || getPlatform() !== 'android') return []\n return (window as any).craft?.appLanguage?.getAvailableLanguages?.() ?? []\n },\n\n /**\n * Get current app language.\n */\n async getCurrentLanguage(): Promise<string | null> {\n if (!isCraft() || getPlatform() !== 'android') return null\n return (window as any).craft?.appLanguage?.getCurrentLanguage?.()\n },\n\n /**\n * Set app language.\n */\n async setLanguage(languageTag: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.appLanguage?.setLanguage?.(languageTag)\n },\n\n /**\n * Reset to system language.\n */\n async resetToSystem(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.appLanguage?.resetToSystem?.()\n },\n\n /**\n * Open system language settings for this app.\n */\n async openSettings(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.appLanguage?.openSettings?.()\n }\n}\n\n// ============================================================================\n// App Widgets\n// ============================================================================\n\n/**\n * Widget size class.\n */\nexport type WidgetSizeClass = 'small' | 'medium' | 'large' | 'extraLarge'\n\n/**\n * Widget configuration.\n */\nexport interface WidgetConfig {\n /** Widget class name */\n widgetClass: string\n /** Minimum width in dp */\n minWidth: number\n /** Minimum height in dp */\n minHeight: number\n /** Target cell width */\n targetCellWidth?: number\n /** Target cell height */\n targetCellHeight?: number\n /** Maximum resize width */\n maxResizeWidth?: number\n /** Maximum resize height */\n maxResizeHeight?: number\n /** Update period in milliseconds (minimum 30 minutes) */\n updatePeriodMs?: number\n /** Whether widget is resizable */\n resizable?: boolean\n /** Widget category */\n category?: 'homeScreen' | 'keyguard' | 'searchBox'\n}\n\n/**\n * Widget data.\n */\nexport interface WidgetData {\n /** Widget ID */\n widgetId: number\n /** Widget data */\n data: Record<string, any>\n}\n\n/**\n * App Widgets API for home screen widgets.\n *\n * @example\n * // Update widget content\n * await widgets.updateWidget(widgetId, {\n * title: 'Weather',\n * temperature: '72°F',\n * icon: 'sunny'\n * })\n *\n * // Request widget pin\n * await widgets.requestPin('WeatherWidget')\n *\n * // Handle widget interactions\n * widgets.onInteraction((_widgetId, action) => {\n * if (action === 'refresh') {\n * refreshWeatherData()\n * }\n * })\n */\nexport const widgets = {\n /**\n * Get all active widget IDs for a widget class.\n */\n async getActiveWidgets(widgetClass: string): Promise<number[]> {\n if (!isCraft() || getPlatform() !== 'android') return []\n return (window as any).craft?.widgets?.getActiveWidgets?.(widgetClass) ?? []\n },\n\n /**\n * Update a widget.\n */\n async updateWidget(widgetId: number, data: Record<string, any>): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.widgets?.updateWidget?.(widgetId, data)\n },\n\n /**\n * Update all widgets of a class.\n */\n async updateAllWidgets(widgetClass: string, data: Record<string, any>): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.widgets?.updateAllWidgets?.(widgetClass, data)\n },\n\n /**\n * Request to pin a widget to home screen.\n */\n async requestPin(widgetClass: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.widgets?.requestPin?.(widgetClass) ?? false\n },\n\n /**\n * Check if app widgets are supported.\n */\n async isSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.widgets?.isSupported?.() ?? false\n },\n\n /**\n * Register widget update handler.\n */\n onUpdate(widgetClass: string, handler: (widgetIds: number[]) => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.widgets?.onUpdate?.(widgetClass, handler)\n },\n\n /**\n * Register widget interaction handler.\n */\n onInteraction(handler: (widgetId: number, action: string, extras?: Record<string, any>) => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.widgets?.onInteraction?.(handler)\n },\n\n /**\n * Register widget resize handler.\n */\n onResize(handler: (widgetId: number, width: number, height: number) => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.widgets?.onResize?.(handler)\n },\n\n /**\n * Register widget delete handler.\n */\n onDelete(handler: (widgetId: number) => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.widgets?.onDelete?.(handler)\n }\n}\n\n// ============================================================================\n// Google Play Billing\n// ============================================================================\n\n/**\n * Product details from Google Play.\n */\nexport interface PlayProduct {\n /** Product ID */\n productId: string\n /** Product type */\n productType: 'inapp' | 'subs'\n /** Title */\n title: string\n /** Name */\n name: string\n /** Description */\n description: string\n /** One-time purchase offer (for inapp) */\n oneTimePurchaseOfferDetails?: {\n formattedPrice: string\n priceAmountMicros: number\n priceCurrencyCode: string\n }\n /** Subscription offer details (for subs) */\n subscriptionOfferDetails?: Array<{\n offerId: string\n basePlanId: string\n offerTags: string[]\n pricingPhases: Array<{\n formattedPrice: string\n priceAmountMicros: number\n priceCurrencyCode: string\n billingPeriod: string\n billingCycleCount: number\n recurrenceMode: 'infinite' | 'finite' | 'nonRecurring'\n }>\n }>\n}\n\n/**\n * Purchase result.\n */\nexport interface PlayPurchase {\n /** Order ID */\n orderId: string\n /** Package name */\n packageName: string\n /** Product IDs */\n products: string[]\n /** Purchase time */\n purchaseTime: number\n /** Purchase state */\n purchaseState: 'purchased' | 'pending' | 'unspecified'\n /** Purchase token */\n purchaseToken: string\n /** Whether acknowledged */\n isAcknowledged: boolean\n /** Whether auto-renewing */\n isAutoRenewing: boolean\n}\n\n/**\n * Google Play Billing API.\n *\n * @example\n * // Query products\n * const products = await playBilling.getProducts(['premium', 'coins_100'], 'inapp')\n *\n * // Launch purchase flow\n * const result = await playBilling.purchase('premium')\n *\n * // Check purchases\n * const purchases = await playBilling.getPurchases('inapp')\n */\nexport const playBilling = {\n /**\n * Connect to billing service.\n */\n async connect(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.playBilling?.connect?.() ?? false\n },\n\n /**\n * Disconnect from billing service.\n */\n async disconnect(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.playBilling?.disconnect?.()\n },\n\n /**\n * Query product details.\n */\n async getProducts(productIds: string[], productType: 'inapp' | 'subs'): Promise<PlayProduct[]> {\n if (!isCraft() || getPlatform() !== 'android') return []\n return (window as any).craft?.playBilling?.getProducts?.(productIds, productType) ?? []\n },\n\n /**\n * Launch purchase flow.\n */\n async purchase(productId: string, options?: {\n offerToken?: string\n isOfferPersonalized?: boolean\n oldPurchaseToken?: string\n replacementMode?: 'charge_prorated_price' | 'charge_full_price' | 'without_proration' | 'deferred'\n }): Promise<{ success: boolean; purchase?: PlayPurchase; error?: string }> {\n if (!isCraft() || getPlatform() !== 'android') {\n return { success: false, error: 'Play Billing not available' }\n }\n return (window as any).craft?.playBilling?.purchase?.(productId, options) ?? { success: false }\n },\n\n /**\n * Get purchases.\n */\n async getPurchases(productType: 'inapp' | 'subs'): Promise<PlayPurchase[]> {\n if (!isCraft() || getPlatform() !== 'android') return []\n return (window as any).craft?.playBilling?.getPurchases?.(productType) ?? []\n },\n\n /**\n * Acknowledge a purchase.\n */\n async acknowledgePurchase(purchaseToken: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.playBilling?.acknowledgePurchase?.(purchaseToken) ?? false\n },\n\n /**\n * Consume a purchase (for consumables).\n */\n async consumePurchase(purchaseToken: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.playBilling?.consumePurchase?.(purchaseToken) ?? false\n },\n\n /**\n * Check subscription status.\n */\n async isSubscribed(productId: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'android') return false\n return (window as any).craft?.playBilling?.isSubscribed?.(productId) ?? false\n },\n\n /**\n * Listen for purchases updates.\n */\n onPurchasesUpdated(handler: (purchases: PlayPurchase[]) => void): void {\n if (!isCraft() || getPlatform() !== 'android') return\n ;(window as any).craft?.playBilling?.onPurchasesUpdated?.(handler)\n },\n\n /**\n * Show subscription management.\n */\n async showSubscriptionManagement(productId?: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'android') return\n return (window as any).craft?.playBilling?.showSubscriptionManagement?.(productId)\n }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nconst androidAdvanced: {\n materialYou: typeof materialYou\n photoPicker: typeof photoPicker\n workManager: typeof workManager\n foregroundService: typeof foregroundService\n predictiveBack: typeof predictiveBack\n appLanguage: typeof appLanguage\n widgets: typeof widgets\n playBilling: typeof playBilling\n} = {\n materialYou: materialYou,\n photoPicker: photoPicker,\n workManager: workManager,\n foregroundService: foregroundService,\n predictiveBack: predictiveBack,\n appLanguage: appLanguage,\n widgets: widgets,\n playBilling: playBilling\n}\n\nexport default androidAdvanced\n",
|
|
26
|
+
"/**\n * @fileoverview macOS Advanced Features API\n * @description Advanced macOS-specific features including Touch Bar, Desktop Widgets,\n * Stage Manager, Handoff/Continuity, Sidecar, and system integration.\n * @module @craft-native/api/macos-advanced\n */\n\nimport { isCraft, getPlatform } from './process'\n\n// ============================================================================\n// Touch Bar\n// ============================================================================\n\n/**\n * Touch Bar item types.\n */\nexport type TouchBarItemType =\n | 'button'\n | 'label'\n | 'slider'\n | 'popover'\n | 'colorPicker'\n | 'scrubber'\n | 'segmentedControl'\n | 'spacer'\n | 'group'\n\n/**\n * Touch Bar button item.\n */\nexport interface TouchBarButton {\n type: 'button'\n id: string\n label?: string\n icon?: string // SF Symbol name or image path\n backgroundColor?: string\n accessibilityLabel?: string\n}\n\n/**\n * Touch Bar label item.\n */\nexport interface TouchBarLabel {\n type: 'label'\n id: string\n label: string\n textColor?: string\n accessibilityLabel?: string\n}\n\n/**\n * Touch Bar slider item.\n */\nexport interface TouchBarSlider {\n type: 'slider'\n id: string\n label?: string\n minValue: number\n maxValue: number\n value: number\n minAccessoryIcon?: string\n maxAccessoryIcon?: string\n}\n\n/**\n * Touch Bar color picker item.\n */\nexport interface TouchBarColorPicker {\n type: 'colorPicker'\n id: string\n selectedColor?: string\n availableColors?: string[]\n}\n\n/**\n * Touch Bar scrubber item.\n */\nexport interface TouchBarScrubber {\n type: 'scrubber'\n id: string\n items: Array<{ label?: string; icon?: string }>\n selectedIndex?: number\n mode: 'fixed' | 'free'\n showsArrowButtons?: boolean\n}\n\n/**\n * Touch Bar segmented control.\n */\nexport interface TouchBarSegmentedControl {\n type: 'segmentedControl'\n id: string\n segments: Array<{ label?: string; icon?: string }>\n selectedIndex?: number\n segmentStyle?: 'automatic' | 'rounded' | 'separated'\n}\n\n/**\n * Touch Bar popover item.\n */\nexport interface TouchBarPopover {\n type: 'popover'\n id: string\n label?: string\n icon?: string\n items: TouchBarItem[]\n showCloseButton?: boolean\n}\n\n/**\n * Touch Bar spacer.\n */\nexport interface TouchBarSpacer {\n type: 'spacer'\n size: 'small' | 'large' | 'flexible'\n}\n\n/**\n * Touch Bar group.\n */\nexport interface TouchBarGroup {\n type: 'group'\n id: string\n items: TouchBarItem[]\n}\n\n/**\n * Touch Bar item union type.\n */\nexport type TouchBarItem =\n | TouchBarButton\n | TouchBarLabel\n | TouchBarSlider\n | TouchBarColorPicker\n | TouchBarScrubber\n | TouchBarSegmentedControl\n | TouchBarPopover\n | TouchBarSpacer\n | TouchBarGroup\n\n/**\n * Touch Bar API for MacBook Pro Touch Bar support.\n *\n * @example\n * // Create a Touch Bar\n * touchBar.set([\n * { type: 'button', id: 'play', icon: 'play.fill' },\n * { type: 'spacer', size: 'flexible' },\n * { type: 'slider', id: 'volume', minValue: 0, maxValue: 100, value: 50 },\n * { type: 'button', id: 'favorite', icon: 'heart.fill', backgroundColor: '#ff375f' }\n * ])\n *\n * // Handle interactions\n * touchBar.onTap('play', () => togglePlayback())\n * touchBar.onSliderChange('volume', (value) => setVolume(value))\n */\nexport const touchBar = {\n /**\n * Check if Touch Bar is available.\n */\n async isAvailable(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'macos') return false\n return (window as any).craft?.touchBar?.isAvailable?.() ?? false\n },\n\n /**\n * Set Touch Bar items.\n */\n set(items: TouchBarItem[]): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.touchBar?.set?.(items)\n },\n\n /**\n * Update a specific item.\n */\n updateItem(id: string, updates: Partial<TouchBarItem>): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.touchBar?.updateItem?.(id, updates)\n },\n\n /**\n * Clear Touch Bar.\n */\n clear(): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.touchBar?.clear?.()\n },\n\n /**\n * Register tap handler for button.\n */\n onTap(id: string, handler: () => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.touchBar?.onTap?.(id, handler)\n },\n\n /**\n * Register slider change handler.\n */\n onSliderChange(id: string, handler: (value: number) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.touchBar?.onSliderChange?.(id, handler)\n },\n\n /**\n * Register color picker change handler.\n */\n onColorChange(id: string, handler: (color: string) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.touchBar?.onColorChange?.(id, handler)\n },\n\n /**\n * Register scrubber selection handler.\n */\n onScrubberSelect(id: string, handler: (index: number) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.touchBar?.onScrubberSelect?.(id, handler)\n },\n\n /**\n * Register segment selection handler.\n */\n onSegmentSelect(id: string, handler: (index: number) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.touchBar?.onSegmentSelect?.(id, handler)\n },\n\n /**\n * Show/hide escape key.\n */\n setEscapeKeyVisible(visible: boolean): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.touchBar?.setEscapeKeyVisible?.(visible)\n }\n}\n\n// ============================================================================\n// Desktop Widgets (WidgetKit)\n// ============================================================================\n\n/**\n * Widget family (size).\n */\nexport type WidgetFamily = 'systemSmall' | 'systemMedium' | 'systemLarge' | 'systemExtraLarge'\n\n/**\n * Widget timeline entry.\n */\nexport interface WidgetTimelineEntry {\n /** Entry date */\n date: Date\n /** Widget content data */\n content: Record<string, any>\n /** Relevance score (0-1) */\n relevance?: number\n}\n\n/**\n * Widget configuration.\n */\nexport interface WidgetConfiguration {\n /** Widget kind identifier */\n kind: string\n /** Display name */\n displayName: string\n /** Description */\n description: string\n /** Supported families */\n supportedFamilies: WidgetFamily[]\n /** Configuration intent type (for configurable widgets) */\n configurationIntent?: string\n}\n\n/**\n * Desktop Widgets API for macOS widgets (WidgetKit).\n *\n * @example\n * // Register a widget\n * desktopWidgets.register({\n * kind: 'weather',\n * displayName: 'Weather',\n * description: 'Shows current weather',\n * supportedFamilies: ['systemSmall', 'systemMedium']\n * })\n *\n * // Provide timeline\n * desktopWidgets.provideTimeline('weather', async (_context) => {\n * const weather = await fetchWeather()\n * return {\n * entries: [\n * { date: new Date(), content: { temp: weather.temp, condition: weather.condition } }\n * ],\n * policy: { type: 'after', date: new Date(Date.now() + 3600000) }\n * }\n * })\n *\n * // Reload timeline\n * await desktopWidgets.reloadTimeline('weather')\n */\nexport const desktopWidgets = {\n /**\n * Check if widgets are supported.\n */\n async isSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'macos') return false\n return (window as any).craft?.desktopWidgets?.isSupported?.() ?? false\n },\n\n /**\n * Register a widget configuration.\n */\n register(config: WidgetConfiguration): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.desktopWidgets?.register?.(config)\n },\n\n /**\n * Provide timeline for a widget.\n */\n provideTimeline(\n kind: string,\n provider: (context: { family: WidgetFamily; isPreview: boolean }) => Promise<{\n entries: WidgetTimelineEntry[]\n policy: { type: 'atEnd' | 'never' | 'after'; date?: Date }\n }>\n ): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.desktopWidgets?.provideTimeline?.(kind, provider)\n },\n\n /**\n * Reload timeline for a widget.\n */\n async reloadTimeline(kind: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.desktopWidgets?.reloadTimeline?.(kind)\n },\n\n /**\n * Reload all timelines.\n */\n async reloadAllTimelines(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.desktopWidgets?.reloadAllTimelines?.()\n },\n\n /**\n * Get current widget configurations.\n */\n async getCurrentConfigurations(kind: string): Promise<Array<{\n widgetId: string\n family: WidgetFamily\n intent?: Record<string, any>\n }>> {\n if (!isCraft() || getPlatform() !== 'macos') return []\n return (window as any).craft?.desktopWidgets?.getCurrentConfigurations?.(kind) ?? []\n },\n\n /**\n * Handle widget URL.\n */\n onWidgetURL(kind: string, handler: (url: string, widgetFamily: WidgetFamily) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.desktopWidgets?.onWidgetURL?.(kind, handler)\n }\n}\n\n// ============================================================================\n// Stage Manager\n// ============================================================================\n\n/**\n * Stage Manager API for window organization.\n *\n * @example\n * // Check if Stage Manager is active\n * const isActive = await stageManager.isActive()\n *\n * // Create a window set (group)\n * await stageManager.createSet(['window1', 'window2'])\n *\n * // Listen for active set changes\n * stageManager.onActiveSetChange((windowIds) => {\n * console.log('Active set:', windowIds)\n * })\n */\nexport const stageManager = {\n /**\n * Check if Stage Manager is active.\n */\n async isActive(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'macos') return false\n return (window as any).craft?.stageManager?.isActive?.() ?? false\n },\n\n /**\n * Check if Stage Manager is available.\n */\n async isAvailable(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'macos') return false\n return (window as any).craft?.stageManager?.isAvailable?.() ?? false\n },\n\n /**\n * Get the current active window set.\n */\n async getActiveSet(): Promise<string[]> {\n if (!isCraft() || getPlatform() !== 'macos') return []\n return (window as any).craft?.stageManager?.getActiveSet?.() ?? []\n },\n\n /**\n * Create a window set.\n */\n async createSet(windowIds: string[]): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.stageManager?.createSet?.(windowIds)\n },\n\n /**\n * Add window to current set.\n */\n async addToCurrentSet(windowId: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.stageManager?.addToCurrentSet?.(windowId)\n },\n\n /**\n * Remove window from current set.\n */\n async removeFromCurrentSet(windowId: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.stageManager?.removeFromCurrentSet?.(windowId)\n },\n\n /**\n * Listen for active set changes.\n */\n onActiveSetChange(handler: (windowIds: string[]) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.stageManager?.onActiveSetChange?.(handler)\n },\n\n /**\n * Listen for Stage Manager enable/disable.\n */\n onStateChange(handler: (isActive: boolean) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.stageManager?.onStateChange?.(handler)\n }\n}\n\n// ============================================================================\n// Handoff / Continuity\n// ============================================================================\n\n/**\n * User activity for Handoff.\n */\nexport interface UserActivity {\n /** Activity type (reverse domain notation) */\n activityType: string\n /** Title shown to user */\n title: string\n /** User info dictionary */\n userInfo?: Record<string, any>\n /** Web page URL for Universal Links */\n webpageURL?: string\n /** Whether activity should be indexed */\n isEligibleForSearch?: boolean\n /** Whether activity should be handed off */\n isEligibleForHandoff?: boolean\n /** Whether activity supports public indexing */\n isEligibleForPublicIndexing?: boolean\n /** Keywords for search */\n keywords?: string[]\n /** Expiration date */\n expirationDate?: Date\n}\n\n/**\n * Handoff/Continuity API for cross-device experiences.\n *\n * @example\n * // Start an activity for Handoff\n * handoff.startActivity({\n * activityType: 'com.myapp.editing-document',\n * title: 'Editing: My Document',\n * userInfo: { documentId: '123', scrollPosition: 500 },\n * webpageURL: 'https://myapp.com/doc/123'\n * })\n *\n * // Handle continuing activity from another device\n * handoff.onContinue((activity) => {\n * openDocument(activity.userInfo.documentId)\n * scrollTo(activity.userInfo.scrollPosition)\n * })\n *\n * // Universal Clipboard\n * const hasRemoteContent = await handoff.hasRemoteClipboardContent()\n */\nexport const handoff = {\n /**\n * Start a user activity for Handoff.\n */\n startActivity(activity: UserActivity): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.handoff?.startActivity?.(activity)\n },\n\n /**\n * Update the current activity.\n */\n updateActivity(updates: Partial<UserActivity>): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.handoff?.updateActivity?.(updates)\n },\n\n /**\n * Invalidate (stop) the current activity.\n */\n invalidateActivity(): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.handoff?.invalidateActivity?.()\n },\n\n /**\n * Handle continuing an activity from another device.\n */\n onContinue(handler: (activity: UserActivity) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.handoff?.onContinue?.(handler)\n },\n\n /**\n * Check if there's content on remote clipboard (Universal Clipboard).\n */\n async hasRemoteClipboardContent(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'macos') return false\n return (window as any).craft?.handoff?.hasRemoteClipboardContent?.() ?? false\n },\n\n /**\n * Request AirDrop file transfer.\n */\n async shareViaAirDrop(filePaths: string[]): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'macos') return false\n return (window as any).craft?.handoff?.shareViaAirDrop?.(filePaths) ?? false\n },\n\n /**\n * Check if Handoff is available.\n */\n async isAvailable(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'macos') return false\n return (window as any).craft?.handoff?.isAvailable?.() ?? false\n }\n}\n\n// ============================================================================\n// Sidecar\n// ============================================================================\n\n/**\n * Sidecar device info.\n */\nexport interface SidecarDevice {\n /** Device identifier */\n id: string\n /** Device name */\n name: string\n /** Device model */\n model: string\n /** Whether currently connected */\n isConnected: boolean\n}\n\n/**\n * Sidecar API for iPad as second display.\n *\n * @example\n * // Get available Sidecar devices\n * const devices = await sidecar.getAvailableDevices()\n *\n * // Connect to a device\n * await sidecar.connect(devices[0].id)\n *\n * // Move window to Sidecar display\n * await sidecar.moveWindowToSidecar(windowId)\n */\nexport const sidecar = {\n /**\n * Check if Sidecar is available.\n */\n async isAvailable(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'macos') return false\n return (window as any).craft?.sidecar?.isAvailable?.() ?? false\n },\n\n /**\n * Get available Sidecar devices.\n */\n async getAvailableDevices(): Promise<SidecarDevice[]> {\n if (!isCraft() || getPlatform() !== 'macos') return []\n return (window as any).craft?.sidecar?.getAvailableDevices?.() ?? []\n },\n\n /**\n * Get currently connected device.\n */\n async getConnectedDevice(): Promise<SidecarDevice | null> {\n if (!isCraft() || getPlatform() !== 'macos') return null\n return (window as any).craft?.sidecar?.getConnectedDevice?.()\n },\n\n /**\n * Connect to a Sidecar device.\n */\n async connect(deviceId: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'macos') return false\n return (window as any).craft?.sidecar?.connect?.(deviceId) ?? false\n },\n\n /**\n * Disconnect from Sidecar.\n */\n async disconnect(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.sidecar?.disconnect?.()\n },\n\n /**\n * Move a window to the Sidecar display.\n */\n async moveWindowToSidecar(windowId: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.sidecar?.moveWindowToSidecar?.(windowId)\n },\n\n /**\n * Listen for connection changes.\n */\n onConnectionChange(handler: (device: SidecarDevice | null) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.sidecar?.onConnectionChange?.(handler)\n }\n}\n\n// ============================================================================\n// Spotlight Integration\n// ============================================================================\n\n/**\n * Spotlight searchable item.\n */\nexport interface SpotlightItem {\n /** Unique identifier */\n uniqueIdentifier: string\n /** Domain identifier (for grouping) */\n domainIdentifier?: string\n /** Display title */\n title: string\n /** Content description */\n contentDescription?: string\n /** Thumbnail URL or path */\n thumbnailURL?: string\n /** Keywords for search */\n keywords?: string[]\n /** Content type (UTI) */\n contentType?: string\n /** URL to open when selected */\n contentURL?: string\n /** Rating (0-5) */\n rating?: number\n /** Relative importance */\n rankingHint?: number\n}\n\n/**\n * Spotlight API for search integration.\n *\n * @example\n * // Index items for Spotlight\n * await spotlight.indexItems([\n * {\n * uniqueIdentifier: 'doc-123',\n * title: 'My Document',\n * contentDescription: 'Important notes about the project',\n * keywords: ['notes', 'project', 'important']\n * }\n * ])\n *\n * // Delete items from index\n * await spotlight.deleteItems(['doc-123'])\n *\n * // Handle Spotlight search result selection\n * spotlight.onContinueActivity((identifier) => {\n * openDocument(identifier)\n * })\n */\nexport const spotlight = {\n /**\n * Index items for Spotlight search.\n */\n async indexItems(items: SpotlightItem[]): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.spotlight?.indexItems?.(items)\n },\n\n /**\n * Delete items from Spotlight index.\n */\n async deleteItems(identifiers: string[]): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.spotlight?.deleteItems?.(identifiers)\n },\n\n /**\n * Delete all items in a domain.\n */\n async deleteItemsInDomain(domainIdentifier: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.spotlight?.deleteItemsInDomain?.(domainIdentifier)\n },\n\n /**\n * Delete all indexed items.\n */\n async deleteAllItems(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.spotlight?.deleteAllItems?.()\n },\n\n /**\n * Handle user selecting a Spotlight result.\n */\n onContinueActivity(handler: (identifier: string, userInfo?: Record<string, any>) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.spotlight?.onContinueActivity?.(handler)\n },\n\n /**\n * Check indexing status.\n */\n async getIndexingStatus(): Promise<{\n isIndexing: boolean\n itemCount: number\n }> {\n if (!isCraft() || getPlatform() !== 'macos') {\n return { isIndexing: false, itemCount: 0 }\n }\n return (window as any).craft?.spotlight?.getIndexingStatus?.() ?? { isIndexing: false, itemCount: 0 }\n }\n}\n\n// ============================================================================\n// Quick Actions (Services Menu)\n// ============================================================================\n\n/**\n * Quick Action definition.\n */\nexport interface QuickAction {\n /** Action identifier */\n id: string\n /** Display title */\n title: string\n /** Icon (SF Symbol or path) */\n icon?: string\n /** Input types this action accepts */\n inputTypes: Array<'text' | 'url' | 'file' | 'image'>\n}\n\n/**\n * Quick Actions API for Services menu integration.\n *\n * @example\n * // Register a quick action\n * quickActions.register({\n * id: 'summarize-text',\n * title: 'Summarize with MyApp',\n * icon: 'text.alignleft',\n * inputTypes: ['text']\n * })\n *\n * // Handle quick action invocation\n * quickActions.onInvoke('summarize-text', async (input) => {\n * const summary = await summarize(input.text)\n * return { result: summary }\n * })\n */\nexport const quickActions = {\n /**\n * Register a quick action.\n */\n register(action: QuickAction): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.quickActions?.register?.(action)\n },\n\n /**\n * Unregister a quick action.\n */\n unregister(actionId: string): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.quickActions?.unregister?.(actionId)\n },\n\n /**\n * Handle quick action invocation.\n */\n onInvoke(\n actionId: string,\n handler: (input: {\n text?: string\n url?: string\n filePaths?: string[]\n }) => Promise<{ result?: string; error?: string }>\n ): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.quickActions?.onInvoke?.(actionId, handler)\n }\n}\n\n// ============================================================================\n// Share Extensions\n// ============================================================================\n\n/**\n * Share Extension API.\n *\n * @example\n * // Handle share extension invocation\n * shareExtension.onReceive((items) => {\n * for (const item of items) {\n * if (item.type === 'url') {\n * saveBookmark(item.url)\n * }\n * }\n * })\n */\nexport const shareExtension = {\n /**\n * Handle receiving shared items.\n */\n onReceive(handler: (items: Array<{\n type: 'text' | 'url' | 'image' | 'file'\n text?: string\n url?: string\n filePath?: string\n mimeType?: string\n }>) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.shareExtension?.onReceive?.(handler)\n },\n\n /**\n * Complete the share action.\n */\n async complete(success = true): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.shareExtension?.complete?.(success)\n },\n\n /**\n * Cancel the share action.\n */\n async cancel(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.shareExtension?.cancel?.()\n }\n}\n\n// ============================================================================\n// Window Management\n// ============================================================================\n\n/**\n * Window tab group.\n */\nexport interface WindowTabGroup {\n /** Tab group identifier */\n id: string\n /** Windows in this group */\n windowIds: string[]\n /** Active window index */\n activeIndex: number\n}\n\n/**\n * Advanced Window Management API.\n *\n * @example\n * // Enable native tabs\n * windowManagement.enableTabs()\n *\n * // Create a new tab\n * await windowManagement.newTab()\n *\n * // Enter full screen\n * await windowManagement.enterFullScreen()\n *\n * // Set up split view\n * await windowManagement.createSplitView(window1Id, window2Id)\n */\nexport const windowManagement = {\n /**\n * Enable native window tabs.\n */\n enableTabs(): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.windowManagement?.enableTabs?.()\n },\n\n /**\n * Disable native window tabs.\n */\n disableTabs(): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.windowManagement?.disableTabs?.()\n },\n\n /**\n * Create a new tab.\n */\n async newTab(url?: string): Promise<string> {\n if (!isCraft() || getPlatform() !== 'macos') return ''\n return (window as any).craft?.windowManagement?.newTab?.(url) ?? ''\n },\n\n /**\n * Close current tab.\n */\n async closeTab(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.closeTab?.()\n },\n\n /**\n * Get tab groups.\n */\n async getTabGroups(): Promise<WindowTabGroup[]> {\n if (!isCraft() || getPlatform() !== 'macos') return []\n return (window as any).craft?.windowManagement?.getTabGroups?.() ?? []\n },\n\n /**\n * Select a tab.\n */\n async selectTab(windowId: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.selectTab?.(windowId)\n },\n\n /**\n * Move tab to new window.\n */\n async moveTabToNewWindow(windowId: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.moveTabToNewWindow?.(windowId)\n },\n\n /**\n * Merge all windows.\n */\n async mergeAllWindows(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.mergeAllWindows?.()\n },\n\n /**\n * Enter full screen mode.\n */\n async enterFullScreen(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.enterFullScreen?.()\n },\n\n /**\n * Exit full screen mode.\n */\n async exitFullScreen(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.exitFullScreen?.()\n },\n\n /**\n * Toggle full screen.\n */\n async toggleFullScreen(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.toggleFullScreen?.()\n },\n\n /**\n * Create split view with two windows.\n */\n async createSplitView(leftWindowId: string, rightWindowId: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.createSplitView?.(leftWindowId, rightWindowId)\n },\n\n /**\n * Exit split view.\n */\n async exitSplitView(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.exitSplitView?.()\n },\n\n /**\n * Tile window to left half.\n */\n async tileLeft(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.tileLeft?.()\n },\n\n /**\n * Tile window to right half.\n */\n async tileRight(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.tileRight?.()\n },\n\n /**\n * Move window to space.\n */\n async moveToSpace(spaceIndex: number): Promise<void> {\n if (!isCraft() || getPlatform() !== 'macos') return\n return (window as any).craft?.windowManagement?.moveToSpace?.(spaceIndex)\n },\n\n /**\n * Register tab change handler.\n */\n onTabChange(handler: (tabGroup: WindowTabGroup) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.windowManagement?.onTabChange?.(handler)\n },\n\n /**\n * Register full screen change handler.\n */\n onFullScreenChange(handler: (isFullScreen: boolean) => void): void {\n if (!isCraft() || getPlatform() !== 'macos') return\n ;(window as any).craft?.windowManagement?.onFullScreenChange?.(handler)\n }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nconst macosAdvanced: {\n touchBar: typeof touchBar\n desktopWidgets: typeof desktopWidgets\n stageManager: typeof stageManager\n handoff: typeof handoff\n sidecar: typeof sidecar\n spotlight: typeof spotlight\n quickActions: typeof quickActions\n shareExtension: typeof shareExtension\n windowManagement: typeof windowManagement\n} = {\n touchBar: touchBar,\n desktopWidgets: desktopWidgets,\n stageManager: stageManager,\n handoff: handoff,\n sidecar: sidecar,\n spotlight: spotlight,\n quickActions: quickActions,\n shareExtension: shareExtension,\n windowManagement: windowManagement\n}\n\nexport default macosAdvanced\n",
|
|
27
|
+
"/**\n * @fileoverview Windows Advanced Features API\n * @description Advanced Windows-specific features including Jump Lists, Taskbar Progress,\n * Toast Notifications, Windows Hello, Widgets, and Windows App SDK integration.\n * @module @craft-native/api/windows-advanced\n */\n\nimport { isCraft, getPlatform } from './process'\n\n// ============================================================================\n// Jump Lists\n// ============================================================================\n\n/**\n * Jump list task.\n */\nexport interface JumpListTask {\n /** Task identifier */\n id: string\n /** Display title */\n title: string\n /** Description */\n description?: string\n /** Icon path or index */\n icon?: string\n /** Icon index (for exe icons) */\n iconIndex?: number\n /** Arguments to pass when launched */\n arguments?: string\n /** Working directory */\n workingDirectory?: string\n}\n\n/**\n * Jump list category.\n */\nexport interface JumpListCategory {\n /** Category type */\n type: 'tasks' | 'frequent' | 'recent' | 'custom'\n /** Custom category title (for 'custom' type) */\n title?: string\n /** Items in this category */\n items: JumpListTask[]\n}\n\n/**\n * Jump Lists API for Windows taskbar integration.\n *\n * @example\n * // Set up jump list\n * await jumpList.set([\n * {\n * type: 'tasks',\n * items: [\n * { id: 'new', title: 'New Window', icon: '%SystemRoot%\\\\system32\\\\shell32.dll', iconIndex: 1 },\n * { id: 'settings', title: 'Settings', arguments: '--settings' }\n * ]\n * },\n * {\n * type: 'custom',\n * title: 'Recent Projects',\n * items: recentProjects.map(p => ({ id: p.id, title: p.name, arguments: `--project ${p.id}` }))\n * }\n * ])\n *\n * // Handle jump list item click\n * jumpList.onItemClick((id, _args) => {\n * if (id === 'settings') openSettings()\n * })\n */\nexport const jumpList = {\n /**\n * Check if Jump Lists are supported.\n */\n async isSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.jumpList?.isSupported?.() ?? false\n },\n\n /**\n * Set the jump list categories.\n */\n async set(categories: JumpListCategory[]): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.jumpList?.set?.(categories)\n },\n\n /**\n * Clear the jump list.\n */\n async clear(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.jumpList?.clear?.()\n },\n\n /**\n * Add item to recent list.\n */\n async addToRecent(filePath: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.jumpList?.addToRecent?.(filePath)\n },\n\n /**\n * Clear recent list.\n */\n async clearRecent(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.jumpList?.clearRecent?.()\n },\n\n /**\n * Add item to frequent list.\n */\n async addToFrequent(filePath: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.jumpList?.addToFrequent?.(filePath)\n },\n\n /**\n * Clear frequent list.\n */\n async clearFrequent(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.jumpList?.clearFrequent?.()\n },\n\n /**\n * Handle jump list item click.\n */\n onItemClick(handler: (itemId: string, arguments_: string | null) => void): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.jumpList?.onItemClick?.(handler)\n }\n}\n\n// ============================================================================\n// Taskbar Progress\n// ============================================================================\n\n/**\n * Taskbar progress state.\n */\nexport type TaskbarProgressState = 'none' | 'indeterminate' | 'normal' | 'error' | 'paused'\n\n/**\n * Taskbar Progress API for Windows taskbar.\n *\n * @example\n * // Show download progress\n * await taskbarProgress.setState('normal')\n * await taskbarProgress.setProgress(0.5) // 50%\n *\n * // Show indeterminate progress\n * await taskbarProgress.setState('indeterminate')\n *\n * // Show error state\n * await taskbarProgress.setState('error')\n *\n * // Clear progress\n * await taskbarProgress.setState('none')\n */\nexport const taskbarProgress = {\n /**\n * Set progress state.\n */\n async setState(state: TaskbarProgressState): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.taskbarProgress?.setState?.(state)\n },\n\n /**\n * Set progress value (0-1).\n */\n async setProgress(value: number): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.taskbarProgress?.setProgress?.(Math.max(0, Math.min(1, value)))\n },\n\n /**\n * Clear progress.\n */\n async clear(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.taskbarProgress?.clear?.()\n },\n\n /**\n * Flash taskbar button.\n */\n async flash(options?: {\n count?: number\n interval?: number\n flags?: 'all' | 'caption' | 'tray'\n }): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.taskbarProgress?.flash?.(options)\n },\n\n /**\n * Stop flashing.\n */\n async stopFlash(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.taskbarProgress?.stopFlash?.()\n },\n\n /**\n * Set overlay icon.\n */\n async setOverlayIcon(iconPath: string | null, description?: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.taskbarProgress?.setOverlayIcon?.(iconPath, description)\n }\n}\n\n// ============================================================================\n// Toast Notifications\n// ============================================================================\n\n/**\n * Toast notification action.\n */\nexport interface ToastAction {\n /** Action identifier */\n id: string\n /** Button text */\n content: string\n /** Action type */\n type?: 'foreground' | 'background' | 'protocol'\n /** Arguments to pass */\n arguments?: string\n /** Image for button */\n imageUri?: string\n /** Input ID to reference */\n inputId?: string\n}\n\n/**\n * Toast notification input.\n */\nexport interface ToastInput {\n /** Input identifier */\n id: string\n /** Input type */\n type: 'text' | 'selection'\n /** Placeholder text (for text input) */\n placeHolderContent?: string\n /** Default value */\n defaultInput?: string\n /** Selection options (for selection input) */\n selections?: Array<{ id: string; content: string }>\n}\n\n/**\n * Toast notification content.\n */\nexport interface ToastContent {\n /** Title text (first line) */\n title: string\n /** Body text (second line) */\n body?: string\n /** Additional body text (third line) */\n body2?: string\n /** App logo override */\n appLogoOverride?: {\n uri: string\n hint?: 'circle' | 'none'\n }\n /** Hero image (full width) */\n heroImage?: {\n uri: string\n }\n /** Inline image */\n inlineImage?: {\n uri: string\n }\n /** Attribution text */\n attribution?: string\n /** Audio */\n audio?: {\n src?: 'default' | 'im' | 'mail' | 'reminder' | 'sms' | 'alarm' | string\n loop?: boolean\n silent?: boolean\n }\n /** Scenario type */\n scenario?: 'default' | 'alarm' | 'reminder' | 'incomingCall' | 'urgent'\n /** Expiration time */\n expirationTime?: Date\n /** Actions */\n actions?: ToastAction[]\n /** Inputs */\n inputs?: ToastInput[]\n /** Progress bar */\n progress?: {\n value: number | 'indeterminate'\n title?: string\n status?: string\n valueStringOverride?: string\n }\n}\n\n/**\n * Toast Notifications API for Windows notifications.\n *\n * @example\n * // Show simple notification\n * await toastNotifications.show({\n * title: 'Download Complete',\n * body: 'Your file has been downloaded successfully.',\n * actions: [\n * { id: 'open', content: 'Open File' },\n * { id: 'folder', content: 'Open Folder' }\n * ]\n * })\n *\n * // Show progress notification\n * const tag = 'download-1'\n * await toastNotifications.show({\n * title: 'Downloading...',\n * body: 'file.zip',\n * progress: { value: 0.5, status: '50% complete' }\n * }, { tag })\n *\n * // Update progress\n * await toastNotifications.update(tag, {\n * progress: { value: 1, status: 'Complete!' }\n * })\n *\n * // Handle action\n * toastNotifications.onActivated((args) => {\n * if (args.actionId === 'open') openFile()\n * })\n */\nexport const toastNotifications = {\n /**\n * Check if toast notifications are supported.\n */\n async isSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.toastNotifications?.isSupported?.() ?? false\n },\n\n /**\n * Show a toast notification.\n */\n async show(content: ToastContent, options?: {\n tag?: string\n group?: string\n suppressPopup?: boolean\n }): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.toastNotifications?.show?.(content, options)\n },\n\n /**\n * Update an existing notification by tag.\n */\n async update(tag: string, updates: Partial<ToastContent>): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.toastNotifications?.update?.(tag, updates)\n },\n\n /**\n * Hide a notification by tag.\n */\n async hide(tag: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.toastNotifications?.hide?.(tag)\n },\n\n /**\n * Hide a notification group.\n */\n async hideGroup(group: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.toastNotifications?.hideGroup?.(group)\n },\n\n /**\n * Clear all notifications.\n */\n async clearAll(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.toastNotifications?.clearAll?.()\n },\n\n /**\n * Get notification history.\n */\n async getHistory(): Promise<Array<{ tag: string; group: string; deliveredTime: Date }>> {\n if (!isCraft() || getPlatform() !== 'windows') return []\n return (window as any).craft?.toastNotifications?.getHistory?.() ?? []\n },\n\n /**\n * Handle notification activation (click or action).\n */\n onActivated(handler: (args: {\n tag?: string\n group?: string\n actionId?: string\n arguments?: string\n userInput?: Record<string, string>\n }) => void): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.toastNotifications?.onActivated?.(handler)\n },\n\n /**\n * Handle notification dismissed.\n */\n onDismissed(handler: (args: {\n tag?: string\n reason: 'user' | 'application' | 'timeout'\n }) => void): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.toastNotifications?.onDismissed?.(handler)\n }\n}\n\n// ============================================================================\n// Windows Hello (Biometrics)\n// ============================================================================\n\n/**\n * Windows Hello availability.\n */\nexport interface WindowsHelloAvailability {\n /** Whether Windows Hello is available */\n isAvailable: boolean\n /** Available biometric types */\n biometricTypes: Array<'face' | 'fingerprint' | 'iris'>\n /** Whether device supports companion devices */\n supportsCompanionDevice: boolean\n}\n\n/**\n * Windows Hello API for biometric authentication.\n *\n * @example\n * // Check availability\n * const hello = await windowsHello.getAvailability()\n * if (hello.isAvailable) {\n * // Authenticate\n * const result = await windowsHello.authenticate('Confirm your identity')\n * if (result.success) {\n * // User authenticated\n * }\n * }\n *\n * // Create a credential\n * const credential = await windowsHello.createCredential('user@example.com', 'Sign in to MyApp')\n *\n * // Verify credential\n * const verified = await windowsHello.verifyCredential(credential.keyId, 'Sign in to MyApp')\n */\nexport const windowsHello = {\n /**\n * Check Windows Hello availability.\n */\n async getAvailability(): Promise<WindowsHelloAvailability> {\n if (!isCraft() || getPlatform() !== 'windows') {\n return { isAvailable: false, biometricTypes: [], supportsCompanionDevice: false }\n }\n return (window as any).craft?.windowsHello?.getAvailability?.() ?? {\n isAvailable: false,\n biometricTypes: [],\n supportsCompanionDevice: false\n }\n },\n\n /**\n * Prompt for Windows Hello authentication.\n */\n async authenticate(message: string): Promise<{\n success: boolean\n error?: 'canceled' | 'notConfigured' | 'notAllowed' | 'unknown'\n }> {\n if (!isCraft() || getPlatform() !== 'windows') {\n return { success: false, error: 'notConfigured' }\n }\n return (window as any).craft?.windowsHello?.authenticate?.(message) ?? { success: false }\n },\n\n /**\n * Create a Windows Hello credential.\n */\n async createCredential(\n userId: string,\n message: string\n ): Promise<{\n success: boolean\n keyId?: string\n publicKey?: string\n attestation?: string\n error?: string\n }> {\n if (!isCraft() || getPlatform() !== 'windows') {\n return { success: false, error: 'Windows Hello not available' }\n }\n return (window as any).craft?.windowsHello?.createCredential?.(userId, message) ?? { success: false }\n },\n\n /**\n * Sign data with Windows Hello credential.\n */\n async signWithCredential(\n keyId: string,\n challenge: string,\n message: string\n ): Promise<{\n success: boolean\n signature?: string\n error?: string\n }> {\n if (!isCraft() || getPlatform() !== 'windows') {\n return { success: false, error: 'Windows Hello not available' }\n }\n return (window as any).craft?.windowsHello?.signWithCredential?.(keyId, challenge, message) ?? { success: false }\n },\n\n /**\n * Delete a Windows Hello credential.\n */\n async deleteCredential(keyId: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.windowsHello?.deleteCredential?.(keyId) ?? false\n },\n\n /**\n * Check if a credential exists.\n */\n async hasCredential(keyId: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.windowsHello?.hasCredential?.(keyId) ?? false\n }\n}\n\n// ============================================================================\n// Windows Widgets\n// ============================================================================\n\n/**\n * Widget template type.\n */\nexport type WidgetTemplateType =\n | 'small'\n | 'medium'\n | 'large'\n | 'adaptive'\n\n/**\n * Widget content.\n */\nexport interface WindowsWidgetContent {\n /** Template JSON */\n template: Record<string, any>\n /** Data to bind to template */\n data: Record<string, any>\n}\n\n/**\n * Windows Widgets API (Windows 11).\n *\n * @example\n * // Register widget provider\n * windowsWidgets.register({\n * id: 'weather-widget',\n * name: 'Weather',\n * description: 'Shows current weather',\n * defaultTemplate: 'medium'\n * })\n *\n * // Provide content\n * windowsWidgets.onContentRequested('weather-widget', async (_context) => {\n * const weather = await fetchWeather()\n * return {\n * template: weatherTemplate,\n * data: { temp: weather.temp, condition: weather.condition }\n * }\n * })\n *\n * // Handle customization\n * windowsWidgets.onCustomize('weather-widget', async (settings) => {\n * // Save user settings\n * })\n */\nexport const windowsWidgets = {\n /**\n * Check if Windows Widgets are supported.\n */\n async isSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.windowsWidgets?.isSupported?.() ?? false\n },\n\n /**\n * Register a widget provider.\n */\n register(config: {\n id: string\n name: string\n description: string\n defaultTemplate: WidgetTemplateType\n supportedTemplates?: WidgetTemplateType[]\n hasCustomization?: boolean\n }): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.windowsWidgets?.register?.(config)\n },\n\n /**\n * Unregister a widget provider.\n */\n unregister(widgetId: string): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.windowsWidgets?.unregister?.(widgetId)\n },\n\n /**\n * Handle content request.\n */\n onContentRequested(\n widgetId: string,\n handler: (context: {\n templateType: WidgetTemplateType\n customData?: Record<string, any>\n }) => Promise<WindowsWidgetContent>\n ): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.windowsWidgets?.onContentRequested?.(widgetId, handler)\n },\n\n /**\n * Update widget content.\n */\n async updateContent(widgetId: string, content: WindowsWidgetContent): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.windowsWidgets?.updateContent?.(widgetId, content)\n },\n\n /**\n * Handle widget action.\n */\n onAction(\n widgetId: string,\n handler: (action: string, data?: Record<string, any>) => void\n ): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.windowsWidgets?.onAction?.(widgetId, handler)\n },\n\n /**\n * Handle customization.\n */\n onCustomize(\n widgetId: string,\n handler: (settings: Record<string, any>) => Promise<void>\n ): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.windowsWidgets?.onCustomize?.(widgetId, handler)\n }\n}\n\n// ============================================================================\n// MSIX Packaging / Auto-Update\n// ============================================================================\n\n/**\n * Package version info.\n */\nexport interface PackageVersion {\n /** Major version */\n major: number\n /** Minor version */\n minor: number\n /** Build version */\n build: number\n /** Revision version */\n revision: number\n /** Full version string */\n full: string\n}\n\n/**\n * Update info.\n */\nexport interface UpdateInfo {\n /** Whether update is available */\n isAvailable: boolean\n /** Whether update is mandatory */\n isMandatory: boolean\n /** New version */\n version?: PackageVersion\n /** Update size in bytes */\n updateSize?: number\n}\n\n/**\n * MSIX/Auto-Update API for Windows Store apps.\n *\n * @example\n * // Check for updates\n * const update = await msixUpdate.checkForUpdates()\n * if (update.isAvailable) {\n * // Download and install\n * await msixUpdate.downloadAndInstall({\n * showProgress: true,\n * restartOnComplete: true\n * })\n * }\n */\nexport const msixUpdate = {\n /**\n * Get current package version.\n */\n async getCurrentVersion(): Promise<PackageVersion | null> {\n if (!isCraft() || getPlatform() !== 'windows') return null\n return (window as any).craft?.msixUpdate?.getCurrentVersion?.()\n },\n\n /**\n * Check for updates.\n */\n async checkForUpdates(): Promise<UpdateInfo> {\n if (!isCraft() || getPlatform() !== 'windows') {\n return { isAvailable: false, isMandatory: false }\n }\n return (window as any).craft?.msixUpdate?.checkForUpdates?.() ?? { isAvailable: false, isMandatory: false }\n },\n\n /**\n * Download and install update.\n */\n async downloadAndInstall(options?: {\n showProgress?: boolean\n restartOnComplete?: boolean\n }): Promise<{ success: boolean; error?: string }> {\n if (!isCraft() || getPlatform() !== 'windows') {\n return { success: false, error: 'MSIX not available' }\n }\n return (window as any).craft?.msixUpdate?.downloadAndInstall?.(options) ?? { success: false }\n },\n\n /**\n * Get download progress.\n */\n onDownloadProgress(handler: (progress: {\n bytesDownloaded: number\n totalBytes: number\n percentage: number\n }) => void): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.msixUpdate?.onDownloadProgress?.(handler)\n },\n\n /**\n * Check if running as MSIX package.\n */\n async isPackaged(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.msixUpdate?.isPackaged?.() ?? false\n },\n\n /**\n * Get package install location.\n */\n async getInstallLocation(): Promise<string | null> {\n if (!isCraft() || getPlatform() !== 'windows') return null\n return (window as any).craft?.msixUpdate?.getInstallLocation?.()\n }\n}\n\n// ============================================================================\n// Share Target\n// ============================================================================\n\n/**\n * Shared data item.\n */\nexport interface SharedDataItem {\n /** Data type */\n type: 'text' | 'uri' | 'html' | 'bitmap' | 'file'\n /** Text content */\n text?: string\n /** URI */\n uri?: string\n /** HTML content */\n html?: string\n /** File path */\n filePath?: string\n /** File name */\n fileName?: string\n /** Content type */\n contentType?: string\n}\n\n/**\n * Share Target API for Windows share integration.\n *\n * @example\n * // Handle incoming share\n * shareTarget.onShare(async (items, operation) => {\n * for (const item of items) {\n * if (item.type === 'uri') {\n * await saveBookmark(item.uri)\n * }\nelse if (item.type === 'file') {\n * await importFile(item.filePath)\n * }\n * }\n * operation.complete()\n * })\n */\nexport const shareTarget = {\n /**\n * Handle incoming share.\n */\n onShare(handler: (\n items: SharedDataItem[],\n operation: {\n complete: () => void\n fail: (error: string) => void\n }\n ) => Promise<void>): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.shareTarget?.onShare?.(handler)\n },\n\n /**\n * Check if app was launched as share target.\n */\n async wasLaunchedAsShareTarget(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.shareTarget?.wasLaunchedAsShareTarget?.() ?? false\n },\n\n /**\n * Get shared data if launched as share target.\n */\n async getSharedData(): Promise<SharedDataItem[]> {\n if (!isCraft() || getPlatform() !== 'windows') return []\n return (window as any).craft?.shareTarget?.getSharedData?.() ?? []\n }\n}\n\n// ============================================================================\n// Startup Tasks\n// ============================================================================\n\n/**\n * Startup Task API for Windows launch at startup.\n *\n * @example\n * // Check if startup is enabled\n * const state = await startupTask.getState()\n *\n * // Request startup\n * await startupTask.request()\n *\n * // Disable startup\n * await startupTask.disable()\n */\nexport const startupTask = {\n /**\n * Get current startup state.\n */\n async getState(): Promise<'disabled' | 'disabledByUser' | 'enabled' | 'disabledByPolicy' | 'enabledByPolicy'> {\n if (!isCraft() || getPlatform() !== 'windows') return 'disabled'\n return (window as any).craft?.startupTask?.getState?.() ?? 'disabled'\n },\n\n /**\n * Request enabling startup.\n */\n async request(): Promise<'disabled' | 'disabledByUser' | 'enabled' | 'disabledByPolicy' | 'enabledByPolicy'> {\n if (!isCraft() || getPlatform() !== 'windows') return 'disabled'\n return (window as any).craft?.startupTask?.request?.() ?? 'disabled'\n },\n\n /**\n * Disable startup.\n */\n async disable(): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.startupTask?.disable?.()\n }\n}\n\n// ============================================================================\n// Secondary Tiles\n// ============================================================================\n\n/**\n * Secondary tile configuration.\n */\nexport interface SecondaryTile {\n /** Tile ID */\n tileId: string\n /** Display name */\n displayName: string\n /** Arguments when launched */\n arguments: string\n /** Square 150x150 logo */\n square150x150Logo: string\n /** Wide 310x150 logo */\n wide310x150Logo?: string\n /** Square 310x310 logo */\n square310x310Logo?: string\n /** Background color */\n backgroundColor?: string\n /** Show name on tile */\n showNameOnSquare150x150Logo?: boolean\n /** Show name on wide tile */\n showNameOnWide310x150Logo?: boolean\n}\n\n/**\n * Secondary Tiles API for Windows Start menu tiles.\n *\n * @example\n * // Pin a tile\n * await secondaryTiles.pin({\n * tileId: 'project-123',\n * displayName: 'My Project',\n * arguments: '--project 123',\n * square150x150Logo: 'ms-appx:///Assets/ProjectTile.png'\n * })\n *\n * // Check if pinned\n * const isPinned = await secondaryTiles.exists('project-123')\n *\n * // Update tile\n * await secondaryTiles.updateBadge('project-123', 5)\n */\nexport const secondaryTiles = {\n /**\n * Check if secondary tiles are supported.\n */\n async isSupported(): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.secondaryTiles?.isSupported?.() ?? false\n },\n\n /**\n * Pin a secondary tile.\n */\n async pin(tile: SecondaryTile): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.secondaryTiles?.pin?.(tile) ?? false\n },\n\n /**\n * Unpin a secondary tile.\n */\n async unpin(tileId: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.secondaryTiles?.unpin?.(tileId) ?? false\n },\n\n /**\n * Check if a tile exists.\n */\n async exists(tileId: string): Promise<boolean> {\n if (!isCraft() || getPlatform() !== 'windows') return false\n return (window as any).craft?.secondaryTiles?.exists?.(tileId) ?? false\n },\n\n /**\n * Get all pinned tiles.\n */\n async getAll(): Promise<string[]> {\n if (!isCraft() || getPlatform() !== 'windows') return []\n return (window as any).craft?.secondaryTiles?.getAll?.() ?? []\n },\n\n /**\n * Update tile content.\n */\n async updateTile(tileId: string, content: {\n text1?: string\n text2?: string\n text3?: string\n image?: string\n }): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.secondaryTiles?.updateTile?.(tileId, content)\n },\n\n /**\n * Update tile badge.\n */\n async updateBadge(tileId: string, value: number | 'none' | 'activity' | 'alert' | 'attention' | 'available' | 'away' | 'busy' | 'newMessage' | 'paused' | 'playing' | 'unavailable' | 'error'): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.secondaryTiles?.updateBadge?.(tileId, value)\n },\n\n /**\n * Clear tile notification.\n */\n async clearTile(tileId: string): Promise<void> {\n if (!isCraft() || getPlatform() !== 'windows') return\n return (window as any).craft?.secondaryTiles?.clearTile?.(tileId)\n },\n\n /**\n * Handle tile launch.\n */\n onLaunch(handler: (tileId: string, arguments_: string) => void): void {\n if (!isCraft() || getPlatform() !== 'windows') return\n ;(window as any).craft?.secondaryTiles?.onLaunch?.(handler)\n }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nconst windowsAdvanced: {\n jumpList: typeof jumpList\n taskbarProgress: typeof taskbarProgress\n toastNotifications: typeof toastNotifications\n windowsHello: typeof windowsHello\n windowsWidgets: typeof windowsWidgets\n msixUpdate: typeof msixUpdate\n shareTarget: typeof shareTarget\n startupTask: typeof startupTask\n secondaryTiles: typeof secondaryTiles\n} = {\n jumpList: jumpList,\n taskbarProgress: taskbarProgress,\n toastNotifications: toastNotifications,\n windowsHello: windowsHello,\n windowsWidgets: windowsWidgets,\n msixUpdate: msixUpdate,\n shareTarget: shareTarget,\n startupTask: startupTask,\n secondaryTiles: secondaryTiles\n}\n\nexport default windowsAdvanced\n",
|
|
28
|
+
"/**\n * Craft Dialog API\n * Native file pickers and alert dialogs\n * @module @craft-native/api/dialog\n */\n\nimport { getBridge } from '../bridge/core'\nimport { isWebKitHost, webkitRequest } from '../bridge/webkit-pending'\n\n/**\n * Default timeout for *file-system* dialog round-trips (open/save).\n * Dialogs are user-facing and may stay open for minutes, so the cap is\n * high but still bounded — a forgotten dialog shouldn't pin the\n * pending-queue closure forever.\n */\nconst FILE_DIALOG_TIMEOUT_MS = 5 * 60 * 1000\n\n/**\n * Alert/confirm/prompt dialogs have no upper bound — they sit modal until\n * the user clicks. Use a large but finite cap (1 hour) so a forgotten\n * background dialog still gets garbage-collected eventually.\n */\nconst MODAL_DIALOG_TIMEOUT_MS = 60 * 60 * 1000\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * File filter for open/save dialogs\n */\nexport interface FileFilter {\n /** Filter display name (e.g., \"Images\") */\n name: string\n /** File extensions without dots (e.g., [\"png\", \"jpg\", \"gif\"]) */\n extensions: string[]\n}\n\n/**\n * Options for open file dialog\n */\nexport interface OpenDialogOptions {\n /** Dialog title */\n title?: string\n /** Default path to open */\n defaultPath?: string\n /** File filters */\n filters?: FileFilter[]\n /** Allow selecting multiple files */\n multiple?: boolean\n /** Allow selecting directories */\n directory?: boolean\n /** Show hidden files */\n showHiddenFiles?: boolean\n}\n\n/**\n * Options for save file dialog\n */\nexport interface SaveDialogOptions {\n /** Dialog title */\n title?: string\n /** Default path to save */\n defaultPath?: string\n /** Default file name */\n defaultName?: string\n /** File filters */\n filters?: FileFilter[]\n /** Show hidden files */\n showHiddenFiles?: boolean\n}\n\n/**\n * Alert dialog style\n */\nexport type AlertStyle = 'info' | 'warning' | 'critical'\n\n/**\n * Options for alert dialog\n */\nexport interface AlertOptions {\n /** Dialog title (main message) */\n title: string\n /** Dialog message (secondary text) */\n message?: string\n /** Alert style */\n style?: AlertStyle\n /** Custom button labels */\n buttons?: string[]\n}\n\n/**\n * Options for confirm dialog\n */\nexport interface ConfirmOptions {\n /** Dialog title (main message) */\n title: string\n /** Dialog message (secondary text) */\n message?: string\n /** OK button label */\n okLabel?: string\n /** Cancel button label */\n cancelLabel?: string\n}\n\n/**\n * Result from open dialog\n */\nexport interface OpenDialogResult {\n /** Whether a file was selected (not cancelled) */\n canceled: boolean\n /** Selected file paths */\n filePaths: string[]\n}\n\n/**\n * Result from save dialog\n */\nexport interface SaveDialogResult {\n /** Whether save was cancelled */\n canceled: boolean\n /** Selected file path */\n filePath?: string\n}\n\n// ============================================================================\n// Dialog Functions\n// ============================================================================\n\n/**\n * Show open file dialog\n * @param options Dialog options\n * @returns Selected file path(s)\n */\nexport async function openFile(options: OpenDialogOptions = {}): Promise<OpenDialogResult> {\n const action = options.multiple ? 'openFiles' : 'openFile'\n\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ canceled?: boolean; filePaths?: string[] } | undefined>(\n action,\n { type: 'dialog', action, data: options },\n { timeoutMs: FILE_DIALOG_TIMEOUT_MS },\n )\n const canceled = !!(payload && payload.canceled === true)\n const filePaths = Array.isArray(payload?.filePaths) ? (payload!.filePaths as string[]) : []\n return { canceled, filePaths }\n }\n\n const bridge = getBridge()\n return bridge.request(`dialog.${action}`, options)\n}\n\n/**\n * Show open folder dialog\n * @param options Dialog options\n * @returns Selected folder path\n */\nexport async function openFolder(options: Omit<OpenDialogOptions, 'multiple' | 'directory'> = {}): Promise<OpenDialogResult> {\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ canceled?: boolean; filePaths?: string[] } | undefined>(\n 'openFolder',\n { type: 'dialog', action: 'openFolder', data: options },\n { timeoutMs: FILE_DIALOG_TIMEOUT_MS },\n )\n const canceled = !!(payload && payload.canceled === true)\n const filePaths = Array.isArray(payload?.filePaths) ? (payload!.filePaths as string[]) : []\n return { canceled, filePaths }\n }\n\n const bridge = getBridge()\n return bridge.request('dialog.openFolder', options)\n}\n\n/**\n * Show save file dialog\n * @param options Dialog options\n * @returns Selected save path\n */\nexport async function saveFile(options: SaveDialogOptions = {}): Promise<SaveDialogResult> {\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ canceled?: boolean; filePath?: string } | undefined>(\n 'saveFile',\n { type: 'dialog', action: 'saveFile', data: options },\n { timeoutMs: FILE_DIALOG_TIMEOUT_MS },\n )\n const canceled = !!(payload && payload.canceled === true)\n const filePath = typeof payload?.filePath === 'string' ? payload.filePath : undefined\n return { canceled, filePath }\n }\n\n const bridge = getBridge()\n return bridge.request('dialog.saveFile', options)\n}\n\n/**\n * Show alert dialog\n * @param options Alert options or just a message string\n * @returns Button index that was clicked\n */\nexport async function showAlert(options: AlertOptions | string): Promise<number> {\n const opts = typeof options === 'string' ? { title: options } : options\n\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ buttonIndex?: number } | undefined>(\n 'showAlert',\n { type: 'dialog', action: 'showAlert', data: opts },\n { timeoutMs: MODAL_DIALOG_TIMEOUT_MS },\n )\n if (payload && typeof payload.buttonIndex === 'number') {\n return payload.buttonIndex\n }\n return 0\n }\n\n const bridge = getBridge()\n return bridge.request('dialog.showAlert', opts)\n}\n\n/**\n * Show confirm dialog with OK/Cancel buttons\n * @param options Confirm options or just a message string\n * @returns true if OK was clicked, false if cancelled\n */\nexport async function showConfirm(options: ConfirmOptions | string): Promise<boolean> {\n const opts = typeof options === 'string' ? { title: options } : options\n\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ ok?: boolean } | undefined>(\n 'showConfirm',\n { type: 'dialog', action: 'showConfirm', data: opts },\n { timeoutMs: MODAL_DIALOG_TIMEOUT_MS },\n )\n return !!(payload && payload.ok === true)\n }\n\n const bridge = getBridge()\n return bridge.request('dialog.showConfirm', opts)\n}\n\n/**\n * Show prompt dialog with text input\n * @param title Dialog title\n * @param defaultValue Default input value\n * @returns User input or null if cancelled\n */\nexport async function showPrompt(title: string, defaultValue?: string): Promise<string | null> {\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ value?: string } | undefined>(\n 'showPrompt',\n { type: 'dialog', action: 'showPrompt', data: { title, defaultValue } },\n { timeoutMs: MODAL_DIALOG_TIMEOUT_MS },\n )\n if (payload && typeof payload.value === 'string') return payload.value\n return null\n }\n\n const bridge = getBridge()\n return bridge.request('dialog.showPrompt', { title, defaultValue })\n}\n\n// ============================================================================\n// Convenience exports\n// ============================================================================\n\nexport const dialog: {\n openFile: typeof openFile\n openFolder: typeof openFolder\n saveFile: typeof saveFile\n showAlert: typeof showAlert\n showConfirm: typeof showConfirm\n showPrompt: typeof showPrompt\n} = {\n openFile,\n openFolder,\n saveFile,\n showAlert,\n showConfirm,\n showPrompt,\n}\n\nexport default dialog\n",
|
|
29
|
+
"/**\n * Craft Clipboard API\n * Read and write to the system clipboard\n * @module @craft-native/api/clipboard\n */\n\nimport { getBridge } from '../bridge/core'\nimport { isWebKitHost, postWebKit, webkitRequest } from '../bridge/webkit-pending'\n\n/** Default timeout for callback-style clipboard reads. */\nconst CLIPBOARD_READ_TIMEOUT_MS = 5000\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Clipboard content types\n */\nexport type ClipboardFormat = 'text' | 'html' | 'rtf' | 'image'\n\n/**\n * Clipboard data with multiple formats\n */\nexport interface ClipboardData {\n /** Plain text content */\n text?: string\n /** HTML content */\n html?: string\n /** RTF content */\n rtf?: string\n /** Image as data URL or base64 */\n image?: string\n}\n\n// ============================================================================\n// Clipboard Functions\n// ============================================================================\n\n/**\n * Write text to clipboard\n * @param text Text to copy\n */\nexport async function writeText(text: string): Promise<void> {\n if (isWebKitHost()) {\n postWebKit({ type: 'clipboard', action: 'writeText', data: { text } })\n return\n }\n\n const bridge = getBridge()\n return bridge.request('clipboard.writeText', { text })\n}\n\n/**\n * Read text from clipboard\n * @returns Clipboard text content\n */\nexport async function readText(): Promise<string> {\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ text?: string } | undefined>(\n 'readText',\n { type: 'clipboard', action: 'readText' },\n { timeoutMs: CLIPBOARD_READ_TIMEOUT_MS },\n )\n return payload && typeof payload.text === 'string' ? payload.text : ''\n }\n\n const bridge = getBridge()\n return bridge.request('clipboard.readText')\n}\n\n/**\n * Write HTML to clipboard\n * @param html HTML content to copy\n */\nexport async function writeHTML(html: string): Promise<void> {\n if (isWebKitHost()) {\n postWebKit({ type: 'clipboard', action: 'writeHTML', data: { html } })\n return\n }\n\n const bridge = getBridge()\n return bridge.request('clipboard.writeHTML', { html })\n}\n\n/**\n * Read HTML from clipboard\n * @returns Clipboard HTML content\n */\nexport async function readHTML(): Promise<string> {\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ html?: string } | undefined>(\n 'readHTML',\n { type: 'clipboard', action: 'readHTML' },\n { timeoutMs: CLIPBOARD_READ_TIMEOUT_MS },\n )\n return payload && typeof payload.html === 'string' ? payload.html : ''\n }\n\n const bridge = getBridge()\n return bridge.request('clipboard.readHTML')\n}\n\n/**\n * Clear clipboard contents\n */\nexport async function clear(): Promise<void> {\n if (isWebKitHost()) {\n postWebKit({ type: 'clipboard', action: 'clear' })\n return\n }\n\n const bridge = getBridge()\n return bridge.request('clipboard.clear')\n}\n\n/**\n * Check if clipboard has text content\n * @returns true if clipboard contains text\n */\nexport async function hasText(): Promise<boolean> {\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ value?: boolean } | undefined>(\n 'hasText',\n { type: 'clipboard', action: 'hasText' },\n { timeoutMs: CLIPBOARD_READ_TIMEOUT_MS },\n )\n return !!(payload && payload.value === true)\n }\n\n const bridge = getBridge()\n return bridge.request('clipboard.hasText')\n}\n\n/**\n * Check if clipboard has HTML content\n * @returns true if clipboard contains HTML\n */\nexport async function hasHTML(): Promise<boolean> {\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ value?: boolean } | undefined>(\n 'hasHTML',\n { type: 'clipboard', action: 'hasHTML' },\n { timeoutMs: CLIPBOARD_READ_TIMEOUT_MS },\n )\n return !!(payload && payload.value === true)\n }\n\n const bridge = getBridge()\n return bridge.request('clipboard.hasHTML')\n}\n\n/**\n * Check if clipboard has image content\n * @returns true if clipboard contains image\n */\nexport async function hasImage(): Promise<boolean> {\n if (isWebKitHost()) {\n const payload = await webkitRequest<{ value?: boolean } | undefined>(\n 'hasImage',\n { type: 'clipboard', action: 'hasImage' },\n { timeoutMs: CLIPBOARD_READ_TIMEOUT_MS },\n )\n return !!(payload && payload.value === true)\n }\n\n const bridge = getBridge()\n return bridge.request('clipboard.hasImage')\n}\n\n/**\n * Write multiple formats to clipboard at once\n * @param data Clipboard data with multiple formats\n */\nexport async function write(data: ClipboardData): Promise<void> {\n // Write each format that's present\n const promises: Promise<void>[] = []\n\n if (data.text) {\n promises.push(writeText(data.text))\n }\n if (data.html) {\n promises.push(writeHTML(data.html))\n }\n\n await Promise.all(promises)\n}\n\n/**\n * Read all available formats from clipboard\n * @returns Clipboard data with all available formats\n */\nexport async function read(): Promise<ClipboardData> {\n const [text, html] = await Promise.all([\n readText().catch((err) => {\n console.debug('[Craft Clipboard] readText failed:', err)\n return undefined\n }),\n readHTML().catch((err) => {\n console.debug('[Craft Clipboard] readHTML failed:', err)\n return undefined\n }),\n ])\n\n return {\n text: text || undefined,\n html: html || undefined,\n }\n}\n\n// ============================================================================\n// Convenience exports\n// ============================================================================\n\nexport const clipboard: {\n writeText: typeof writeText\n readText: typeof readText\n writeHTML: typeof writeHTML\n readHTML: typeof readHTML\n clear: typeof clear\n hasText: typeof hasText\n hasHTML: typeof hasHTML\n hasImage: typeof hasImage\n write: typeof write\n read: typeof read\n} = {\n writeText,\n readText,\n writeHTML,\n readHTML,\n clear,\n hasText,\n hasHTML,\n hasImage,\n write,\n read,\n}\n\nexport default clipboard\n",
|
|
30
|
+
"/**\n * Craft Media API\n * Cross-platform camera and microphone access for desktop and mobile.\n *\n * @example\n * ```typescript\n * import { media } from '@aspect/craft'\n *\n * // List available cameras and microphones\n * const devices = await media.enumerateDevices()\n * const cameras = devices.filter(d => d.kind === 'videoinput')\n * const microphones = devices.filter(d => d.kind === 'audioinput')\n *\n * // Get camera stream\n * const stream = await media.getCamera()\n *\n * // Get microphone stream\n * const audioStream = await media.getMicrophone()\n *\n * // Get both camera and microphone\n * const avStream = await media.getMediaStream({ video: true, audio: true })\n *\n * // Check if media access is available\n * const hasCamera = await media.hasCameraAccess()\n * const hasMic = await media.hasMicrophoneAccess()\n * ```\n */\n\n/**\n * Media device information\n */\nexport interface MediaDeviceInfo {\n /** Unique device identifier */\n deviceId: string\n /** Device group ID (devices sharing same physical device) */\n groupId: string\n /** Device type: 'audioinput' | 'audiooutput' | 'videoinput' */\n kind: 'audioinput' | 'audiooutput' | 'videoinput'\n /** Human-readable device label */\n label: string\n}\n\n/**\n * Camera options\n */\nexport interface CameraOptions {\n /** Preferred camera device ID */\n deviceId?: string\n /** Prefer front or back camera (mobile) */\n facingMode?: 'user' | 'environment'\n /** Preferred width */\n width?: number | { min?: number; ideal?: number; max?: number }\n /** Preferred height */\n height?: number | { min?: number; ideal?: number; max?: number }\n /** Preferred frame rate */\n frameRate?: number | { min?: number; ideal?: number; max?: number }\n /** Aspect ratio */\n aspectRatio?: number | { min?: number; ideal?: number; max?: number }\n}\n\n/**\n * Microphone options\n */\nexport interface MicrophoneOptions {\n /** Preferred microphone device ID */\n deviceId?: string\n /** Enable echo cancellation */\n echoCancellation?: boolean\n /** Enable noise suppression */\n noiseSuppression?: boolean\n /** Enable auto gain control */\n autoGainControl?: boolean\n /** Sample rate in Hz */\n sampleRate?: number\n /** Number of channels (1 = mono, 2 = stereo) */\n channelCount?: number\n}\n\n/**\n * Combined media stream options\n */\nexport interface MediaStreamOptions {\n /** Enable video capture */\n video?: boolean | CameraOptions\n /** Enable audio capture */\n audio?: boolean | MicrophoneOptions\n}\n\n/**\n * Internal: detect whether the page has *granted* (not merely \"could\n * prompt for\") access to a given device kind.\n *\n * The previous implementation returned `true` whenever\n * `enumerateDevices()` listed at least one matching device — but Safari\n * and Chrome return device entries with empty `label` *before* the user\n * has granted permission, so callers thought they had access, called\n * `getUserMedia`, and then saw the permission prompt anyway. We tighten\n * the contract to:\n *\n * - `permissions.query` reports `'granted'`, OR\n * - at least one matching device has a non-empty `label` (browsers\n * populate `label` only after a successful prior `getUserMedia`).\n *\n * `'denied'` short-circuits to `false` regardless. Errors → false.\n */\nasync function _hasMediaAccess(\n permissionName: 'camera' | 'microphone',\n deviceKind: 'videoinput' | 'audioinput',\n): Promise<boolean> {\n if (typeof navigator === 'undefined' || !navigator.mediaDevices) {\n return false\n }\n try {\n if (navigator.permissions) {\n try {\n const result = await navigator.permissions.query({ name: permissionName as PermissionName })\n if (result.state === 'granted') return true\n if (result.state === 'denied') return false\n // `prompt` falls through to the label check.\n }\n catch {\n // Some browsers (Firefox <90) don't recognize 'camera'/'microphone'\n // as PermissionName; fall through to device enumeration.\n }\n }\n const devices = await navigator.mediaDevices.enumerateDevices()\n const matching = devices.filter((d) => d.kind === deviceKind)\n if (matching.length === 0) return false\n // A non-empty label means the browser has previously granted access\n // (label is hidden until the permission prompt resolves at least once).\n return matching.some((d) => typeof d.label === 'string' && d.label.length > 0)\n }\n catch {\n return false\n }\n}\n\n/**\n * Media API for camera and microphone access.\n * Works across macOS, Linux, Windows, iOS, and Android.\n */\nexport const media = {\n /**\n * Enumerate all available media devices (cameras, microphones, speakers).\n *\n * @returns Promise resolving to array of media devices\n * @example\n * ```typescript\n * const devices = await media.enumerateDevices()\n * const cameras = devices.filter(d => d.kind === 'videoinput')\n * console.log('Available cameras:', cameras.map(c => c.label))\n * ```\n */\n async enumerateDevices(): Promise<MediaDeviceInfo[]> {\n if (typeof navigator === 'undefined' || !navigator.mediaDevices) {\n return []\n }\n\n try {\n const devices = await navigator.mediaDevices.enumerateDevices()\n return devices.map((d) => ({\n deviceId: d.deviceId,\n groupId: d.groupId,\n kind: d.kind as 'audioinput' | 'audiooutput' | 'videoinput',\n label: d.label || `${d.kind} (${d.deviceId.slice(0, 8)}...)`,\n }))\n }\ncatch {\n return []\n }\n },\n\n /**\n * Get list of available cameras.\n *\n * @returns Promise resolving to array of camera devices\n */\n async getCameras(): Promise<MediaDeviceInfo[]> {\n const devices = await this.enumerateDevices()\n return devices.filter((d) => d.kind === 'videoinput')\n },\n\n /**\n * Get list of available microphones.\n *\n * @returns Promise resolving to array of microphone devices\n */\n async getMicrophones(): Promise<MediaDeviceInfo[]> {\n const devices = await this.enumerateDevices()\n return devices.filter((d) => d.kind === 'audioinput')\n },\n\n /**\n * Get list of available audio output devices (speakers/headphones).\n *\n * @returns Promise resolving to array of speaker devices\n */\n async getSpeakers(): Promise<MediaDeviceInfo[]> {\n const devices = await this.enumerateDevices()\n return devices.filter((d) => d.kind === 'audiooutput')\n },\n\n /**\n * Get a camera video stream.\n *\n * @param options - Camera options\n * @returns Promise resolving to MediaStream\n * @example\n * ```typescript\n * // Get default camera\n * const stream = await media.getCamera()\n *\n * // Get specific camera with HD resolution\n * const hdStream = await media.getCamera({\n * deviceId: 'abc123',\n * width: { ideal: 1920 },\n * height: { ideal: 1080 }\n * })\n *\n * // Use in video element\n * videoElement.srcObject = stream\n * ```\n */\n async getCamera(options?: CameraOptions): Promise<MediaStream> {\n if (typeof navigator === 'undefined' || !navigator.mediaDevices) {\n throw new Error('Media devices not available')\n }\n\n const constraints: MediaStreamConstraints = {\n video: options\n ? {\n deviceId: options.deviceId ? { exact: options.deviceId } : undefined,\n facingMode: options.facingMode,\n width: options.width,\n height: options.height,\n frameRate: options.frameRate,\n aspectRatio: options.aspectRatio,\n }\n : true,\n audio: false,\n }\n\n return navigator.mediaDevices.getUserMedia(constraints)\n },\n\n /**\n * Get a microphone audio stream.\n *\n * @param options - Microphone options\n * @returns Promise resolving to MediaStream\n * @example\n * ```typescript\n * // Get default microphone\n * const stream = await media.getMicrophone()\n *\n * // Get microphone with noise suppression\n * const cleanStream = await media.getMicrophone({\n * echoCancellation: true,\n * noiseSuppression: true\n * })\n * ```\n */\n async getMicrophone(options?: MicrophoneOptions): Promise<MediaStream> {\n if (typeof navigator === 'undefined' || !navigator.mediaDevices) {\n throw new Error('Media devices not available')\n }\n\n const constraints: MediaStreamConstraints = {\n video: false,\n audio: options\n ? {\n deviceId: options.deviceId ? { exact: options.deviceId } : undefined,\n echoCancellation: options.echoCancellation,\n noiseSuppression: options.noiseSuppression,\n autoGainControl: options.autoGainControl,\n sampleRate: options.sampleRate,\n channelCount: options.channelCount,\n }\n : true,\n }\n\n return navigator.mediaDevices.getUserMedia(constraints)\n },\n\n /**\n * Get a combined audio/video stream.\n *\n * @param options - Media stream options\n * @returns Promise resolving to MediaStream\n * @example\n * ```typescript\n * // Get both camera and microphone\n * const stream = await media.getMediaStream({ video: true, audio: true })\n *\n * // Get camera with specific settings and microphone with noise suppression\n * const stream = await media.getMediaStream({\n * video: { width: 1280, height: 720 },\n * audio: { noiseSuppression: true }\n * })\n * ```\n */\n async getMediaStream(options: MediaStreamOptions): Promise<MediaStream> {\n if (typeof navigator === 'undefined' || !navigator.mediaDevices) {\n throw new Error('Media devices not available')\n }\n\n const constraints: MediaStreamConstraints = {\n video: options.video === true ? true : options.video ? this._buildVideoConstraints(options.video) : false,\n audio: options.audio === true ? true : options.audio ? this._buildAudioConstraints(options.audio) : false,\n }\n\n return navigator.mediaDevices.getUserMedia(constraints)\n },\n\n /**\n * Check if camera access is available (permission granted or can be requested).\n *\n * @returns Promise resolving to boolean\n */\n async hasCameraAccess(): Promise<boolean> {\n return _hasMediaAccess('camera', 'videoinput')\n },\n\n /**\n * Check if microphone access is available (permission granted or can be requested).\n *\n * @returns Promise resolving to boolean\n */\n async hasMicrophoneAccess(): Promise<boolean> {\n return _hasMediaAccess('microphone', 'audioinput')\n },\n\n /**\n * Request camera and/or microphone permission.\n * This will prompt the user for permission if not already granted.\n *\n * @param options - What to request (camera, microphone, or both)\n * @returns Promise resolving to true if granted\n */\n async requestPermission(options: { camera?: boolean; microphone?: boolean } = {}): Promise<boolean> {\n const { camera = false, microphone = false } = options\n\n if (!camera && !microphone) {\n return true\n }\n\n try {\n const stream = await this.getMediaStream({\n video: camera,\n audio: microphone,\n })\n // Stop all tracks immediately - we just needed to trigger the permission\n stream.getTracks().forEach((track) => track.stop())\n return true\n }\ncatch {\n return false\n }\n },\n\n /**\n * Stop all tracks in a media stream.\n *\n * @param stream - MediaStream to stop\n */\n stopStream(stream: MediaStream): void {\n stream.getTracks().forEach((track) => track.stop())\n },\n\n /**\n * Listen for device changes (camera/microphone plugged in or removed).\n *\n * @param callback - Function called when devices change\n * @returns Cleanup function to remove listener\n */\n onDeviceChange(callback: () => void): () => void {\n if (typeof navigator === 'undefined' || !navigator.mediaDevices) {\n return () => {}\n }\n\n navigator.mediaDevices.addEventListener('devicechange', callback)\n return () => navigator.mediaDevices.removeEventListener('devicechange', callback)\n },\n\n // Internal helper to build video constraints\n _buildVideoConstraints(options: CameraOptions): MediaTrackConstraints {\n return {\n deviceId: options.deviceId ? { exact: options.deviceId } : undefined,\n facingMode: options.facingMode,\n width: options.width,\n height: options.height,\n frameRate: options.frameRate,\n aspectRatio: options.aspectRatio,\n }\n },\n\n // Internal helper to build audio constraints\n _buildAudioConstraints(options: MicrophoneOptions): MediaTrackConstraints {\n return {\n deviceId: options.deviceId ? { exact: options.deviceId } : undefined,\n echoCancellation: options.echoCancellation,\n noiseSuppression: options.noiseSuppression,\n autoGainControl: options.autoGainControl,\n sampleRate: options.sampleRate,\n channelCount: options.channelCount,\n }\n },\n}\n\nexport default media\n",
|
|
31
|
+
"/**\n * @fileoverview Cross-Platform Native Sidebar API\n * @description Unified sidebar component that renders with native styling\n * on macOS, Windows, and Linux.\n * @module @craft-native/api/sidebar\n */\n\nimport { getPlatform, type Platform } from './process'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SidebarItem {\n id: string\n label: string\n icon?: string\n badge?: string | number\n selected?: boolean\n children?: SidebarItem[]\n expanded?: boolean\n enabled?: boolean\n tintColor?: string\n tooltip?: string\n}\n\nexport interface SidebarSection {\n id: string\n title?: string\n items: SidebarItem[]\n collapsible?: boolean\n collapsed?: boolean\n}\n\nexport interface SidebarConfig {\n /** Sidebar width in pixels */\n width?: number\n /** Sections with grouped items */\n sections?: SidebarSection[]\n /** Flat list of items (no sections) */\n items?: SidebarItem[]\n /** Show search field */\n showSearch?: boolean\n /** Search placeholder */\n searchPlaceholder?: string\n /**\n * Milliseconds to debounce search input. Set to `0` for instant search.\n * Default 80ms — fast enough to feel live, slow enough that fast typists\n * don't fire one bridge call per keystroke.\n */\n searchDebounceMs?: number\n /** Header title */\n headerTitle?: string\n /** Header subtitle */\n headerSubtitle?: string\n /** Allow resizing */\n resizable?: boolean\n /** Platform-specific style overrides */\n platform?: {\n macos?: MacOSSidebarConfig\n windows?: WindowsSidebarConfig\n linux?: LinuxSidebarConfig\n }\n}\n\nexport interface MacOSSidebarConfig {\n /** Use vibrancy effect */\n vibrancy?: boolean\n /** Material type for vibrancy */\n material?: 'sidebar' | 'headerView' | 'menu' | 'popover'\n /** Position traffic lights in sidebar (Settings/Tahoe style) */\n trafficLightsInSidebar?: boolean\n /** Hide titlebar separator */\n hideTitlebarSeparator?: boolean\n}\n\nexport interface WindowsSidebarConfig {\n /** Use Mica/Acrylic material */\n material?: 'mica' | 'acrylic' | 'none'\n /** Use Windows 11 rounded corners */\n rounded?: boolean\n}\n\nexport interface LinuxSidebarConfig {\n /** GTK theme variant */\n theme?: 'adwaita' | 'breeze' | 'auto'\n}\n\nexport interface SidebarSelectEvent {\n itemId: string\n sectionId?: string\n item: SidebarItem\n}\n\nexport interface SidebarSearchEvent {\n query: string\n}\n\n// ============================================================================\n// Platform Detection & Defaults\n// ============================================================================\n\nfunction getDefaults(platform: Platform): Partial<SidebarConfig> {\n switch (platform) {\n case 'macos':\n case 'darwin':\n return {\n width: 220,\n platform: {\n macos: {\n vibrancy: true,\n material: 'sidebar',\n trafficLightsInSidebar: false,\n hideTitlebarSeparator: false\n }\n }\n }\n case 'windows':\n case 'win32':\n return {\n width: 200,\n platform: {\n windows: {\n material: 'mica',\n rounded: true\n }\n }\n }\n case 'linux':\n return {\n width: 200,\n platform: {\n linux: {\n theme: 'auto'\n }\n }\n }\n default:\n return { width: 220 }\n }\n}\n\n// ============================================================================\n// CSS Generation\n// ============================================================================\n\nfunction generateCSS(config: SidebarConfig, platform: Platform): string {\n const width = config.width || 220\n\n // Base styles that work everywhere\n const baseStyles = `\n .craft-sidebar {\n width: ${width}px;\n height: 100%;\n display: flex;\n flex-direction: column;\n user-select: none;\n font-family: var(--craft-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--craft-font-size, 13px);\n }\n .craft-sidebar-header {\n padding: 12px 16px;\n border-bottom: 1px solid var(--craft-border);\n }\n .craft-sidebar-header-title {\n font-weight: 600;\n font-size: 14px;\n }\n .craft-sidebar-header-subtitle {\n font-size: 11px;\n opacity: 0.7;\n margin-top: 2px;\n }\n .craft-sidebar-search {\n padding: 8px 12px;\n }\n .craft-sidebar-search input {\n width: 100%;\n padding: 6px 10px;\n border-radius: var(--craft-radius, 6px);\n border: 1px solid var(--craft-border);\n background: var(--craft-input-bg);\n color: var(--craft-text);\n font-size: 13px;\n outline: none;\n }\n .craft-sidebar-search input:focus {\n border-color: var(--craft-accent);\n }\n .craft-sidebar-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 4px 0;\n }\n .craft-sidebar-section {\n margin-bottom: 8px;\n }\n .craft-sidebar-section-header {\n display: flex;\n align-items: center;\n padding: 6px 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n opacity: 0.6;\n cursor: pointer;\n }\n .craft-sidebar-section-header:hover {\n opacity: 0.8;\n }\n .craft-sidebar-section-chevron {\n width: 12px;\n height: 12px;\n margin-right: 4px;\n transition: transform 0.15s;\n }\n .craft-sidebar-section-header.collapsed .craft-sidebar-section-chevron {\n transform: rotate(-90deg);\n }\n .craft-sidebar-section-items {\n transition: max-height 0.2s ease-out, opacity 0.15s;\n }\n .craft-sidebar-section-items.collapsed {\n max-height: 0;\n opacity: 0;\n overflow: hidden;\n }\n .craft-sidebar-item {\n display: flex;\n align-items: center;\n padding: 6px 12px 6px 16px;\n margin: 1px 8px;\n border-radius: var(--craft-radius, 6px);\n cursor: pointer;\n gap: 8px;\n transition: background 0.1s;\n }\n .craft-sidebar-item:hover {\n background: var(--craft-hover);\n }\n .craft-sidebar-item.selected {\n background: var(--craft-accent);\n color: var(--craft-accent-text, #fff);\n }\n .craft-sidebar-item-icon {\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n }\n .craft-sidebar-item-label {\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .craft-sidebar-item-badge {\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n background: var(--craft-badge-bg);\n }\n .craft-sidebar-item.selected .craft-sidebar-item-badge {\n background: rgba(255,255,255,0.25);\n }\n .craft-sidebar-footer {\n padding: 8px 12px;\n border-top: 1px solid var(--craft-border);\n display: flex;\n gap: 4px;\n }\n `\n\n // Platform-specific styles\n let platformStyles = ''\n\n if (platform === 'macos' || platform === 'darwin') {\n const macConfig = config.platform?.macos\n platformStyles = `\n :root {\n --craft-font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;\n --craft-bg: ${macConfig?.vibrancy ? 'rgba(246,246,246,0.8)' : '#f6f6f6'};\n --craft-bg-dark: ${macConfig?.vibrancy ? 'rgba(30,30,30,0.8)' : '#1e1e1e'};\n --craft-text: #1d1d1f;\n --craft-text-dark: #f5f5f7;\n --craft-border: rgba(0,0,0,0.1);\n --craft-border-dark: rgba(255,255,255,0.1);\n --craft-hover: rgba(0,0,0,0.04);\n --craft-hover-dark: rgba(255,255,255,0.06);\n --craft-accent: #007aff;\n --craft-accent-text: #fff;\n --craft-input-bg: rgba(0,0,0,0.05);\n --craft-input-bg-dark: rgba(255,255,255,0.08);\n --craft-badge-bg: rgba(0,0,0,0.08);\n --craft-badge-bg-dark: rgba(255,255,255,0.1);\n --craft-radius: 6px;\n }\n .craft-sidebar {\n background: var(--craft-bg);\n color: var(--craft-text);\n ${macConfig?.vibrancy ? 'backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%);' : ''}\n border-right: 1px solid var(--craft-border);\n }\n @media (prefers-color-scheme: dark) {\n .craft-sidebar {\n background: var(--craft-bg-dark);\n color: var(--craft-text-dark);\n border-color: var(--craft-border-dark);\n }\n .craft-sidebar-item:hover { background: var(--craft-hover-dark); }\n .craft-sidebar-search input { background: var(--craft-input-bg-dark); }\n .craft-sidebar-item-badge { background: var(--craft-badge-bg-dark); }\n }\n `\n }\n else if (platform === 'windows' || platform === 'win32') {\n const winConfig = config.platform?.windows\n platformStyles = `\n :root {\n --craft-font-family: 'Segoe UI Variable', 'Segoe UI', sans-serif;\n --craft-bg: ${winConfig?.material === 'mica' ? 'rgba(243,243,243,0.9)' : '#f3f3f3'};\n --craft-bg-dark: ${winConfig?.material === 'mica' ? 'rgba(32,32,32,0.9)' : '#202020'};\n --craft-text: #1a1a1a;\n --craft-text-dark: #fff;\n --craft-border: rgba(0,0,0,0.08);\n --craft-border-dark: rgba(255,255,255,0.08);\n --craft-hover: rgba(0,0,0,0.04);\n --craft-hover-dark: rgba(255,255,255,0.06);\n --craft-accent: #0078d4;\n --craft-accent-text: #fff;\n --craft-input-bg: #fff;\n --craft-input-bg-dark: rgba(255,255,255,0.06);\n --craft-badge-bg: rgba(0,0,0,0.05);\n --craft-badge-bg-dark: rgba(255,255,255,0.08);\n --craft-radius: ${winConfig?.rounded ? '4px' : '0'};\n }\n .craft-sidebar {\n background: var(--craft-bg);\n color: var(--craft-text);\n ${winConfig?.material !== 'none' ? 'backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px);' : ''}\n }\n @media (prefers-color-scheme: dark) {\n .craft-sidebar {\n background: var(--craft-bg-dark);\n color: var(--craft-text-dark);\n }\n .craft-sidebar-item:hover { background: var(--craft-hover-dark); }\n .craft-sidebar-search input { background: var(--craft-input-bg-dark); border-color: var(--craft-border-dark); }\n .craft-sidebar-item-badge { background: var(--craft-badge-bg-dark); }\n }\n `\n }\n else {\n // Linux / GTK style\n platformStyles = `\n :root {\n --craft-font-family: 'Cantarell', 'Ubuntu', sans-serif;\n --craft-bg: #f6f5f4;\n --craft-bg-dark: #303030;\n --craft-text: #2e3436;\n --craft-text-dark: #fff;\n --craft-border: rgba(0,0,0,0.12);\n --craft-border-dark: rgba(255,255,255,0.12);\n --craft-hover: rgba(0,0,0,0.05);\n --craft-hover-dark: rgba(255,255,255,0.08);\n --craft-accent: #3584e4;\n --craft-accent-text: #fff;\n --craft-input-bg: #fff;\n --craft-input-bg-dark: rgba(255,255,255,0.08);\n --craft-badge-bg: rgba(0,0,0,0.08);\n --craft-badge-bg-dark: rgba(255,255,255,0.12);\n --craft-radius: 6px;\n }\n .craft-sidebar {\n background: var(--craft-bg);\n color: var(--craft-text);\n border-right: 1px solid var(--craft-border);\n }\n @media (prefers-color-scheme: dark) {\n .craft-sidebar {\n background: var(--craft-bg-dark);\n color: var(--craft-text-dark);\n border-color: var(--craft-border-dark);\n }\n .craft-sidebar-item:hover { background: var(--craft-hover-dark); }\n .craft-sidebar-search input { background: var(--craft-input-bg-dark); border-color: var(--craft-border-dark); }\n .craft-sidebar-item-badge { background: var(--craft-badge-bg-dark); }\n }\n `\n }\n\n return baseStyles + platformStyles\n}\n\n// ============================================================================\n// HTML Escaping\n// ============================================================================\n\nfunction escapeHtml(unsafe: string): string {\n return unsafe\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n}\n\n// ============================================================================\n// HTML Generation\n// ============================================================================\n\nfunction generateHTML(config: SidebarConfig): string {\n const renderItem = (item: SidebarItem): string => `\n <div class=\"craft-sidebar-item${item.selected ? ' selected' : ''}\" data-id=\"${escapeHtml(item.id)}\">\n ${item.icon ? `<span class=\"craft-sidebar-item-icon\">${getIcon(item.icon, item.tintColor)}</span>` : ''}\n <span class=\"craft-sidebar-item-label\">${escapeHtml(item.label)}</span>\n ${item.badge !== undefined ? `<span class=\"craft-sidebar-item-badge\">${escapeHtml(String(item.badge))}</span>` : ''}\n </div>\n `\n\n const renderSection = (section: SidebarSection): string => `\n <div class=\"craft-sidebar-section\" data-section=\"${escapeHtml(section.id)}\">\n ${section.title ? `\n <div class=\"craft-sidebar-section-header${section.collapsed ? ' collapsed' : ''}\" data-section-toggle=\"${escapeHtml(section.id)}\">\n ${section.collapsible !== false ? `<svg class=\"craft-sidebar-section-chevron\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"m9 18 6-6-6-6\"/></svg>` : ''}\n ${escapeHtml(section.title)}\n </div>\n ` : ''}\n <div class=\"craft-sidebar-section-items${section.collapsed ? ' collapsed' : ''}\" data-section-items=\"${escapeHtml(section.id)}\">\n ${section.items.map(renderItem).join('')}\n </div>\n </div>\n `\n\n return `\n <aside class='craft-sidebar'>\n ${config.headerTitle ? `\n <div class='craft-sidebar-header'>\n <div class='craft-sidebar-header-title'>${escapeHtml(config.headerTitle)}</div>\n ${config.headerSubtitle ? `<div class=\"craft-sidebar-header-subtitle\">${escapeHtml(config.headerSubtitle)}</div>` : ''}\n </div>\n ` : ''}\n ${config.showSearch ? `\n <div class='craft-sidebar-search'>\n <input type='text' placeholder='${escapeHtml(config.searchPlaceholder || 'Search')}' data-sidebar-search>\n </div>\n ` : ''}\n <div class='craft-sidebar-content'>\n ${config.sections?.map(renderSection).join('') || ''}\n ${config.items?.map(renderItem).join('') || ''}\n </div>\n </aside>\n `\n}\n\n// Simple icon helper - returns SVG for common icons\nfunction getIcon(name: string, tintColor?: string): string {\n const color = escapeHtml(tintColor || 'currentColor')\n const icons: Record<string, string> = {\n folder: `<svg viewBox='0 0 24 24' fill='${color}'><path d='M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z'/></svg>`,\n file: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><path d='M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z'/><polyline points='13 2 13 9 20 9'/></svg>`,\n home: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><path d='m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'/></svg>`,\n download: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><path d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/><polyline points='7 10 12 15 17 10'/><line x1='12' y1='15' x2='12' y2='3'/></svg>`,\n cloud: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><path d='M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z'/></svg>`,\n star: `<svg viewBox='0 0 24 24' fill='${color}'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>`,\n settings: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><circle cx='12' cy='12' r='3'/><path d='M12 1v2m0 18v2M4.22 4.22l1.42 1.42m12.72 12.72 1.42 1.42M1 12h2m18 0h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42'/></svg>`,\n user: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><path d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'/><circle cx='12' cy='7' r='4'/></svg>`,\n users: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><path d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/><circle cx='9' cy='7' r='4'/><path d='M23 21v-2a4 4 0 0 0-3-3.87m-4-12a4 4 0 0 1 0 7.75'/></svg>`,\n clock: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><circle cx='12' cy='12' r='10'/><polyline points='12 6 12 12 16 14'/></svg>`,\n computer: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><rect x='2' y='3' width='20' height='14' rx='2' ry='2'/><line x1='8' y1='21' x2='16' y2='21'/><line x1='12' y1='17' x2='12' y2='21'/></svg>`,\n globe: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><circle cx='12' cy='12' r='10'/><line x1='2' y1='12' x2='22' y2='12'/><path d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/></svg>`,\n tag: `<svg viewBox='0 0 24 24' fill='${color}'><circle cx='12' cy='12' r='8'/></svg>`,\n wifi: `<svg viewBox='0 0 24 24' fill='none' stroke='${color}' stroke-width='2'><path d='M5 12.55a11 11 0 0 1 14.08 0M1.42 9a16 16 0 0 1 21.16 0M8.53 16.11a6 6 0 0 1 6.95 0M12 20h.01'/></svg>`,\n }\n return icons[name] || icons.file\n}\n\n// ============================================================================\n// Sidebar Class\n// ============================================================================\n\nexport class Sidebar {\n private config: SidebarConfig\n private element: HTMLElement | null = null\n private onSelectHandler?: (event: SidebarSelectEvent) => void\n private onSearchHandler?: (event: SidebarSearchEvent) => void\n // Cleanup callbacks for the listeners attached by attachEventListeners.\n // Re-rendering replaces `this.element` via `outerHTML`, but the old DOM\n // node is reachable from event-loop callbacks until it's GC'd, so any\n // pending click on the old node would still fire its (stale) listener.\n // Calling these before reassigning the element prevents that.\n private listenerCleanups: Array<() => void> = []\n\n constructor(config: SidebarConfig = {}) {\n const platform = getPlatform()\n const defaults = getDefaults(platform)\n this.config = { ...defaults, ...config }\n }\n\n /** Render the sidebar and return HTML + CSS */\n render(): { html: string; css: string } {\n const platform = getPlatform()\n return {\n html: generateHTML(this.config),\n css: generateCSS(this.config, platform)\n }\n }\n\n /** Mount sidebar to a container element */\n mount(container: HTMLElement | string = 'body'): void {\n const target = typeof container === 'string'\n ? document.querySelector(container)\n : container\n\n if (!target) {\n console.error('[Sidebar] Container not found')\n return\n }\n\n const { html, css } = this.render()\n\n // Inject styles\n const styleEl = document.createElement('style')\n styleEl.textContent = css\n document.head.appendChild(styleEl)\n\n // Inject HTML\n target.insertAdjacentHTML('afterbegin', html)\n this.element = target.querySelector('.craft-sidebar')\n\n this.attachEventListeners()\n }\n\n /** Update configuration and re-render */\n update(config: Partial<SidebarConfig>): void {\n this.config = { ...this.config, ...config }\n if (this.element) {\n this.detachEventListeners()\n const { html } = this.render()\n this.element.outerHTML = html\n this.element = document.querySelector('.craft-sidebar')\n this.attachEventListeners()\n }\n }\n\n /** Tear down listeners and remove the sidebar from the DOM. */\n destroy(): void {\n this.detachEventListeners()\n if (this.element) {\n this.element.remove()\n this.element = null\n }\n }\n\n private detachEventListeners(): void {\n for (const cleanup of this.listenerCleanups) cleanup()\n this.listenerCleanups = []\n }\n\n /** Select an item programmatically */\n selectItem(itemId: string): void {\n if (!this.element) return\n this.element.querySelectorAll('.craft-sidebar-item').forEach(el => {\n el.classList.toggle('selected', el.getAttribute('data-id') === itemId)\n })\n }\n\n /** Register selection handler */\n onSelect(handler: (event: SidebarSelectEvent) => void): void {\n this.onSelectHandler = handler\n }\n\n /** Register search handler */\n onSearch(handler: (event: SidebarSearchEvent) => void): void {\n this.onSearchHandler = handler\n }\n\n private attachEventListeners(): void {\n if (!this.element) return\n\n const track = (target: Element, type: string, handler: EventListener) => {\n target.addEventListener(type, handler)\n this.listenerCleanups.push(() => target.removeEventListener(type, handler))\n }\n\n // Item clicks\n this.element.querySelectorAll('.craft-sidebar-item').forEach(item => {\n track(item, 'click', () => {\n const itemId = item.getAttribute('data-id')\n if (!itemId) return\n\n // Update selection\n this.element?.querySelectorAll('.craft-sidebar-item').forEach(el => {\n el.classList.remove('selected')\n })\n item.classList.add('selected')\n\n // Fire event\n if (this.onSelectHandler) {\n const sidebarItem = this.findItem(itemId)\n this.onSelectHandler({\n itemId,\n item: sidebarItem || { id: itemId, label: '' }\n })\n }\n })\n })\n\n // Section toggle\n this.element.querySelectorAll('[data-section-toggle]').forEach(header => {\n track(header, 'click', () => {\n const sectionId = header.getAttribute('data-section-toggle')\n const items = this.element?.querySelector(`[data-section-items='${sectionId}']`)\n if (items) {\n header.classList.toggle('collapsed')\n items.classList.toggle('collapsed')\n }\n })\n })\n\n // Search. Debounced so fast typing doesn't fire one bridge call per\n // keystroke. Filtering still runs locally on the input element so the\n // visible UI stays responsive; only the `onSearchHandler` event is\n // throttled.\n const searchInput = this.element.querySelector('[data-sidebar-search]') as HTMLInputElement\n if (searchInput) {\n const debounceMs = this.config.searchDebounceMs ?? 80\n let debounceTimer: ReturnType<typeof setTimeout> | null = null\n this.listenerCleanups.push(() => {\n if (debounceTimer) clearTimeout(debounceTimer)\n })\n\n track(searchInput, 'input', () => {\n const query = searchInput.value.toLowerCase()\n\n // Filter items immediately for snappy local feedback.\n this.element?.querySelectorAll('.craft-sidebar-item').forEach(item => {\n const label = item.querySelector('.craft-sidebar-item-label')?.textContent?.toLowerCase() || ''\n ;(item as HTMLElement).style.display = label.includes(query) ? '' : 'none'\n })\n\n if (!this.onSearchHandler) return\n if (debounceMs <= 0) {\n this.onSearchHandler({ query: searchInput.value })\n return\n }\n if (debounceTimer) clearTimeout(debounceTimer)\n debounceTimer = setTimeout(() => {\n debounceTimer = null\n this.onSearchHandler?.({ query: searchInput.value })\n }, debounceMs)\n })\n }\n }\n\n private findItem(itemId: string): SidebarItem | undefined {\n const searchItems = (items: SidebarItem[]): SidebarItem | undefined => {\n for (const item of items) {\n if (item.id === itemId) return item\n if (item.children) {\n const found = searchItems(item.children)\n if (found) return found\n }\n }\n }\n\n if (this.config.items) {\n const found = searchItems(this.config.items)\n if (found) return found\n }\n\n for (const section of this.config.sections || []) {\n const found = searchItems(section.items)\n if (found) return found\n }\n }\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/** Create a sidebar with platform-appropriate defaults */\nexport function createSidebar(config: SidebarConfig = {}): Sidebar {\n return new Sidebar(config)\n}\n\n/** Create a file-browser style sidebar (Finder/Explorer) */\nexport function createFileSidebar(sections?: SidebarSection[]): Sidebar {\n const p = getPlatform()\n const isMac = p === 'macos' || p === 'darwin'\n const defaultSections: SidebarSection[] = [\n {\n id: 'favorites',\n title: 'Favorites',\n collapsible: true,\n items: [\n { id: 'home', label: 'Home', icon: 'home' },\n { id: 'desktop', label: 'Desktop', icon: 'computer' },\n { id: 'documents', label: 'Documents', icon: 'folder' },\n { id: 'downloads', label: 'Downloads', icon: 'download' }\n ]\n },\n {\n id: 'cloud',\n title: isMac ? 'iCloud' : 'Cloud',\n collapsible: true,\n items: [\n { id: 'cloud-drive', label: isMac ? 'iCloud Drive' : 'Cloud Storage', icon: 'cloud' }\n ]\n },\n {\n id: 'locations',\n title: 'Locations',\n collapsible: true,\n items: [\n { id: 'this-pc', label: isMac ? 'This Mac' : 'This PC', icon: 'computer' },\n { id: 'network', label: 'Network', icon: 'globe' }\n ]\n }\n ]\n\n return new Sidebar({\n sections: sections || defaultSections,\n showSearch: true,\n searchPlaceholder: 'Search'\n })\n}\n\n/** Create a settings/preferences style sidebar */\nexport function createSettingsSidebar(items: SidebarItem[]): Sidebar {\n return new Sidebar({\n items,\n showSearch: true,\n searchPlaceholder: 'Search settings',\n platform: {\n macos: {\n vibrancy: true,\n trafficLightsInSidebar: true,\n hideTitlebarSeparator: true\n },\n windows: {\n material: 'mica',\n rounded: true\n }\n }\n })\n}\n\n// ============================================================================\n// Convenience Export\n// ============================================================================\n\nexport const sidebar: {\n create: typeof createSidebar\n file: typeof createFileSidebar\n settings: typeof createSettingsSidebar\n Sidebar: typeof Sidebar\n} = {\n create: createSidebar,\n file: createFileSidebar,\n settings: createSettingsSidebar,\n Sidebar: Sidebar\n}\n\nexport default sidebar\n",
|
|
32
|
+
"/**\n * Craft Sidebar Components\n * Native sidebar implementations with different styles:\n * - Tahoe (the macOS Tahoe source list — macOS 26/27)\n * - Arc (Browser-style collapsible vertical tabs)\n * - OrbStack (Dark minimal sidebar)\n *\n * These drive the NATIVE (NSOutlineView) sidebar. For web-rendered sidebars\n * in stx apps, use `@stacksjs/components`' <Sidebar theme=\"macos\"> over a\n * `webSidebarMaterial` window — that component is the canonical macOS look.\n * @module @craft-native/components/sidebar\n */\n\nimport { getBridge } from '../bridge/core'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Sidebar item — components-flavored.\n *\n * NOTE: there is a separate `SidebarItem` type in `api/sidebar` with a\n * narrower shape (only `tintColor` / `enabled` / no `contextMenu`). The\n * top-level package exports the api version; if you reach into\n * `craft-native/components` directly you will get *this* one.\n * Don't rely on cross-mixing the two.\n */\nexport interface SidebarItem {\n /** Unique identifier */\n id: string\n /** Display label */\n label: string\n /** Icon (SF Symbol name, path, or emoji) */\n icon?: string\n /** Badge text/number */\n badge?: string | number\n /** Badge color */\n badgeColor?: string\n /** Whether item is selected */\n selected?: boolean\n /** Whether item is disabled */\n disabled?: boolean\n /** Whether item is expandable/collapsible */\n expandable?: boolean\n /** Whether item is expanded (if expandable) */\n expanded?: boolean\n /** Child items */\n children?: SidebarItem[]\n /** Custom data */\n data?: Record<string, any>\n /** Tooltip */\n tooltip?: string\n /** Context menu items */\n contextMenu?: ContextMenuItem[]\n /** Whether item is draggable */\n draggable?: boolean\n /** Drop target types accepted */\n dropTypes?: string[]\n}\n\n/**\n * Sidebar section (group of items)\n */\nexport interface SidebarSection {\n /** Section ID */\n id: string\n /** Section title (can be empty for untitled section) */\n title?: string\n /** Items in this section */\n items: SidebarItem[]\n /** Whether section is collapsible */\n collapsible?: boolean\n /** Whether section is collapsed */\n collapsed?: boolean\n}\n\n/**\n * Context menu item\n */\nexport interface ContextMenuItem {\n /** Item ID */\n id?: string\n /** Label */\n label?: string\n /** Item type */\n type?: 'normal' | 'separator' | 'checkbox'\n /** Icon */\n icon?: string\n /** Keyboard shortcut */\n shortcut?: string\n /** Checked state */\n checked?: boolean\n /** Disabled state */\n disabled?: boolean\n /** Submenu items */\n submenu?: ContextMenuItem[]\n}\n\n/**\n * Sidebar style presets\n */\nexport type SidebarStyle = 'tahoe' | 'arc' | 'orbstack' | 'custom'\n\n/**\n * Sidebar position\n */\nexport type SidebarPosition = 'left' | 'right'\n\n/**\n * Sidebar configuration\n */\nexport interface SidebarConfig {\n /** Sidebar style preset */\n style?: SidebarStyle\n /** Position (left or right) */\n position?: SidebarPosition\n /** Width in pixels */\n width?: number\n /** Minimum width */\n minWidth?: number\n /** Maximum width */\n maxWidth?: number\n /** Whether sidebar is collapsible */\n collapsible?: boolean\n /** Whether sidebar starts collapsed */\n collapsed?: boolean\n /** Collapsed width (for icon-only mode) */\n collapsedWidth?: number\n /** Enable resizing */\n resizable?: boolean\n /** Background color (or vibrancy for macOS) */\n background?: string | 'sidebar' | 'window' | 'selection' | 'menu' | 'popover' | 'under-window'\n /** Show separator line */\n showSeparator?: boolean\n /** Separator color */\n separatorColor?: string\n /** Enable search */\n searchable?: boolean\n /** Search placeholder */\n searchPlaceholder?: string\n /** Enable drag and drop */\n dragAndDrop?: boolean\n /** Sections */\n sections?: SidebarSection[]\n /** Flat items (no sections) */\n items?: SidebarItem[]\n /** Header content */\n header?: SidebarHeaderConfig\n /** Footer content */\n footer?: SidebarFooterConfig\n}\n\n/**\n * Sidebar header configuration\n */\nexport interface SidebarHeaderConfig {\n /** Title */\n title?: string\n /** Subtitle */\n subtitle?: string\n /** Icon/avatar */\n icon?: string\n /** Custom height */\n height?: number\n /** Show collapse button */\n showCollapseButton?: boolean\n /** Custom actions */\n actions?: Array<{ id: string; icon: string; tooltip?: string }>\n}\n\n/**\n * Sidebar footer configuration\n */\nexport interface SidebarFooterConfig {\n /** Items */\n items?: SidebarItem[]\n /** Custom height */\n height?: number\n /** Show settings button */\n showSettings?: boolean\n /** Custom content */\n content?: string\n}\n\n/**\n * Sidebar event types\n */\nexport type SidebarEventType =\n | 'select'\n | 'double-click'\n | 'context-menu'\n | 'expand'\n | 'collapse'\n | 'resize'\n | 'search'\n | 'drag-start'\n | 'drag-end'\n | 'drop'\n | 'reorder'\n | 'header-action'\n | 'footer-action'\n\n/**\n * Sidebar event data map\n */\nexport interface SidebarEventMap {\n 'select': { item: SidebarItem; section?: SidebarSection }\n 'double-click': { item: SidebarItem; section?: SidebarSection }\n 'context-menu': { item: SidebarItem; section?: SidebarSection; menuItemId: string }\n 'expand': { item: SidebarItem }\n 'collapse': { item: SidebarItem }\n 'resize': { width: number }\n 'search': { query: string }\n 'drag-start': { item: SidebarItem }\n 'drag-end': { item: SidebarItem; cancelled: boolean }\n 'drop': { item: SidebarItem; target: SidebarItem | null; position: 'before' | 'after' | 'inside' }\n 'reorder': { items: SidebarItem[]; section?: SidebarSection }\n 'header-action': { actionId: string }\n 'footer-action': { actionId: string }\n}\n\n/**\n * Sidebar event handler\n */\nexport type SidebarEventHandler<T extends SidebarEventType> = (_data: SidebarEventMap[T]) => void\n\n// ============================================================================\n// Style Presets\n// ============================================================================\n\n/**\n * Tahoe style (macOS Sonoma/Sequoia Finder)\n * - Source list appearance\n * - Translucent sidebar background\n * - SF Symbol icons\n * - Native selection highlighting\n */\nexport const tahoeStyle: Partial<SidebarConfig> = {\n style: 'tahoe',\n width: 220,\n minWidth: 150,\n maxWidth: 350,\n collapsible: true,\n collapsedWidth: 0,\n resizable: true,\n background: 'sidebar',\n showSeparator: false,\n searchable: true,\n searchPlaceholder: 'Search',\n dragAndDrop: true\n}\n\n/**\n * Arc style (Browser vertical tabs)\n * - Compact, icon-focused when collapsed\n * - Animated expand/collapse\n * - Pill-shaped selection\n * - Hover preview\n */\nexport const arcStyle: Partial<SidebarConfig> = {\n style: 'arc',\n width: 260,\n minWidth: 48,\n maxWidth: 320,\n collapsible: true,\n collapsedWidth: 48,\n resizable: true,\n background: 'under-window',\n showSeparator: true,\n searchable: true,\n searchPlaceholder: 'Search tabs...',\n dragAndDrop: true\n}\n\n/**\n * OrbStack style (Dark minimal)\n * - Dark background\n * - Minimal chrome\n * - Subtle hover states\n * - Compact spacing\n */\nexport const orbstackStyle: Partial<SidebarConfig> = {\n style: 'orbstack',\n width: 200,\n minWidth: 160,\n maxWidth: 280,\n collapsible: true,\n collapsedWidth: 0,\n resizable: false,\n background: '#1a1a1a',\n showSeparator: true,\n separatorColor: '#333',\n searchable: false,\n dragAndDrop: false\n}\n\n// ============================================================================\n// Sidebar Class\n// ============================================================================\n\n/**\n * Native sidebar component\n */\nexport class Sidebar {\n private _id: string\n private _config: SidebarConfig\n private _listeners: Map<string, Set<Function>> = new Map()\n private _items: Map<string, SidebarItem> = new Map()\n private _selectedId: string | null = null\n private _destroyed: boolean = false\n\n constructor(config: SidebarConfig = {}) {\n this._id = `sidebar_${Date.now()}`\n this._config = this._applyStylePreset(config)\n this._indexItems()\n this._setupEventListeners()\n }\n\n /**\n * Get sidebar ID\n */\n get id(): string {\n return this._id\n }\n\n /**\n * Get current configuration\n */\n get config(): SidebarConfig {\n return { ...this._config }\n }\n\n /**\n * Get currently selected item ID\n */\n get selectedId(): string | null {\n return this._selectedId\n }\n\n /**\n * Get currently selected item\n */\n get selectedItem(): SidebarItem | null {\n return this._selectedId ? this._items.get(this._selectedId) || null : null\n }\n\n /**\n * Check if sidebar is collapsed\n */\n get isCollapsed(): boolean {\n return this._config.collapsed || false\n }\n\n private _applyStylePreset(config: SidebarConfig): SidebarConfig {\n let preset: Partial<SidebarConfig> = {}\n\n switch (config.style) {\n case 'tahoe':\n preset = tahoeStyle\n break\n case 'arc':\n preset = arcStyle\n break\n case 'orbstack':\n preset = orbstackStyle\n break\n }\n\n return { ...preset, ...config }\n }\n\n private _indexItems(): void {\n this._items.clear()\n\n const index = (items: SidebarItem[] | undefined) => {\n if (!items) return\n items.forEach(item => {\n this._items.set(item.id, item)\n if (item.children) {\n index(item.children)\n }\n })\n }\n\n index(this._config.items)\n this._config.sections?.forEach(section => {\n index(section.items)\n })\n }\n\n private _setupEventListeners(): void {\n if (typeof window !== 'undefined') {\n const events: SidebarEventType[] = [\n 'select', 'double-click', 'context-menu', 'expand', 'collapse',\n 'resize', 'search', 'drag-start', 'drag-end', 'drop', 'reorder',\n 'header-action', 'footer-action'\n ]\n\n events.forEach(event => {\n window.addEventListener(`craft:sidebar:${event}` as any, (e: CustomEvent) => {\n if (e.detail?.sidebarId === this._id) {\n if (event === 'select') {\n this._selectedId = e.detail?.item?.id || null\n }\n this._emit(event, e.detail)\n }\n })\n })\n }\n }\n\n private _emit(event: string, data?: any): void {\n const listeners = this._listeners.get(event)\n if (listeners) {\n listeners.forEach(fn => fn(data))\n }\n }\n\n /**\n * Register an event handler\n */\n on<T extends SidebarEventType>(event: T, handler: SidebarEventHandler<T>): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n this._listeners.get(event)!.add(handler)\n\n return () => {\n this._listeners.get(event)?.delete(handler)\n }\n }\n\n /**\n * Register a one-time event handler\n */\n once<T extends SidebarEventType>(event: T, handler: SidebarEventHandler<T>): () => void {\n const wrapper = (data: SidebarEventMap[T]) => {\n this._listeners.get(event)?.delete(wrapper)\n handler(data)\n }\n return this.on(event, wrapper as any)\n }\n\n /**\n * Remove event handler\n */\n off<T extends SidebarEventType>(event: T, handler: SidebarEventHandler<T>): void {\n this._listeners.get(event)?.delete(handler)\n }\n\n // ==========================================================================\n // Sidebar Control\n // ==========================================================================\n\n /**\n * Initialize and render the sidebar\n */\n async create(): Promise<void> {\n await this._call('create', { config: this._config })\n }\n\n /**\n * Update sidebar configuration\n */\n async update(config: Partial<SidebarConfig>): Promise<void> {\n this._config = { ...this._config, ...config }\n this._indexItems()\n await this._call('update', { config: this._config })\n }\n\n /**\n * Collapse the sidebar\n */\n async collapse(): Promise<void> {\n this._config.collapsed = true\n await this._call('collapse')\n }\n\n /**\n * Expand the sidebar\n */\n async expand(): Promise<void> {\n this._config.collapsed = false\n await this._call('expand')\n }\n\n /**\n * Toggle sidebar collapsed state\n */\n async toggle(): Promise<void> {\n if (this._config.collapsed) {\n await this.expand()\n }\nelse {\n await this.collapse()\n }\n }\n\n /**\n * Set sidebar width\n */\n async setWidth(width: number): Promise<void> {\n this._config.width = Math.max(\n this._config.minWidth || 0,\n Math.min(width, this._config.maxWidth || Infinity)\n )\n await this._call('setWidth', { width: this._config.width })\n }\n\n /**\n * Destroy the sidebar\n */\n async destroy(): Promise<void> {\n await this._call('destroy')\n this._destroyed = true\n this._listeners.clear()\n }\n\n // ==========================================================================\n // Item Management\n // ==========================================================================\n\n /**\n * Select an item by ID\n */\n async select(itemId: string): Promise<void> {\n this._selectedId = itemId\n await this._call('select', { itemId })\n }\n\n /**\n * Clear selection\n */\n async clearSelection(): Promise<void> {\n this._selectedId = null\n await this._call('clearSelection')\n }\n\n /**\n * Get item by ID\n */\n getItem(itemId: string): SidebarItem | undefined {\n return this._items.get(itemId)\n }\n\n /**\n * Add a new item\n */\n async addItem(item: SidebarItem, options?: { sectionId?: string; parentId?: string; index?: number }): Promise<void> {\n this._items.set(item.id, item)\n await this._call('addItem', { item, ...options })\n }\n\n /**\n * Update an existing item\n */\n async updateItem(itemId: string, updates: Partial<SidebarItem>): Promise<void> {\n const item = this._items.get(itemId)\n if (item) {\n Object.assign(item, updates)\n await this._call('updateItem', { itemId, updates })\n }\n }\n\n /**\n * Remove an item\n */\n async removeItem(itemId: string): Promise<void> {\n this._items.delete(itemId)\n if (this._selectedId === itemId) {\n this._selectedId = null\n }\n await this._call('removeItem', { itemId })\n }\n\n /**\n * Set items (replace all)\n */\n async setItems(items: SidebarItem[]): Promise<void> {\n this._config.items = items\n this._indexItems()\n await this._call('setItems', { items })\n }\n\n /**\n * Set sections (replace all)\n */\n async setSections(sections: SidebarSection[]): Promise<void> {\n this._config.sections = sections\n this._indexItems()\n await this._call('setSections', { sections })\n }\n\n /**\n * Expand an item (show children)\n */\n async expandItem(itemId: string): Promise<void> {\n const item = this._items.get(itemId)\n if (item) {\n item.expanded = true\n await this._call('expandItem', { itemId })\n }\n }\n\n /**\n * Collapse an item (hide children)\n */\n async collapseItem(itemId: string): Promise<void> {\n const item = this._items.get(itemId)\n if (item) {\n item.expanded = false\n await this._call('collapseItem', { itemId })\n }\n }\n\n /**\n * Scroll to item\n */\n async scrollToItem(itemId: string): Promise<void> {\n await this._call('scrollToItem', { itemId })\n }\n\n /**\n * Update item badge\n */\n async setBadge(itemId: string, badge: string | number | null): Promise<void> {\n const item = this._items.get(itemId)\n if (item) {\n item.badge = badge ?? undefined\n await this._call('setBadge', { itemId, badge })\n }\n }\n\n // ==========================================================================\n // Section Management\n // ==========================================================================\n\n /**\n * Add a new section\n */\n async addSection(section: SidebarSection, index?: number): Promise<void> {\n if (!this._config.sections) {\n this._config.sections = []\n }\n if (index !== undefined) {\n this._config.sections.splice(index, 0, section)\n }\nelse {\n this._config.sections.push(section)\n }\n section.items.forEach(item => this._items.set(item.id, item))\n await this._call('addSection', { section, index })\n }\n\n /**\n * Update a section\n */\n async updateSection(sectionId: string, updates: Partial<SidebarSection>): Promise<void> {\n const section = this._config.sections?.find(s => s.id === sectionId)\n if (section) {\n Object.assign(section, updates)\n if (updates.items) {\n updates.items.forEach(item => this._items.set(item.id, item))\n }\n await this._call('updateSection', { sectionId, updates })\n }\n }\n\n /**\n * Remove a section\n */\n async removeSection(sectionId: string): Promise<void> {\n const index = this._config.sections?.findIndex(s => s.id === sectionId)\n if (index !== undefined && index >= 0 && this._config.sections) {\n const section = this._config.sections[index]\n section.items.forEach(item => this._items.delete(item.id))\n this._config.sections.splice(index, 1)\n await this._call('removeSection', { sectionId })\n }\n }\n\n /**\n * Collapse a section\n */\n async collapseSection(sectionId: string): Promise<void> {\n const section = this._config.sections?.find(s => s.id === sectionId)\n if (section) {\n section.collapsed = true\n await this._call('collapseSection', { sectionId })\n }\n }\n\n /**\n * Expand a section\n */\n async expandSection(sectionId: string): Promise<void> {\n const section = this._config.sections?.find(s => s.id === sectionId)\n if (section) {\n section.collapsed = false\n await this._call('expandSection', { sectionId })\n }\n }\n\n // ==========================================================================\n // Search\n // ==========================================================================\n\n /**\n * Set search query programmatically\n */\n async setSearchQuery(query: string): Promise<void> {\n await this._call('setSearchQuery', { query })\n }\n\n /**\n * Clear search\n */\n async clearSearch(): Promise<void> {\n await this._call('clearSearch')\n }\n\n /**\n * Focus search input\n */\n async focusSearch(): Promise<void> {\n await this._call('focusSearch')\n }\n\n // ==========================================================================\n // Helper Methods\n // ==========================================================================\n\n private async _call<T = void>(action: string, data?: Record<string, any>): Promise<T> {\n const payload = { sidebarId: this._id, ...data }\n\n if (typeof window !== 'undefined' && (window as any).webkit?.messageHandlers?.craft) {\n return new Promise((resolve, reject) => {\n try {\n (window as any).webkit.messageHandlers.craft.postMessage({\n type: 'sidebar',\n action,\n data: payload\n })\n resolve(undefined as T)\n }\ncatch (error) {\n reject(error)\n }\n })\n }\n\n const bridge = getBridge()\n return bridge.request(`sidebar.${action}`, payload)\n }\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/**\n * Create a Tahoe-style sidebar (macOS Finder)\n */\nexport function createTahoeSidebar(config: Omit<SidebarConfig, 'style'> = {}): Sidebar {\n return new Sidebar({ ...tahoeStyle, ...config, style: 'tahoe' })\n}\n\n/**\n * Create an Arc-style sidebar (Browser tabs)\n */\nexport function createArcSidebar(config: Omit<SidebarConfig, 'style'> = {}): Sidebar {\n return new Sidebar({ ...arcStyle, ...config, style: 'arc' })\n}\n\n/**\n * Create an OrbStack-style sidebar (Dark minimal)\n */\nexport function createOrbStackSidebar(config: Omit<SidebarConfig, 'style'> = {}): Sidebar {\n return new Sidebar({ ...orbstackStyle, ...config, style: 'orbstack' })\n}\n\n/**\n * Create a custom sidebar\n */\nexport function createSidebar(config: SidebarConfig = {}): Sidebar {\n return new Sidebar(config)\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Create a sidebar item\n */\nexport function sidebarItem(id: string, label: string, options: Omit<SidebarItem, 'id' | 'label'> = {}): SidebarItem {\n return { id, label, ...options }\n}\n\n/**\n * Create a sidebar section\n */\nexport function sidebarSection(id: string, items: SidebarItem[], options: Omit<SidebarSection, 'id' | 'items'> = {}): SidebarSection {\n return { id, items, ...options }\n}\n\n/**\n * Create a separator item (displayed as a divider)\n */\nexport function sidebarSeparator(id?: string): SidebarItem {\n return { id: id || `separator_${Date.now()}`, label: '', disabled: true }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nconst sidebarModule: {\n Sidebar: typeof Sidebar\n createSidebar: typeof createSidebar\n createTahoeSidebar: typeof createTahoeSidebar\n createArcSidebar: typeof createArcSidebar\n createOrbStackSidebar: typeof createOrbStackSidebar\n sidebarItem: typeof sidebarItem\n sidebarSection: typeof sidebarSection\n sidebarSeparator: typeof sidebarSeparator\n tahoeStyle: typeof tahoeStyle\n arcStyle: typeof arcStyle\n orbstackStyle: typeof orbstackStyle\n} = {\n Sidebar: Sidebar,\n createSidebar: createSidebar,\n createTahoeSidebar: createTahoeSidebar,\n createArcSidebar: createArcSidebar,\n createOrbStackSidebar: createOrbStackSidebar,\n sidebarItem: sidebarItem,\n sidebarSection: sidebarSection,\n sidebarSeparator: sidebarSeparator,\n tahoeStyle: tahoeStyle,\n arcStyle: arcStyle,\n orbstackStyle: orbstackStyle\n}\n\nexport default sidebarModule\n",
|
|
33
|
+
"/**\n * Craft Native UI Components\n * Type-safe bindings for native platform UI components\n * @module @craft-native/components/native\n */\n\nimport { getBridge } from '../bridge/core'\n\n// Monotonically increasing counter ensures IDs stay unique even when multiple\n// components are created in the same millisecond — `Date.now()` alone collides.\nlet _componentIdCounter = 0\nfunction nextComponentId(prefix: string): string {\n _componentIdCounter++\n return `${prefix}_${Date.now()}_${_componentIdCounter}`\n}\n\n// ============================================================================\n// Base Types\n// ============================================================================\n\n/**\n * Base component props\n */\nexport interface ComponentProps {\n /** Unique component ID */\n id?: string\n /** CSS class names */\n className?: string\n /** Inline styles */\n style?: Record<string, any>\n /** Hidden state */\n hidden?: boolean\n /** Disabled state */\n disabled?: boolean\n /** Tooltip text */\n tooltip?: string\n}\n\n/**\n * Component instance\n */\nexport interface ComponentInstance {\n /** Component ID */\n id: string\n /** Component type */\n type: string\n /** Update component properties */\n update(props: Record<string, any>): Promise<void>\n /** Destroy component */\n destroy(): Promise<void>\n /** Show component */\n show(): Promise<void>\n /** Hide component */\n hide(): Promise<void>\n /** Focus component */\n focus(): Promise<void>\n /** Register event handler */\n on(event: string, handler: Function): () => void\n}\n\n// ============================================================================\n// Split View\n// ============================================================================\n\n/**\n * Split view orientation\n */\nexport type SplitViewOrientation = 'horizontal' | 'vertical'\n\n/**\n * Split view divider style\n */\nexport type SplitViewDividerStyle = 'thin' | 'thick' | 'paneSplitter'\n\n/**\n * Split view configuration\n */\nexport interface SplitViewConfig extends ComponentProps {\n /** Split orientation */\n orientation?: SplitViewOrientation\n /** Divider style */\n dividerStyle?: SplitViewDividerStyle\n /** Initial divider position (percentage or pixels) */\n position?: number\n /** Minimum position for each pane */\n minPositions?: [number, number]\n /** Maximum position for each pane */\n maxPositions?: [number, number]\n /** Autosave position with key */\n autosaveName?: string\n}\n\n/**\n * Create a native split view\n */\nexport async function createSplitView(config: SplitViewConfig = {}): Promise<SplitViewInstance> {\n const id = config.id || nextComponentId('splitview')\n await callNative('component.createSplitView', { id, config })\n return new SplitViewInstance(id, config)\n}\n\n/**\n * Split view instance\n */\nexport class SplitViewInstance implements ComponentInstance {\n id: string\n type = 'splitView'\n private _config: SplitViewConfig\n private _listeners: Map<string, Set<Function>> = new Map()\n\n constructor(id: string, config: SplitViewConfig) {\n this.id = id\n this._config = config\n this._setupListeners()\n }\n\n private _setupListeners(): void {\n if (typeof window !== 'undefined') {\n window.addEventListener(`craft:splitView:${this.id}:resize` as any, (e: CustomEvent) => {\n this._emit('resize', e.detail)\n })\n }\n }\n\n private _emit(event: string, data?: any): void {\n this._listeners.get(event)?.forEach(fn => fn(data))\n }\n\n on(event: string, handler: Function): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n this._listeners.get(event)!.add(handler)\n return () => this._listeners.get(event)?.delete(handler)\n }\n\n async update(props: Partial<SplitViewConfig>): Promise<void> {\n Object.assign(this._config, props)\n await callNative('component.update', { id: this.id, props })\n }\n\n async destroy(): Promise<void> {\n await callNative('component.destroy', { id: this.id })\n }\n\n async show(): Promise<void> {\n await callNative('component.show', { id: this.id })\n }\n\n async hide(): Promise<void> {\n await callNative('component.hide', { id: this.id })\n }\n\n async focus(): Promise<void> {\n await callNative('component.focus', { id: this.id })\n }\n\n /**\n * Set divider position\n */\n async setPosition(position: number, animated?: boolean): Promise<void> {\n this._config.position = position\n await callNative('splitView.setPosition', { id: this.id, position, animated })\n }\n\n /**\n * Get current divider position\n */\n async getPosition(): Promise<number> {\n return callNative('splitView.getPosition', { id: this.id })\n }\n\n /**\n * Collapse a pane\n */\n async collapsePane(index: 0 | 1): Promise<void> {\n await callNative('splitView.collapsePane', { id: this.id, index })\n }\n\n /**\n * Expand a pane\n */\n async expandPane(index: 0 | 1): Promise<void> {\n await callNative('splitView.expandPane', { id: this.id, index })\n }\n}\n\n// ============================================================================\n// File Browser\n// ============================================================================\n\n/**\n * File browser configuration\n */\nexport interface FileBrowserConfig extends ComponentProps {\n /** Root path to browse */\n rootPath?: string\n /** Show hidden files */\n showHidden?: boolean\n /** Selection mode */\n selectionMode?: 'single' | 'multiple' | 'none'\n /** File filter */\n fileFilter?: Array<{ name: string; extensions: string[] }>\n /** Show path bar */\n showPathBar?: boolean\n /** Show toolbar */\n showToolbar?: boolean\n /** Show sidebar */\n showSidebar?: boolean\n /** Show preview */\n showPreview?: boolean\n /** View mode */\n viewMode?: 'list' | 'icon' | 'column' | 'gallery'\n /** Sort by */\n sortBy?: 'name' | 'date' | 'size' | 'kind'\n /** Sort order */\n sortOrder?: 'ascending' | 'descending'\n /** Allow directory selection */\n allowDirectorySelection?: boolean\n /** Allow file creation */\n allowFileCreation?: boolean\n}\n\n/**\n * File browser selection\n */\nexport interface FileBrowserSelection {\n /** Selected file paths */\n paths: string[]\n /** Selected file info */\n files: Array<{\n path: string\n name: string\n isDirectory: boolean\n size: number\n modified: Date\n }>\n}\n\n/**\n * Create a native file browser\n */\nexport async function createFileBrowser(config: FileBrowserConfig = {}): Promise<FileBrowserInstance> {\n const id = config.id || nextComponentId('filebrowser')\n await callNative('component.createFileBrowser', { id, config })\n return new FileBrowserInstance(id, config)\n}\n\n/**\n * File browser instance\n */\nexport class FileBrowserInstance implements ComponentInstance {\n id: string\n type = 'fileBrowser'\n private _config: FileBrowserConfig\n private _listeners: Map<string, Set<Function>> = new Map()\n\n constructor(id: string, config: FileBrowserConfig) {\n this.id = id\n this._config = config\n this._setupListeners()\n }\n\n private _setupListeners(): void {\n if (typeof window !== 'undefined') {\n const events = ['select', 'open', 'navigate', 'context-menu']\n events.forEach(event => {\n window.addEventListener(`craft:fileBrowser:${this.id}:${event}` as any, (e: CustomEvent) => {\n this._emit(event, e.detail)\n })\n })\n }\n }\n\n private _emit(event: string, data?: any): void {\n this._listeners.get(event)?.forEach(fn => fn(data))\n }\n\n on(event: string, handler: Function): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n this._listeners.get(event)!.add(handler)\n return () => this._listeners.get(event)?.delete(handler)\n }\n\n async update(props: Partial<FileBrowserConfig>): Promise<void> {\n Object.assign(this._config, props)\n await callNative('component.update', { id: this.id, props })\n }\n\n async destroy(): Promise<void> {\n await callNative('component.destroy', { id: this.id })\n }\n\n async show(): Promise<void> {\n await callNative('component.show', { id: this.id })\n }\n\n async hide(): Promise<void> {\n await callNative('component.hide', { id: this.id })\n }\n\n async focus(): Promise<void> {\n await callNative('component.focus', { id: this.id })\n }\n\n /**\n * Get current selection\n */\n async getSelection(): Promise<FileBrowserSelection> {\n return callNative('fileBrowser.getSelection', { id: this.id })\n }\n\n /**\n * Set selection\n */\n async setSelection(paths: string[]): Promise<void> {\n await callNative('fileBrowser.setSelection', { id: this.id, paths })\n }\n\n /**\n * Navigate to path\n */\n async navigateTo(path: string): Promise<void> {\n await callNative('fileBrowser.navigateTo', { id: this.id, path })\n }\n\n /**\n * Go back in history\n */\n async goBack(): Promise<void> {\n await callNative('fileBrowser.goBack', { id: this.id })\n }\n\n /**\n * Go forward in history\n */\n async goForward(): Promise<void> {\n await callNative('fileBrowser.goForward', { id: this.id })\n }\n\n /**\n * Go to parent directory\n */\n async goUp(): Promise<void> {\n await callNative('fileBrowser.goUp', { id: this.id })\n }\n\n /**\n * Refresh content\n */\n async refresh(): Promise<void> {\n await callNative('fileBrowser.refresh', { id: this.id })\n }\n\n /**\n * Create new folder\n */\n async createFolder(name: string): Promise<string> {\n return callNative('fileBrowser.createFolder', { id: this.id, name })\n }\n\n /**\n * Delete selected files\n */\n async deleteSelection(moveToTrash?: boolean): Promise<void> {\n await callNative('fileBrowser.deleteSelection', { id: this.id, moveToTrash })\n }\n\n /**\n * Get current path\n */\n async getCurrentPath(): Promise<string> {\n return callNative('fileBrowser.getCurrentPath', { id: this.id })\n }\n}\n\n// ============================================================================\n// Outline View (Tree View)\n// ============================================================================\n\n/**\n * Outline item\n */\nexport interface OutlineItem {\n /** Item ID */\n id: string\n /** Display label */\n label: string\n /** Icon */\n icon?: string\n /** Children */\n children?: OutlineItem[]\n /** Expanded state */\n expanded?: boolean\n /** Selectable */\n selectable?: boolean\n /** Editable */\n editable?: boolean\n /** Draggable */\n draggable?: boolean\n /** Custom data */\n data?: Record<string, any>\n}\n\n/**\n * Outline view configuration\n */\nexport interface OutlineViewConfig extends ComponentProps {\n /** Items */\n items?: OutlineItem[]\n /** Allow multiple selection */\n multiSelect?: boolean\n /** Allow reordering */\n allowReorder?: boolean\n /** Show expand buttons */\n showExpandButtons?: boolean\n /** Row height */\n rowHeight?: number\n /** Indent per level */\n indentation?: number\n}\n\n/**\n * Create a native outline view (tree view)\n */\nexport async function createOutlineView(config: OutlineViewConfig = {}): Promise<OutlineViewInstance> {\n const id = config.id || nextComponentId('outlineview')\n await callNative('component.createOutlineView', { id, config })\n return new OutlineViewInstance(id, config)\n}\n\n/**\n * Outline view instance\n */\nexport class OutlineViewInstance implements ComponentInstance {\n id: string\n type = 'outlineView'\n private _config: OutlineViewConfig\n private _listeners: Map<string, Set<Function>> = new Map()\n\n constructor(id: string, config: OutlineViewConfig) {\n this.id = id\n this._config = config\n this._setupListeners()\n }\n\n private _setupListeners(): void {\n if (typeof window !== 'undefined') {\n const events = ['select', 'double-click', 'expand', 'collapse', 'reorder', 'edit']\n events.forEach(event => {\n window.addEventListener(`craft:outlineView:${this.id}:${event}` as any, (e: CustomEvent) => {\n this._emit(event, e.detail)\n })\n })\n }\n }\n\n private _emit(event: string, data?: any): void {\n this._listeners.get(event)?.forEach(fn => fn(data))\n }\n\n on(event: string, handler: Function): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n this._listeners.get(event)!.add(handler)\n return () => this._listeners.get(event)?.delete(handler)\n }\n\n async update(props: Partial<OutlineViewConfig>): Promise<void> {\n Object.assign(this._config, props)\n await callNative('component.update', { id: this.id, props })\n }\n\n async destroy(): Promise<void> {\n await callNative('component.destroy', { id: this.id })\n }\n\n async show(): Promise<void> {\n await callNative('component.show', { id: this.id })\n }\n\n async hide(): Promise<void> {\n await callNative('component.hide', { id: this.id })\n }\n\n async focus(): Promise<void> {\n await callNative('component.focus', { id: this.id })\n }\n\n /**\n * Set items\n */\n async setItems(items: OutlineItem[]): Promise<void> {\n this._config.items = items\n await callNative('outlineView.setItems', { id: this.id, items })\n }\n\n /**\n * Add item\n */\n async addItem(item: OutlineItem, parentId?: string, index?: number): Promise<void> {\n await callNative('outlineView.addItem', { id: this.id, item, parentId, index })\n }\n\n /**\n * Update item\n */\n async updateItem(itemId: string, updates: Partial<OutlineItem>): Promise<void> {\n await callNative('outlineView.updateItem', { id: this.id, itemId, updates })\n }\n\n /**\n * Remove item\n */\n async removeItem(itemId: string): Promise<void> {\n await callNative('outlineView.removeItem', { id: this.id, itemId })\n }\n\n /**\n * Expand item\n */\n async expandItem(itemId: string): Promise<void> {\n await callNative('outlineView.expandItem', { id: this.id, itemId })\n }\n\n /**\n * Collapse item\n */\n async collapseItem(itemId: string): Promise<void> {\n await callNative('outlineView.collapseItem', { id: this.id, itemId })\n }\n\n /**\n * Select item\n */\n async selectItem(itemId: string): Promise<void> {\n await callNative('outlineView.selectItem', { id: this.id, itemId })\n }\n\n /**\n * Get selection\n */\n async getSelection(): Promise<string[]> {\n return callNative('outlineView.getSelection', { id: this.id })\n }\n\n /**\n * Scroll to item\n */\n async scrollToItem(itemId: string): Promise<void> {\n await callNative('outlineView.scrollToItem', { id: this.id, itemId })\n }\n}\n\n// ============================================================================\n// Table View\n// ============================================================================\n\n/**\n * Table column configuration\n */\nexport interface TableColumn {\n /** Column ID */\n id: string\n /** Column header title */\n title: string\n /** Column width */\n width?: number\n /** Minimum width */\n minWidth?: number\n /** Maximum width */\n maxWidth?: number\n /** Resizable */\n resizable?: boolean\n /** Sortable */\n sortable?: boolean\n /** Sort direction */\n sortDirection?: 'ascending' | 'descending' | null\n /** Hidden */\n hidden?: boolean\n /** Alignment */\n alignment?: 'left' | 'center' | 'right'\n /** Editable */\n editable?: boolean\n}\n\n/**\n * Table row\n */\nexport interface TableRow {\n /** Row ID */\n id: string\n /** Column values (column ID -> value) */\n values: Record<string, any>\n /** Row selected */\n selected?: boolean\n /** Row disabled */\n disabled?: boolean\n /** Custom data */\n data?: Record<string, any>\n}\n\n/**\n * Table view configuration\n */\nexport interface TableViewConfig extends ComponentProps {\n /** Columns */\n columns?: TableColumn[]\n /** Rows */\n rows?: TableRow[]\n /** Allow column reordering */\n allowColumnReorder?: boolean\n /** Allow row selection */\n allowSelection?: boolean\n /** Allow multiple selection */\n multiSelect?: boolean\n /** Alternating row colors */\n alternatingRows?: boolean\n /** Show column headers */\n showHeaders?: boolean\n /** Row height */\n rowHeight?: number\n /** Grid lines */\n gridLines?: 'none' | 'horizontal' | 'vertical' | 'both'\n}\n\n/**\n * Create a native table view\n */\nexport async function createTableView(config: TableViewConfig = {}): Promise<TableViewInstance> {\n const id = config.id || nextComponentId('tableview')\n await callNative('component.createTableView', { id, config })\n return new TableViewInstance(id, config)\n}\n\n/**\n * Table view instance\n */\nexport class TableViewInstance implements ComponentInstance {\n id: string\n type = 'tableView'\n private _config: TableViewConfig\n private _listeners: Map<string, Set<Function>> = new Map()\n\n constructor(id: string, config: TableViewConfig) {\n this.id = id\n this._config = config\n this._setupListeners()\n }\n\n private _setupListeners(): void {\n if (typeof window !== 'undefined') {\n const events = ['select', 'double-click', 'sort', 'edit', 'column-resize', 'column-reorder']\n events.forEach(event => {\n window.addEventListener(`craft:tableView:${this.id}:${event}` as any, (e: CustomEvent) => {\n this._emit(event, e.detail)\n })\n })\n }\n }\n\n private _emit(event: string, data?: any): void {\n this._listeners.get(event)?.forEach(fn => fn(data))\n }\n\n on(event: string, handler: Function): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n this._listeners.get(event)!.add(handler)\n return () => this._listeners.get(event)?.delete(handler)\n }\n\n async update(props: Partial<TableViewConfig>): Promise<void> {\n Object.assign(this._config, props)\n await callNative('component.update', { id: this.id, props })\n }\n\n async destroy(): Promise<void> {\n await callNative('component.destroy', { id: this.id })\n }\n\n async show(): Promise<void> {\n await callNative('component.show', { id: this.id })\n }\n\n async hide(): Promise<void> {\n await callNative('component.hide', { id: this.id })\n }\n\n async focus(): Promise<void> {\n await callNative('component.focus', { id: this.id })\n }\n\n /**\n * Set columns\n */\n async setColumns(columns: TableColumn[]): Promise<void> {\n this._config.columns = columns\n await callNative('tableView.setColumns', { id: this.id, columns })\n }\n\n /**\n * Set rows\n */\n async setRows(rows: TableRow[]): Promise<void> {\n this._config.rows = rows\n await callNative('tableView.setRows', { id: this.id, rows })\n }\n\n /**\n * Add row\n */\n async addRow(row: TableRow, index?: number): Promise<void> {\n await callNative('tableView.addRow', { id: this.id, row, index })\n }\n\n /**\n * Update row\n */\n async updateRow(rowId: string, values: Record<string, any>): Promise<void> {\n await callNative('tableView.updateRow', { id: this.id, rowId, values })\n }\n\n /**\n * Remove row\n */\n async removeRow(rowId: string): Promise<void> {\n await callNative('tableView.removeRow', { id: this.id, rowId })\n }\n\n /**\n * Get selection\n */\n async getSelection(): Promise<string[]> {\n return callNative('tableView.getSelection', { id: this.id })\n }\n\n /**\n * Select rows\n */\n async selectRows(rowIds: string[]): Promise<void> {\n await callNative('tableView.selectRows', { id: this.id, rowIds })\n }\n\n /**\n * Sort by column\n */\n async sortBy(columnId: string, direction: 'ascending' | 'descending'): Promise<void> {\n await callNative('tableView.sortBy', { id: this.id, columnId, direction })\n }\n\n /**\n * Scroll to row\n */\n async scrollToRow(rowId: string): Promise<void> {\n await callNative('tableView.scrollToRow', { id: this.id, rowId })\n }\n}\n\n// ============================================================================\n// Quick Look Preview\n// ============================================================================\n\n/**\n * Quick Look configuration\n */\nexport interface QuickLookConfig {\n /** File path to preview */\n path: string\n /** Panel position */\n position?: { x: number; y: number }\n /** Panel size */\n size?: { width: number; height: number }\n}\n\n/**\n * Show Quick Look preview for a file\n */\nexport async function showQuickLook(config: QuickLookConfig): Promise<void> {\n await callNative('quickLook.show', config)\n}\n\n/**\n * Hide Quick Look preview\n */\nexport async function hideQuickLook(): Promise<void> {\n await callNative('quickLook.hide', {})\n}\n\n/**\n * Check if Quick Look is available for a file\n */\nexport async function canQuickLook(path: string): Promise<boolean> {\n return callNative('quickLook.canPreview', { path })\n}\n\n// ============================================================================\n// Color Picker\n// ============================================================================\n\n/**\n * Color picker configuration\n */\nexport interface ColorPickerConfig {\n /** Initial color (hex, rgb, or named) */\n color?: string\n /** Show alpha slider */\n showAlpha?: boolean\n /** Mode */\n mode?: 'wheel' | 'sliders' | 'palette' | 'list'\n /** Title */\n title?: string\n}\n\n/**\n * Show native color picker\n */\nexport async function showColorPicker(config: ColorPickerConfig = {}): Promise<string | null> {\n return callNative('colorPicker.show', config)\n}\n\n// ============================================================================\n// Font Picker\n// ============================================================================\n\n/**\n * Font picker configuration\n */\nexport interface FontPickerConfig {\n /** Initial font */\n font?: { family: string; size: number; weight?: string; style?: string }\n /** Title */\n title?: string\n /** Show size picker */\n showSize?: boolean\n /** Show weight picker */\n showWeight?: boolean\n /** Show style picker */\n showStyle?: boolean\n}\n\n/**\n * Font result\n */\nexport interface FontResult {\n family: string\n size: number\n weight?: string\n style?: string\n}\n\n/**\n * Show native font picker\n */\nexport async function showFontPicker(config: FontPickerConfig = {}): Promise<FontResult | null> {\n return callNative('fontPicker.show', config)\n}\n\n// ============================================================================\n// Date Picker\n// ============================================================================\n\n/**\n * Date picker configuration\n */\nexport interface DatePickerConfig {\n /** Initial date */\n date?: Date | string\n /** Minimum date */\n minDate?: Date | string\n /** Maximum date */\n maxDate?: Date | string\n /** Date format */\n format?: string\n /** Show time picker */\n showTime?: boolean\n /** Calendar style */\n style?: 'default' | 'graphical'\n}\n\n/**\n * Show native date picker\n */\nexport async function showDatePicker(config: DatePickerConfig = {}): Promise<Date | null> {\n const result = await callNative<string | null>('datePicker.show', config)\n return result ? new Date(result) : null\n}\n\n// ============================================================================\n// Progress Indicator\n// ============================================================================\n\n/**\n * Progress indicator configuration\n */\nexport interface ProgressConfig extends ComponentProps {\n /** Progress value (0-1 for determinate, undefined for indeterminate) */\n value?: number\n /** Minimum value */\n min?: number\n /** Maximum value */\n max?: number\n /** Show as percentage text */\n showText?: boolean\n /** Inline styles */\n style?: Record<string, any>\n /** Size */\n size?: 'small' | 'regular' | 'large'\n /** Progress style variant */\n progressStyle?: 'bar' | 'spinning' | 'circular'\n}\n\n/**\n * Create a progress indicator\n */\nexport async function createProgress(config: ProgressConfig = {}): Promise<ProgressInstance> {\n const id = config.id || nextComponentId('progress')\n await callNative('component.createProgress', { id, config })\n return new ProgressInstance(id, config)\n}\n\n/**\n * Progress instance\n */\nexport class ProgressInstance implements ComponentInstance {\n id: string\n type = 'progress'\n private _config: ProgressConfig\n private _listeners: Map<string, Set<Function>> = new Map()\n\n constructor(id: string, config: ProgressConfig) {\n this.id = id\n this._config = config\n }\n\n on(event: string, handler: Function): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n this._listeners.get(event)!.add(handler)\n return () => this._listeners.get(event)?.delete(handler)\n }\n\n async update(props: Partial<ProgressConfig>): Promise<void> {\n Object.assign(this._config, props)\n await callNative('component.update', { id: this.id, props })\n }\n\n async destroy(): Promise<void> {\n await callNative('component.destroy', { id: this.id })\n }\n\n async show(): Promise<void> {\n await callNative('component.show', { id: this.id })\n }\n\n async hide(): Promise<void> {\n await callNative('component.hide', { id: this.id })\n }\n\n async focus(): Promise<void> {\n await callNative('component.focus', { id: this.id })\n }\n\n /**\n * Set progress value\n */\n async setValue(value: number): Promise<void> {\n this._config.value = value\n await callNative('progress.setValue', { id: this.id, value })\n }\n\n /**\n * Start indeterminate animation\n */\n async startAnimation(): Promise<void> {\n await callNative('progress.startAnimation', { id: this.id })\n }\n\n /**\n * Stop animation\n */\n async stopAnimation(): Promise<void> {\n await callNative('progress.stopAnimation', { id: this.id })\n }\n}\n\n// ============================================================================\n// Toolbar\n// ============================================================================\n\n/**\n * Toolbar item\n */\nexport interface ToolbarItem {\n /** Item ID */\n id: string\n /** Item type */\n type?: 'button' | 'toggle' | 'segment' | 'search' | 'space' | 'flexibleSpace' | 'separator' | 'group'\n /** Label */\n label?: string\n /** Icon (SF Symbol or path) */\n icon?: string\n /** Tooltip */\n tooltip?: string\n /** Enabled */\n enabled?: boolean\n /** Selected (for toggle) */\n selected?: boolean\n /** Min width (for search) */\n minWidth?: number\n /** Max width (for search) */\n maxWidth?: number\n /** Segments (for segment control) */\n segments?: Array<{ id: string; label?: string; icon?: string }>\n /** Items (for group) */\n items?: ToolbarItem[]\n}\n\n/**\n * Toolbar configuration\n */\nexport interface ToolbarConfig {\n /** Toolbar items */\n items?: ToolbarItem[]\n /** Default item identifiers */\n defaultItems?: string[]\n /** Allow customization */\n allowsCustomization?: boolean\n /** Display mode */\n displayMode?: 'default' | 'iconOnly' | 'labelOnly' | 'iconAndLabel'\n /** Size mode */\n sizeMode?: 'default' | 'small' | 'regular'\n /** Show separator below toolbar */\n showBottomBorder?: boolean\n}\n\n/**\n * Set window toolbar\n */\nexport async function setToolbar(config: ToolbarConfig): Promise<void> {\n await callNative('toolbar.set', config)\n}\n\n/**\n * Update toolbar item\n */\nexport async function updateToolbarItem(itemId: string, updates: Partial<ToolbarItem>): Promise<void> {\n await callNative('toolbar.updateItem', { itemId, updates })\n}\n\n/**\n * Show/hide toolbar\n */\nexport async function setToolbarVisible(visible: boolean): Promise<void> {\n await callNative('toolbar.setVisible', { visible })\n}\n\n// ============================================================================\n// Touch Bar (macOS)\n// ============================================================================\n\n/**\n * Touch Bar item\n */\nexport interface TouchBarItem {\n /** Item ID */\n id: string\n /** Item type */\n type: 'button' | 'label' | 'slider' | 'colorPicker' | 'popover' | 'group' | 'segmentedControl' | 'scrubber' | 'spacer'\n /** Label text */\n label?: string\n /** Icon */\n icon?: string\n /** Background color */\n backgroundColor?: string\n /** Text color */\n textColor?: string\n /** Enabled */\n enabled?: boolean\n /** Width */\n width?: number\n /** Items (for group/popover) */\n items?: TouchBarItem[]\n /** Segments (for segmented control) */\n segments?: Array<{ id: string; label?: string; icon?: string }>\n /** Min value (for slider) */\n min?: number\n /** Max value (for slider) */\n max?: number\n /** Value (for slider) */\n value?: number\n /** Spacer size */\n size?: 'small' | 'large' | 'flexible'\n}\n\n/**\n * Touch Bar configuration\n */\nexport interface TouchBarConfig {\n /** Touch Bar items */\n items?: TouchBarItem[]\n /** Escape item */\n escapeItem?: TouchBarItem\n}\n\n/**\n * Set Touch Bar\n */\nexport async function setTouchBar(config: TouchBarConfig): Promise<void> {\n await callNative('touchBar.set', config)\n}\n\n/**\n * Update Touch Bar item\n */\nexport async function updateTouchBarItem(itemId: string, updates: Partial<TouchBarItem>): Promise<void> {\n await callNative('touchBar.updateItem', { itemId, updates })\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\nasync function callNative<T = void>(method: string, params: Record<string, any>): Promise<T> {\n if (typeof window !== 'undefined' && (window as any).webkit?.messageHandlers?.craft) {\n return new Promise((resolve, reject) => {\n try {\n (window as any).webkit.messageHandlers.craft.postMessage({\n type: 'native-ui',\n method,\n params\n })\n resolve(undefined as T)\n }\ncatch (error) {\n reject(error)\n }\n })\n }\n\n const bridge = getBridge()\n return bridge.request(method, params)\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nconst nativeComponents: {\n createSplitView: typeof createSplitView\n SplitViewInstance: typeof SplitViewInstance\n createFileBrowser: typeof createFileBrowser\n FileBrowserInstance: typeof FileBrowserInstance\n createOutlineView: typeof createOutlineView\n OutlineViewInstance: typeof OutlineViewInstance\n createTableView: typeof createTableView\n TableViewInstance: typeof TableViewInstance\n showQuickLook: typeof showQuickLook\n hideQuickLook: typeof hideQuickLook\n canQuickLook: typeof canQuickLook\n showColorPicker: typeof showColorPicker\n showFontPicker: typeof showFontPicker\n showDatePicker: typeof showDatePicker\n createProgress: typeof createProgress\n ProgressInstance: typeof ProgressInstance\n setToolbar: typeof setToolbar\n updateToolbarItem: typeof updateToolbarItem\n setToolbarVisible: typeof setToolbarVisible\n setTouchBar: typeof setTouchBar\n updateTouchBarItem: typeof updateTouchBarItem\n} = {\n createSplitView: createSplitView,\n SplitViewInstance: SplitViewInstance,\n createFileBrowser: createFileBrowser,\n FileBrowserInstance: FileBrowserInstance,\n createOutlineView: createOutlineView,\n OutlineViewInstance: OutlineViewInstance,\n createTableView: createTableView,\n TableViewInstance: TableViewInstance,\n showQuickLook: showQuickLook,\n hideQuickLook: hideQuickLook,\n canQuickLook: canQuickLook,\n showColorPicker: showColorPicker,\n showFontPicker: showFontPicker,\n showDatePicker: showDatePicker,\n createProgress: createProgress,\n ProgressInstance: ProgressInstance,\n setToolbar: setToolbar,\n updateToolbarItem: updateToolbarItem,\n setToolbarVisible: setToolbarVisible,\n setTouchBar: setTouchBar,\n updateTouchBarItem: updateTouchBarItem\n}\n\nexport default nativeComponents\n",
|
|
34
|
+
"/**\n * @fileoverview Craft Component Abstractions\n * @description React Native-style component primitives for cross-platform UI development.\n * These provide a consistent abstraction layer over native platform components.\n * @module @craft-native/components\n *\n * @example\n * ```tsx\n * import { View, Text, Image, ScrollView, Pressable } from '@craft-native/components'\n *\n * function MyComponent() {\n * return (\n * <View style={{ flex: 1, padding: 16 }}>\n * <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Hello World</Text>\n * <Image source={{ uri: 'https://example.com/image.png' }} style={{ width: 100, height: 100 }} />\n * </View>\n * )\n * }\n * ```\n */\n\n// ============================================================================\n// Native Sidebar Components\n// ============================================================================\n\nexport {\n Sidebar,\n createSidebar,\n createTahoeSidebar,\n createArcSidebar,\n createOrbStackSidebar,\n sidebarItem,\n sidebarSection,\n sidebarSeparator,\n tahoeStyle,\n arcStyle,\n orbstackStyle\n} from './sidebar'\nexport type {\n SidebarItem,\n SidebarSection,\n ContextMenuItem,\n SidebarStyle,\n SidebarPosition,\n SidebarConfig,\n SidebarHeaderConfig,\n SidebarFooterConfig,\n SidebarEventType,\n SidebarEventMap,\n SidebarEventHandler\n} from './sidebar'\n\n// ============================================================================\n// Native UI Components\n// ============================================================================\n\nexport {\n // Split View\n createSplitView,\n SplitViewInstance,\n\n // File Browser\n createFileBrowser,\n FileBrowserInstance,\n\n // Outline View (Tree)\n createOutlineView,\n OutlineViewInstance,\n\n // Table View\n createTableView,\n TableViewInstance,\n\n // Quick Look\n showQuickLook,\n hideQuickLook,\n canQuickLook,\n\n // Pickers\n showColorPicker,\n showFontPicker,\n showDatePicker,\n\n // Progress\n createProgress,\n ProgressInstance,\n\n // Toolbar\n setToolbar,\n updateToolbarItem,\n setToolbarVisible,\n\n // Touch Bar\n setTouchBar,\n updateTouchBarItem\n} from './native'\nexport type {\n ComponentProps,\n ComponentInstance,\n SplitViewOrientation,\n SplitViewDividerStyle,\n SplitViewConfig,\n FileBrowserConfig,\n FileBrowserSelection,\n OutlineItem,\n OutlineViewConfig,\n TableColumn,\n TableRow,\n TableViewConfig,\n QuickLookConfig,\n ColorPickerConfig,\n FontPickerConfig,\n FontResult,\n DatePickerConfig,\n ProgressConfig,\n ToolbarItem,\n ToolbarConfig,\n TouchBarItem,\n TouchBarConfig\n} from './native'\n\n// ============================================================================\n// Style Types\n// ============================================================================\n\n/**\n * Flexbox style properties.\n */\nexport interface FlexStyle {\n /** Flex grow factor */\n flex?: number\n /** Flex grow factor */\n flexGrow?: number\n /** Flex shrink factor */\n flexShrink?: number\n /** Flex basis */\n flexBasis?: number | string\n /** Flex direction */\n flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse'\n /** Flex wrap */\n flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse'\n /** Justify content (main axis) */\n justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'\n /** Align items (cross axis) */\n alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'\n /** Align self (override parent alignItems) */\n alignSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'\n /** Align content (multi-line) */\n alignContent?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'space-between' | 'space-around'\n /** Gap between items */\n gap?: number\n /** Row gap */\n rowGap?: number\n /** Column gap */\n columnGap?: number\n}\n\n/**\n * Layout style properties.\n */\nexport interface LayoutStyle {\n /** Width */\n width?: number | string\n /** Height */\n height?: number | string\n /** Min width */\n minWidth?: number | string\n /** Max width */\n maxWidth?: number | string\n /** Min height */\n minHeight?: number | string\n /** Max height */\n maxHeight?: number | string\n /** Aspect ratio */\n aspectRatio?: number\n /** Position type */\n position?: 'relative' | 'absolute'\n /** Top position */\n top?: number | string\n /** Right position */\n right?: number | string\n /** Bottom position */\n bottom?: number | string\n /** Left position */\n left?: number | string\n /** Z-index */\n zIndex?: number\n /** Overflow */\n overflow?: 'visible' | 'hidden' | 'scroll'\n /** Display */\n display?: 'flex' | 'none'\n}\n\n/**\n * Spacing style properties.\n */\nexport interface SpacingStyle {\n /** Margin all sides */\n margin?: number | string\n /** Margin top */\n marginTop?: number | string\n /** Margin right */\n marginRight?: number | string\n /** Margin bottom */\n marginBottom?: number | string\n /** Margin left */\n marginLeft?: number | string\n /** Margin horizontal */\n marginHorizontal?: number | string\n /** Margin vertical */\n marginVertical?: number | string\n /** Padding all sides */\n padding?: number | string\n /** Padding top */\n paddingTop?: number | string\n /** Padding right */\n paddingRight?: number | string\n /** Padding bottom */\n paddingBottom?: number | string\n /** Padding left */\n paddingLeft?: number | string\n /** Padding horizontal */\n paddingHorizontal?: number | string\n /** Padding vertical */\n paddingVertical?: number | string\n}\n\n/**\n * Border style properties.\n */\nexport interface BorderStyle {\n /** Border width all sides */\n borderWidth?: number\n /** Border top width */\n borderTopWidth?: number\n /** Border right width */\n borderRightWidth?: number\n /** Border bottom width */\n borderBottomWidth?: number\n /** Border left width */\n borderLeftWidth?: number\n /** Border color */\n borderColor?: string\n /** Border top color */\n borderTopColor?: string\n /** Border right color */\n borderRightColor?: string\n /** Border bottom color */\n borderBottomColor?: string\n /** Border left color */\n borderLeftColor?: string\n /** Border radius all corners */\n borderRadius?: number\n /** Border top left radius */\n borderTopLeftRadius?: number\n /** Border top right radius */\n borderTopRightRadius?: number\n /** Border bottom left radius */\n borderBottomLeftRadius?: number\n /** Border bottom right radius */\n borderBottomRightRadius?: number\n /** Border style */\n borderStyle?: 'solid' | 'dotted' | 'dashed'\n}\n\n/**\n * Background and color style properties.\n */\nexport interface ColorStyle {\n /** Background color */\n backgroundColor?: string\n /** Opacity */\n opacity?: number\n}\n\n/**\n * Shadow style properties.\n */\nexport interface ShadowStyle {\n /** Shadow color */\n shadowColor?: string\n /** Shadow offset */\n shadowOffset?: { width: number; height: number }\n /** Shadow opacity */\n shadowOpacity?: number\n /** Shadow radius */\n shadowRadius?: number\n /** Elevation (Android) */\n elevation?: number\n}\n\n/**\n * Transform style properties.\n */\nexport interface TransformStyle {\n /** Array of transforms */\n transform?: Array<\n | { translateX: number }\n | { translateY: number }\n | { scale: number }\n | { scaleX: number }\n | { scaleY: number }\n | { rotate: string }\n | { rotateX: string }\n | { rotateY: string }\n | { rotateZ: string }\n | { skewX: string }\n | { skewY: string }\n >\n}\n\n/**\n * Combined View style type.\n */\nexport type ViewStyle = FlexStyle & LayoutStyle & SpacingStyle & BorderStyle & ColorStyle & ShadowStyle & TransformStyle\n\n/**\n * Text-specific style properties.\n */\nexport interface TextStyleProps {\n /** Text color */\n color?: string\n /** Font family */\n fontFamily?: string\n /** Font size */\n fontSize?: number\n /** Font style */\n fontStyle?: 'normal' | 'italic'\n /** Font weight */\n fontWeight?: 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'\n /** Letter spacing */\n letterSpacing?: number\n /** Line height */\n lineHeight?: number\n /** Text alignment */\n textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify'\n /** Text decoration line */\n textDecorationLine?: 'none' | 'underline' | 'line-through' | 'underline line-through'\n /** Text decoration style */\n textDecorationStyle?: 'solid' | 'double' | 'dotted' | 'dashed'\n /** Text decoration color */\n textDecorationColor?: string\n /** Text shadow color */\n textShadowColor?: string\n /** Text shadow offset */\n textShadowOffset?: { width: number; height: number }\n /** Text shadow radius */\n textShadowRadius?: number\n /** Text transform */\n textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase'\n}\n\n/**\n * Combined Text style type.\n */\nexport type TextStyle = ViewStyle & TextStyleProps\n\n/**\n * Image-specific style properties.\n */\nexport interface ImageStyleProps {\n /** Resize mode */\n resizeMode?: 'cover' | 'contain' | 'stretch' | 'repeat' | 'center'\n /** Tint color */\n tintColor?: string\n}\n\n/**\n * Combined Image style type.\n */\nexport type ImageStyle = ViewStyle & ImageStyleProps\n\n// ============================================================================\n// Component Props Types\n// ============================================================================\n\n/**\n * Base props for all components.\n */\nexport interface BaseProps {\n /** Unique identifier */\n id?: string\n /** Test ID for testing */\n testID?: string\n /** Accessibility label */\n accessibilityLabel?: string\n /** Accessibility hint */\n accessibilityHint?: string\n /** Accessibility role */\n accessibilityRole?: 'none' | 'button' | 'link' | 'image' | 'text' | 'header' | 'search' | 'menu'\n /** Children elements */\n children?: any\n}\n\n/**\n * View component props.\n */\nexport interface ViewProps extends BaseProps {\n /** Style object or array */\n style?: ViewStyle | ViewStyle[]\n /** Press handler */\n onPress?: () => void\n /** Long press handler */\n onLongPress?: () => void\n /** Layout change handler */\n onLayout?: (event: LayoutEvent) => void\n /** Pointer events behavior */\n pointerEvents?: 'auto' | 'none' | 'box-none' | 'box-only'\n}\n\n/**\n * Text component props.\n */\nexport interface TextProps extends BaseProps {\n /** Style object or array */\n style?: TextStyle | TextStyle[]\n /** Number of lines before truncation */\n numberOfLines?: number\n /** Ellipsize mode */\n ellipsizeMode?: 'head' | 'middle' | 'tail' | 'clip'\n /** Selectable text */\n selectable?: boolean\n /** Press handler */\n onPress?: () => void\n /** Long press handler */\n onLongPress?: () => void\n}\n\n/**\n * Image source type.\n */\nexport type ImageSource =\n | { uri: string; width?: number; height?: number; headers?: Record<string, string> }\n | number // For bundled images\n\n/**\n * Image component props.\n */\nexport interface ImageProps extends BaseProps {\n /** Image source */\n source: ImageSource\n /** Style object or array */\n style?: ImageStyle | ImageStyle[]\n /** Resize mode */\n resizeMode?: 'cover' | 'contain' | 'stretch' | 'repeat' | 'center'\n /** Load start handler */\n onLoadStart?: () => void\n /** Load handler */\n onLoad?: () => void\n /** Load end handler */\n onLoadEnd?: () => void\n /** Error handler */\n onError?: (error: Error) => void\n /** Default source while loading */\n defaultSource?: ImageSource\n /** Blur radius */\n blurRadius?: number\n /** Fade duration (ms) */\n fadeDuration?: number\n /** Alt text for accessibility */\n alt?: string\n}\n\n/**\n * ScrollView component props.\n */\nexport interface ScrollViewProps extends ViewProps {\n /** Horizontal scrolling */\n horizontal?: boolean\n /** Show horizontal scroll indicator */\n showsHorizontalScrollIndicator?: boolean\n /** Show vertical scroll indicator */\n showsVerticalScrollIndicator?: boolean\n /** Paging enabled */\n pagingEnabled?: boolean\n /** Bounce enabled */\n bounces?: boolean\n /** Always bounce vertical */\n alwaysBounceVertical?: boolean\n /** Always bounce horizontal */\n alwaysBounceHorizontal?: boolean\n /** Scroll enabled */\n scrollEnabled?: boolean\n /** Scroll handler */\n onScroll?: (event: ScrollEvent) => void\n /** Scroll begin drag handler */\n onScrollBeginDrag?: () => void\n /** Scroll end drag handler */\n onScrollEndDrag?: () => void\n /** Momentum scroll begin handler */\n onMomentumScrollBegin?: () => void\n /** Momentum scroll end handler */\n onMomentumScrollEnd?: () => void\n /** Content container style */\n contentContainerStyle?: ViewStyle\n /** Keyboard dismiss mode */\n keyboardDismissMode?: 'none' | 'on-drag' | 'interactive'\n /** Keyboard should persist taps */\n keyboardShouldPersistTaps?: 'always' | 'never' | 'handled'\n /** Refresh control component */\n refreshControl?: any\n}\n\n/**\n * Pressable component props.\n */\nexport interface PressableProps extends ViewProps {\n /** Disabled state */\n disabled?: boolean\n /** Press in handler */\n onPressIn?: () => void\n /** Press out handler */\n onPressOut?: () => void\n /** Hit slop for touch area */\n hitSlop?: number | { top?: number; right?: number; bottom?: number; left?: number }\n /** Press retention offset */\n pressRetentionOffset?: number | { top?: number; right?: number; bottom?: number; left?: number }\n /** Android ripple effect */\n android_ripple?: { color?: string; borderless?: boolean; radius?: number }\n /** Delay for long press */\n delayLongPress?: number\n}\n\n/**\n * TextInput component props.\n */\nexport interface TextInputProps extends BaseProps {\n /** Style object or array */\n style?: TextStyle | TextStyle[]\n /** Current value */\n value?: string\n /** Default value */\n defaultValue?: string\n /** Placeholder text */\n placeholder?: string\n /** Placeholder text color */\n placeholderTextColor?: string\n /** Keyboard type */\n keyboardType?: 'default' | 'email-address' | 'numeric' | 'phone-pad' | 'decimal-pad' | 'url'\n /** Return key type */\n returnKeyType?: 'done' | 'go' | 'next' | 'search' | 'send'\n /** Auto capitalize */\n autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters'\n /** Auto correct */\n autoCorrect?: boolean\n /** Auto focus */\n autoFocus?: boolean\n /** Secure text entry (password) */\n secureTextEntry?: boolean\n /** Multi-line input */\n multiline?: boolean\n /** Number of lines for multiline */\n numberOfLines?: number\n /** Max length */\n maxLength?: number\n /** Editable state */\n editable?: boolean\n /** Selection color */\n selectionColor?: string\n /** Change text handler */\n onChangeText?: (text: string) => void\n /** Focus handler */\n onFocus?: () => void\n /** Blur handler */\n onBlur?: () => void\n /** Submit editing handler */\n onSubmitEditing?: () => void\n /** End editing handler */\n onEndEditing?: () => void\n}\n\n/**\n * FlatList component props.\n */\nexport interface FlatListProps<T> extends ScrollViewProps {\n /** Data array */\n data: T[]\n /** Render item function */\n renderItem: (info: { item: T; index: number }) => any\n /** Key extractor function */\n keyExtractor?: (item: T, index: number) => string\n /** Item separator component */\n ItemSeparatorComponent?: any\n /** List header component */\n ListHeaderComponent?: any\n /** List footer component */\n ListFooterComponent?: any\n /** Empty list component */\n ListEmptyComponent?: any\n /** Number of columns */\n numColumns?: number\n /** Initial number to render */\n initialNumToRender?: number\n /** Max to render per batch */\n maxToRenderPerBatch?: number\n /** Window size */\n windowSize?: number\n /** Get item layout for optimization */\n getItemLayout?: (data: T[] | null, index: number) => { length: number; offset: number; index: number }\n /** End reached handler */\n onEndReached?: () => void\n /** End reached threshold */\n onEndReachedThreshold?: number\n /** Refresh handler */\n onRefresh?: () => void\n /** Refreshing state */\n refreshing?: boolean\n}\n\n// ============================================================================\n// Event Types\n// ============================================================================\n\n/**\n * Layout event.\n */\nexport interface LayoutEvent {\n nativeEvent: {\n layout: {\n x: number\n y: number\n width: number\n height: number\n }\n }\n}\n\n/**\n * Scroll event.\n */\nexport interface ScrollEvent {\n nativeEvent: {\n contentOffset: { x: number; y: number }\n contentSize: { width: number; height: number }\n layoutMeasurement: { width: number; height: number }\n }\n}\n\n// ============================================================================\n// Platform Utilities\n// ============================================================================\n\n/**\n * Platform-specific value selection.\n *\n * @example\n * ```typescript\n * const fontSize = Platform.select({\n * ios: 17,\n * android: 16,\n * default: 16\n * })\n *\n * const Component = Platform.select({\n * ios: IOSComponent,\n * android: AndroidComponent,\n * default: WebComponent\n * })\n * ```\n */\nexport const Platform = {\n /** Current platform */\n OS: detectOS() as 'ios' | 'android' | 'web',\n\n /** Platform version */\n Version: getOSVersion() as string,\n\n /**\n * Check if running on iOS.\n */\n isIOS(): boolean {\n return this.OS === 'ios'\n },\n\n /**\n * Check if running on Android.\n */\n isAndroid(): boolean {\n return this.OS === 'android'\n },\n\n /**\n * Check if running on web.\n */\n isWeb(): boolean {\n return this.OS === 'web'\n },\n\n /**\n * Select platform-specific value.\n *\n * @param specifics - Object with platform-specific values\n * @returns Value for current platform\n */\n select<T>(specifics: { ios?: T; android?: T; web?: T; default?: T }): T | undefined {\n if (this.OS === 'ios' && specifics.ios !== undefined) return specifics.ios\n if (this.OS === 'android' && specifics.android !== undefined) return specifics.android\n if (this.OS === 'web' && specifics.web !== undefined) return specifics.web\n return specifics.default\n }\n}\n\n/**\n * Create platform-specific stylesheet.\n *\n * @example\n * ```typescript\n * const styles = StyleSheet.create({\n * container: {\n * flex: 1,\n * backgroundColor: '#fff',\n * padding: 16\n * },\n * title: {\n * fontSize: 24,\n * fontWeight: 'bold'\n * }\n * })\n * ```\n */\nexport const StyleSheet = {\n /**\n * Create a stylesheet from style definitions.\n */\n create<T extends Record<string, ViewStyle | TextStyle | ImageStyle>>(styles: T): T {\n return styles\n },\n\n /**\n * Flatten an array of styles into a single object.\n */\n flatten<T>(style: T | T[] | undefined): T | undefined {\n if (!style) return undefined\n if (Array.isArray(style)) {\n return Object.assign({}, ...style)\n }\n return style\n },\n\n /**\n * Get the absolute fill style (full parent).\n */\n absoluteFill: {\n position: 'absolute' as const,\n top: 0,\n left: 0,\n right: 0,\n bottom: 0\n },\n\n /**\n * Get hairline width (1px on device).\n */\n hairlineWidth: (typeof window !== 'undefined' ? 1 / (window.devicePixelRatio || 1) : 1) as number\n}\n\n/**\n * Animated API for animations.\n * Simplified version for common animations.\n *\n * @example\n * ```typescript\n * const opacity = new Animated.Value(0)\n *\n * // Fade in\n * Animated.timing(opacity, {\n * toValue: 1,\n * duration: 300,\n * useNativeDriver: true\n * }).start()\n *\n * // Spring animation\n * Animated.spring(scale, {\n * toValue: 1.2,\n * friction: 3,\n * useNativeDriver: true\n * }).start()\n * ```\n */\nclass AnimatedValue {\n private _value: number\n private _listeners: Array<(value: number) => void> = []\n\n constructor(value: number) {\n this._value = value\n }\n\n setValue(value: number): void {\n this._value = value\n this._listeners.forEach(listener => listener(value))\n }\n\n getValue(): number {\n return this._value\n }\n\n addListener(callback: (value: number) => void): string {\n this._listeners.push(callback)\n return String(this._listeners.length - 1)\n }\n\n removeListener(id: string): void {\n const index = parseInt(id, 10)\n if (index >= 0 && index < this._listeners.length) {\n this._listeners.splice(index, 1)\n }\n }\n\n removeAllListeners(): void {\n this._listeners = []\n }\n}\n\ntype AnimationResult = { start(callback?: (result: { finished: boolean }) => void): void; stop(): void }\ntype TimingConfig = { toValue: number; duration?: number; delay?: number; easing?: (t: number) => number; useNativeDriver?: boolean }\ntype SpringConfig = { toValue: number; friction?: number; tension?: number; useNativeDriver?: boolean }\n\nfunction animatedTiming(value: AnimatedValue, config: TimingConfig): AnimationResult {\n return {\n start(callback?: (result: { finished: boolean }) => void) {\n const startValue = value.getValue()\n const startTime = Date.now()\n const duration = config.duration || 300\n\n const animate = () => {\n const elapsed = Date.now() - startTime - (config.delay || 0)\n if (elapsed < 0) {\n requestAnimationFrame(animate)\n return\n }\n\n const progress = Math.min(elapsed / duration, 1)\n const easedProgress = config.easing ? config.easing(progress) : progress\n const currentValue = startValue + (config.toValue - startValue) * easedProgress\n\n value.setValue(currentValue)\n\n if (progress < 1) {\n requestAnimationFrame(animate)\n }\nelse {\n callback?.({ finished: true })\n }\n }\n\n requestAnimationFrame(animate)\n },\n stop() {\n // Stop animation\n },\n }\n}\n\nexport const Animated: {\n Value: typeof AnimatedValue\n timing(value: AnimatedValue, config: TimingConfig): AnimationResult\n spring(value: AnimatedValue, config: SpringConfig): AnimationResult\n parallel(animations: Array<{ start: (callback?: (result: { finished: boolean }) => void) => void }>): AnimationResult\n sequence(animations: Array<{ start: (callback?: (result: { finished: boolean }) => void) => void }>): AnimationResult\n} = {\n /**\n * Animated value class.\n */\n Value: AnimatedValue,\n\n /**\n * Create a timing animation.\n */\n timing: animatedTiming,\n\n /**\n * Create a spring animation.\n */\n spring(\n value: AnimatedValue,\n config: SpringConfig,\n ) {\n return {\n start(callback?: (result: { finished: boolean }) => void) {\n // Simplified spring using timing with ease-out\n const duration = 300 * (config.friction || 7) / 7\n animatedTiming(value, {\n toValue: config.toValue,\n duration,\n easing: (t: number) => 1 - (1 - t) ** 3,\n useNativeDriver: config.useNativeDriver,\n }).start(callback)\n },\n stop() {\n // Stop animation\n },\n }\n },\n\n /**\n * Run animations in parallel.\n */\n parallel(\n animations: Array<{ start: (callback?: (result: { finished: boolean }) => void) => void }>\n ) {\n return {\n start(callback?: (result: { finished: boolean }) => void) {\n let completed = 0\n const total = animations.length\n\n if (total === 0) {\n callback?.({ finished: true })\n return\n }\n\n animations.forEach(anim => {\n anim.start(() => {\n completed++\n if (completed === total) {\n callback?.({ finished: true })\n }\n })\n })\n },\n stop() {\n // Stop all animations\n }\n }\n },\n\n /**\n * Run animations in sequence.\n */\n sequence(\n animations: Array<{ start: (callback?: (result: { finished: boolean }) => void) => void }>\n ) {\n return {\n start(callback?: (result: { finished: boolean }) => void) {\n const runNext = (index: number) => {\n if (index >= animations.length) {\n callback?.({ finished: true })\n return\n }\n animations[index].start(() => runNext(index + 1))\n }\n runNext(0)\n },\n stop() {\n // Stop animations\n }\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\nfunction detectOS(): 'ios' | 'android' | 'web' {\n if (typeof window === 'undefined') return 'web'\n const ua = navigator.userAgent.toLowerCase()\n if (/iphone|ipad|ipod/.test(ua)) return 'ios'\n if (/android/.test(ua)) return 'android'\n return 'web'\n}\n\nfunction getOSVersion(): string {\n if (typeof window === 'undefined') return 'unknown'\n const ua = navigator.userAgent\n const match = ua.match(/(?:iPhone|iPad|iPod).*?OS (\\d+)/) ||\n ua.match(/Android (\\d+)/)\n return match ? match[1] : 'unknown'\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nconst components: {\n Platform: typeof Platform\n StyleSheet: typeof StyleSheet\n Animated: typeof Animated\n} = {\n Platform: Platform,\n StyleSheet: StyleSheet,\n Animated: Animated\n}\n\nexport default components\n",
|
|
35
|
+
"/**\n * @fileoverview Headwind CSS Integration\n * @description Integration with zig-headwind, a blazing-fast Tailwind CSS alternative built in Zig.\n * Provides utility-first CSS styling with Tailwind-compatible class names.\n * @module @craft-native/styles/headwind\n *\n * @example\n * ```typescript\n * import { tw, cx, variants, style } from '@craft-native/styles/headwind'\n *\n * // Use Tailwind-compatible classes\n * const buttonClass = tw`px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600`\n *\n * // Conditional classes\n * const className = cx(\n * 'base-class',\n * isActive && 'active',\n * { 'disabled': isDisabled }\n * )\n *\n * // Create variant-based styles\n * const button = variants({\n * base: 'px-4 py-2 rounded font-medium transition-colors',\n * variants: {\n * intent: {\n * primary: 'bg-blue-500 text-white hover:bg-blue-600',\n * secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',\n * danger: 'bg-red-500 text-white hover:bg-red-600'\n * },\n * size: {\n * sm: 'text-sm px-3 py-1.5',\n * md: 'text-base px-4 py-2',\n * lg: 'text-lg px-6 py-3'\n * }\n * },\n * defaultVariants: {\n * intent: 'primary',\n * size: 'md'\n * }\n * })\n *\n * // Use the variant\n * const className = button({ intent: 'danger', size: 'lg' })\n * ```\n */\n\n// ============================================================================\n// Core Utilities\n// ============================================================================\n\n/**\n * Tagged template literal for Tailwind/Headwind classes.\n * Provides syntax highlighting and potential compile-time validation.\n *\n * @example\n * ```typescript\n * const className = tw`flex items-center justify-center p-4 bg-blue-500`\n * ```\n */\nexport function tw(strings: TemplateStringsArray, ...values: unknown[]): string {\n let result = ''\n for (let i = 0; i < strings.length; i++) {\n result += strings[i]\n if (i < values.length) {\n result += String(values[i])\n }\n }\n // Normalize whitespace\n return result.replace(/\\s+/g, ' ').trim()\n}\n\n/**\n * Type for class value inputs.\n */\nexport type ClassValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | ClassValue[]\n | Record<string, boolean | null | undefined>\n\n/**\n * Merge class names conditionally.\n * Supports strings, arrays, objects, and falsy values.\n *\n * @example\n * ```typescript\n * // String classes\n * cx('foo', 'bar') // 'foo bar'\n *\n * // Conditional classes\n * cx('base', isActive && 'active', isDisabled && 'disabled')\n *\n * // Object syntax\n * cx('base', { active: isActive, disabled: isDisabled })\n *\n * // Mixed\n * cx('base', ['array', 'of', 'classes'], { conditional: true })\n * ```\n */\nexport function cx(...inputs: ClassValue[]): string {\n const classes: string[] = []\n\n for (const input of inputs) {\n if (!input) continue\n\n if (typeof input === 'string' || typeof input === 'number') {\n classes.push(String(input))\n }\nelse if (Array.isArray(input)) {\n const nested = cx(...input)\n if (nested) classes.push(nested)\n }\nelse if (typeof input === 'object') {\n for (const [key, value] of Object.entries(input)) {\n if (value) classes.push(key)\n }\n }\n }\n\n return classes.join(' ')\n}\n\n// ============================================================================\n// Variants System\n// ============================================================================\n\n/**\n * Variant configuration type.\n */\nexport interface VariantConfig<V extends Record<string, Record<string, string>>> {\n /** Base classes always applied */\n base?: string\n /** Variant definitions */\n variants: V\n /** Default variant values */\n defaultVariants?: { [K in keyof V]?: keyof V[K] }\n /** Compound variants for specific combinations */\n compoundVariants?: Array<{\n [K in keyof V]?: keyof V[K]\n } & { className: string }>\n}\n\n/**\n * Create a variant-based style function.\n * Similar to CVA (class-variance-authority) or Stitches variants.\n *\n * @example\n * ```typescript\n * const button = variants({\n * base: 'inline-flex items-center justify-center rounded-md font-medium',\n * variants: {\n * intent: {\n * primary: 'bg-blue-500 text-white hover:bg-blue-600',\n * secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',\n * ghost: 'hover:bg-gray-100'\n * },\n * size: {\n * sm: 'h-8 px-3 text-sm',\n * md: 'h-10 px-4 text-sm',\n * lg: 'h-12 px-6 text-base'\n * },\n * disabled: {\n * true: 'opacity-50 cursor-not-allowed'\n * }\n * },\n * defaultVariants: {\n * intent: 'primary',\n * size: 'md'\n * },\n * compoundVariants: [\n * {\n * intent: 'primary',\n * disabled: true,\n * className: 'bg-blue-300'\n * }\n * ]\n * })\n *\n * // Usage\n * button() // Uses defaults\n * button({ intent: 'secondary' })\n * button({ intent: 'primary', size: 'lg', disabled: true })\n * ```\n */\nexport function variants<V extends Record<string, Record<string, string>>>(\n _config: VariantConfig<V>\n): (props?: { [K in keyof V]?: keyof V[K] } & { className?: string }) => string {\n return (props = {}) => {\n const classes: string[] = []\n\n // Add base classes\n if (_config.base) {\n classes.push(_config.base)\n }\n\n // Apply variants\n for (const [variantKey, variantOptions] of Object.entries(_config.variants)) {\n const value = props[variantKey as keyof V]\n ?? _config.defaultVariants?.[variantKey as keyof V]\n\n if (value !== undefined && variantOptions[value as string]) {\n classes.push(variantOptions[value as string])\n }\n }\n\n // Apply compound variants\n if (_config.compoundVariants) {\n for (const compound of _config.compoundVariants) {\n const { className, ...conditions } = compound\n let matches = true\n\n for (const [key, value] of Object.entries(conditions)) {\n const propValue = props[key as keyof V]\n ?? _config.defaultVariants?.[key as keyof V]\n if (propValue !== value) {\n matches = false\n break\n }\n }\n\n if (matches && className) {\n classes.push(className)\n }\n }\n }\n\n // Add custom className\n if (props.className) {\n classes.push(props.className)\n }\n\n return classes.join(' ')\n }\n}\n\n// ============================================================================\n// Style Objects\n// ============================================================================\n\n/**\n * Convert Tailwind classes to inline style object.\n * Useful for React Native or platforms that don't support CSS classes.\n *\n * @example\n * ```typescript\n * const styles = style('p-4 bg-blue-500 text-white rounded-lg')\n * // { padding: 16, backgroundColor: '#3b82f6', color: '#ffffff', borderRadius: 8 }\n * ```\n */\nexport function style(classes: string): Record<string, string | number> {\n const result: Record<string, string | number> = {}\n const classList = classes.split(/\\s+/).filter(Boolean)\n\n for (const cls of classList) {\n const parsed = parseClass(cls)\n if (parsed) {\n Object.assign(result, parsed)\n }\n }\n\n return result\n}\n\n// ============================================================================\n// Class Parsing\n// ============================================================================\n\n/**\n * Parse a single Tailwind class to style object.\n */\nfunction parseClass(cls: string): Record<string, string | number> | null {\n // Spacing\n const spacingMatch = cls.match(/^([pm])([trblxy])?-(\\d+(?:\\.\\d+)?|px)$/)\n if (spacingMatch) {\n const [, type, side, value] = spacingMatch\n const numValue = value === 'px' ? 1 : parseFloat(value) * 4\n const property = type === 'p' ? 'padding' : 'margin'\n\n if (!side) return { [property]: numValue }\n if (side === 'x') return { [`${property}Left`]: numValue, [`${property}Right`]: numValue }\n if (side === 'y') return { [`${property}Top`]: numValue, [`${property}Bottom`]: numValue }\n\n const sideMap: Record<string, string> = { t: 'Top', r: 'Right', b: 'Bottom', l: 'Left' }\n return { [`${property}${sideMap[side]}`]: numValue }\n }\n\n // Width/Height\n const sizeMatch = cls.match(/^(w|h|min-w|max-w|min-h|max-h)-(\\d+|full|screen|auto)$/)\n if (sizeMatch) {\n const [, prop, value] = sizeMatch\n const propMap: Record<string, string> = {\n w: 'width', h: 'height',\n 'min-w': 'minWidth', 'max-w': 'maxWidth',\n 'min-h': 'minHeight', 'max-h': 'maxHeight'\n }\n const valMap: Record<string, string | number> = {\n full: '100%', screen: '100vh', auto: 'auto'\n }\n const numValue = valMap[value] ?? parseFloat(value) * 4\n return { [propMap[prop]]: numValue }\n }\n\n // Flex\n if (cls === 'flex') return { display: 'flex' }\n if (cls === 'flex-1') return { flex: 1 }\n if (cls === 'flex-row') return { flexDirection: 'row' }\n if (cls === 'flex-col') return { flexDirection: 'column' }\n if (cls === 'flex-wrap') return { flexWrap: 'wrap' }\n if (cls === 'items-center') return { alignItems: 'center' }\n if (cls === 'items-start') return { alignItems: 'flex-start' }\n if (cls === 'items-end') return { alignItems: 'flex-end' }\n if (cls === 'justify-center') return { justifyContent: 'center' }\n if (cls === 'justify-start') return { justifyContent: 'flex-start' }\n if (cls === 'justify-end') return { justifyContent: 'flex-end' }\n if (cls === 'justify-between') return { justifyContent: 'space-between' }\n if (cls === 'justify-around') return { justifyContent: 'space-around' }\n\n // Gap\n const gapMatch = cls.match(/^gap-(\\d+(?:\\.\\d+)?)$/)\n if (gapMatch) return { gap: parseFloat(gapMatch[1]) * 4 }\n\n // Border radius\n const roundedMap: Record<string, number | string> = {\n 'rounded-none': 0,\n 'rounded-sm': 2,\n 'rounded': 4,\n 'rounded-md': 6,\n 'rounded-lg': 8,\n 'rounded-xl': 12,\n 'rounded-2xl': 16,\n 'rounded-3xl': 24,\n 'rounded-full': 9999\n }\n if (roundedMap[cls] !== undefined) return { borderRadius: roundedMap[cls] }\n\n // Font size\n const fontSizeMap: Record<string, number> = {\n 'text-xs': 12, 'text-sm': 14, 'text-base': 16, 'text-lg': 18,\n 'text-xl': 20, 'text-2xl': 24, 'text-3xl': 30, 'text-4xl': 36\n }\n if (fontSizeMap[cls]) return { fontSize: fontSizeMap[cls] }\n\n // Font weight\n const fontWeightMap: Record<string, string | number> = {\n 'font-thin': '100', 'font-extralight': '200', 'font-light': '300',\n 'font-normal': '400', 'font-medium': '500', 'font-semibold': '600',\n 'font-bold': '700', 'font-extrabold': '800', 'font-black': '900'\n }\n if (fontWeightMap[cls]) return { fontWeight: fontWeightMap[cls] }\n\n // Text align\n if (cls === 'text-left') return { textAlign: 'left' }\n if (cls === 'text-center') return { textAlign: 'center' }\n if (cls === 'text-right') return { textAlign: 'right' }\n\n // Colors (simplified - full implementation would have all Tailwind colors)\n const colorMatch = cls.match(/^(bg|text|border)-(\\w+)-(\\d{2,3})$/)\n if (colorMatch) {\n const [, property, color, shade] = colorMatch\n const colorValue = getColor(color, parseInt(shade, 10))\n if (colorValue) {\n const propMap: Record<string, string> = {\n bg: 'backgroundColor',\n text: 'color',\n border: 'borderColor'\n }\n return { [propMap[property]]: colorValue }\n }\n }\n\n // Simple colors\n if (cls === 'bg-white') return { backgroundColor: '#ffffff' }\n if (cls === 'bg-black') return { backgroundColor: '#000000' }\n if (cls === 'bg-transparent') return { backgroundColor: 'transparent' }\n if (cls === 'text-white') return { color: '#ffffff' }\n if (cls === 'text-black') return { color: '#000000' }\n\n // Opacity\n const opacityMatch = cls.match(/^opacity-(\\d+)$/)\n if (opacityMatch) return { opacity: parseInt(opacityMatch[1], 10) / 100 }\n\n // Position\n if (cls === 'relative') return { position: 'relative' }\n if (cls === 'absolute') return { position: 'absolute' }\n\n // Display\n if (cls === 'hidden') return { display: 'none' }\n if (cls === 'block') return { display: 'block' }\n if (cls === 'inline') return { display: 'inline' }\n\n // Overflow\n if (cls === 'overflow-hidden') return { overflow: 'hidden' }\n if (cls === 'overflow-scroll') return { overflow: 'scroll' }\n if (cls === 'overflow-auto') return { overflow: 'auto' }\n\n return null\n}\n\n/**\n * Get color value from Tailwind color palette.\n */\nfunction getColor(color: string, shade: number): string | null {\n const colors: Record<string, Record<number, string>> = {\n slate: { 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1', 400: '#94a3b8', 500: '#64748b', 600: '#475569', 700: '#334155', 800: '#1e293b', 900: '#0f172a' },\n gray: { 50: '#f9fafb', 100: '#f3f4f6', 200: '#e5e7eb', 300: '#d1d5db', 400: '#9ca3af', 500: '#6b7280', 600: '#4b5563', 700: '#374151', 800: '#1f2937', 900: '#111827' },\n red: { 50: '#fef2f2', 100: '#fee2e2', 200: '#fecaca', 300: '#fca5a5', 400: '#f87171', 500: '#ef4444', 600: '#dc2626', 700: '#b91c1c', 800: '#991b1b', 900: '#7f1d1d' },\n orange: { 50: '#fff7ed', 100: '#ffedd5', 200: '#fed7aa', 300: '#fdba74', 400: '#fb923c', 500: '#f97316', 600: '#ea580c', 700: '#c2410c', 800: '#9a3412', 900: '#7c2d12' },\n yellow: { 50: '#fefce8', 100: '#fef9c3', 200: '#fef08a', 300: '#fde047', 400: '#facc15', 500: '#eab308', 600: '#ca8a04', 700: '#a16207', 800: '#854d0e', 900: '#713f12' },\n green: { 50: '#f0fdf4', 100: '#dcfce7', 200: '#bbf7d0', 300: '#86efac', 400: '#4ade80', 500: '#22c55e', 600: '#16a34a', 700: '#15803d', 800: '#166534', 900: '#14532d' },\n blue: { 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd', 400: '#60a5fa', 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8', 800: '#1e40af', 900: '#1e3a8a' },\n indigo: { 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc', 400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca', 800: '#3730a3', 900: '#312e81' },\n purple: { 50: '#faf5ff', 100: '#f3e8ff', 200: '#e9d5ff', 300: '#d8b4fe', 400: '#c084fc', 500: '#a855f7', 600: '#9333ea', 700: '#7e22ce', 800: '#6b21a8', 900: '#581c87' },\n pink: { 50: '#fdf2f8', 100: '#fce7f3', 200: '#fbcfe8', 300: '#f9a8d4', 400: '#f472b6', 500: '#ec4899', 600: '#db2777', 700: '#be185d', 800: '#9d174d', 900: '#831843' }\n }\n\n return colors[color]?.[shade] ?? null\n}\n\n// ============================================================================\n// Headwind CLI Integration\n// ============================================================================\n\n/**\n * Headwind CLI configuration.\n */\nexport interface HeadwindConfig {\n /** Content paths to scan for classes */\n content: string[]\n /** Output CSS file path */\n output: string\n /** Enable minification */\n minify?: boolean\n /** Dark mode strategy */\n darkMode?: 'class' | 'media'\n /** Custom theme extensions */\n theme?: {\n extend?: {\n colors?: Record<string, string | Record<string, string>>\n spacing?: Record<string, string>\n fontSize?: Record<string, string>\n fontFamily?: Record<string, string[]>\n borderRadius?: Record<string, string>\n }\n }\n /** Enable JIT mode */\n jit?: boolean\n}\n\n/**\n * Generate Headwind configuration file.\n *\n * @example\n * const config = generateConfig({\n * content: ['./src/components/*.tsx'],\n * output: './dist/styles.css',\n * minify: true,\n * darkMode: 'class',\n * theme: {\n * extend: {\n * colors: {\n * brand: { 50: '#f0f9ff', 500: '#3b82f6', 900: '#1e3a8a' }\n * }\n * }\n * }\n * })\n */\nexport function generateConfig(options: HeadwindConfig): string {\n return JSON.stringify({\n content: options.content,\n output: options.output,\n minify: options.minify ?? false,\n darkMode: options.darkMode ?? 'class',\n jit: options.jit ?? true,\n theme: options.theme ?? {}\n }, null, 2)\n}\n\n/**\n * Build CSS using Headwind CLI.\n * Requires zig-headwind to be installed.\n *\n * @example\n * await buildCSS({\n * content: ['./src/components/*.tsx'],\n * output: './public/styles.css',\n * minify: process.env.NODE_ENV === 'production'\n * })\n */\nexport async function buildCSS(options: HeadwindConfig): Promise<void> {\n if (typeof window !== 'undefined') {\n console.warn('buildCSS can only be run in Node.js environment')\n return\n }\n\n const { exec } = await import('child_process')\n const { promisify } = await import('util')\n const execAsync = promisify(exec)\n\n const args = [\n 'build',\n '--content', options.content.join(','),\n '--output', options.output\n ]\n\n if (options.minify) args.push('--minify')\n\n try {\n await execAsync(`headwind ${args.join(' ')}`)\n console.log(`CSS built successfully: ${options.output}`)\n }\ncatch (error) {\n console.error('Failed to build CSS:', error)\n throw error\n }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nconst _exports: {\n tw: typeof tw;\n cx: typeof cx;\n variants: typeof variants;\n style: typeof style;\n generateConfig: typeof generateConfig;\n buildCSS: typeof buildCSS;\n} = {\n tw,\n cx,\n variants,\n style,\n generateConfig,\n buildCSS\n};\nexport default _exports;\n",
|
|
36
|
+
"/**\n * Craft Sidebar Styles\n * CSS/Tailwind-based sidebar implementations\n *\n * Three styles:\n * - Tahoe: the macOS Tahoe (26/27) source list\n * - Arc: Arc browser vertical tabs style\n * - OrbStack: Dark minimal style\n *\n * For stx apps, prefer `@stacksjs/components`' <Sidebar theme=\"macos\"> —\n * the canonical, behavior-complete implementation these class maps mirror.\n *\n * @module @craft-native/styles/sidebars\n */\n\n// ============================================================================\n// Tahoe Style (macOS source list)\n// ============================================================================\n\n/**\n * Tahoe sidebar — the macOS Tahoe (26/27 \"Liquid Glass\") source list.\n *\n * Metrics measured from native Mail/Music/Notes at @2x:\n * 30px rows + 2px gap, 9px-radius quaternary-fill highlight, 17px icons,\n * 13px labels, plain gray tabular counts, 11px semibold section headers.\n * Selection is a translucent gray fill — never an accent-colored pill.\n */\nexport const tahoeStyles = {\n // Container: frosted sidebar material. In a Craft window with\n // `webSidebarMaterial` the native vibrancy shows through instead.\n sidebar: `\n w-[250px] h-full flex flex-col\n bg-white/55 dark:bg-[#1e1e23]/55\n backdrop-blur-[60px] backdrop-saturate-[1.8]\n text-black dark:text-white\n select-none\n `,\n\n // Scrollable content area\n content: `\n flex-1 overflow-y-auto overflow-x-hidden\n px-[10px] pb-[10px]\n `,\n\n // Section container\n section: `\n flex flex-col gap-[2px]\n `,\n\n // Section header — Title Case, 11px semibold secondary gray\n sectionHeader: `\n pl-[8px] pr-[6px] pt-[16px] pb-[5px]\n text-[11px] font-semibold leading-[13px]\n text-[#3c3c43]/60 dark:text-[#ebebf5]/60\n `,\n\n // Section header (collapsible — chevron revealed on hover)\n sectionHeaderCollapsible: `\n group flex items-center w-full\n pl-[8px] pr-[6px] pt-[16px] pb-[5px]\n text-[11px] font-semibold leading-[13px]\n text-[#3c3c43]/60 dark:text-[#ebebf5]/60\n cursor-default\n `,\n\n // Collapse chevron (section header, hover-revealed)\n collapseChevron: `\n ml-auto h-[11px] w-[11px]\n text-[#3c3c43]/45 dark:text-[#ebebf5]/45\n opacity-0 group-hover:opacity-100\n transition-all duration-200\n `,\n\n // Item — 30px row, 9px radius, subtle hover fill\n item: `\n flex w-full items-center\n h-[30px] rounded-[9px] pl-[4px] pr-[8px]\n text-[13px] leading-[16px] text-black dark:text-white\n cursor-default transition-colors duration-150 ease-out\n hover:bg-black/4 dark:hover:bg-white/6\n active:bg-black/10 dark:active:bg-white/18\n `,\n\n // Item selected — quaternary fill, same text color (no accent, no bold)\n itemSelected: `\n flex w-full items-center\n h-[30px] rounded-[9px] pl-[4px] pr-[8px]\n text-[13px] leading-[16px] text-black dark:text-white\n cursor-default\n bg-black/8 dark:bg-white/14\n `,\n\n // Disclosure gutter before the icon (chevron slot)\n disclosure: `\n flex h-[16px] w-[18px] shrink-0 items-center justify-center\n `,\n\n // Disclosure chevron (rotates 90deg when expanded)\n disclosureChevron: `\n h-[11px] w-[11px]\n text-[#3c3c43]/55 dark:text-[#ebebf5]/55\n transition-transform duration-200 ease-out\n `,\n\n // Item icon — 17px SF-Symbol-style glyph, tinted with a system color\n itemIcon: `\n h-[17px] w-[17px] flex-shrink-0\n text-[#0088ff]\n `,\n\n // Item icon (selected) — tint does not change on selection\n itemIconSelected: `\n h-[17px] w-[17px] flex-shrink-0\n text-[#0088ff]\n `,\n\n // Fixed slot centering the icon\n itemIconSlot: `\n flex h-[20px] w-[22px] shrink-0 items-center justify-center mr-[7px]\n `,\n\n // Item label\n itemLabel: `\n flex-1 truncate\n `,\n\n // Item count — plain gray tabular text, not a pill\n itemBadge: `\n ml-[8px] shrink-0 tabular-nums\n text-[13px] leading-[16px]\n text-[#3c3c43]/60 dark:text-[#ebebf5]/60\n `,\n\n // Item count (selected) — unchanged by selection\n itemBadgeSelected: `\n ml-[8px] shrink-0 tabular-nums\n text-[13px] leading-[16px]\n text-[#3c3c43]/60 dark:text-[#ebebf5]/60\n `,\n\n // Expandable item children container — indented, no guide line\n children: `\n ml-[16px] mt-[2px] flex flex-col gap-[2px]\n `,\n\n // Drag indicator\n dragIndicator: `\n absolute left-0 right-0 h-0.5 bg-[#0088ff]\n pointer-events-none\n `,\n\n // Search input\n searchContainer: `\n px-[10px] pb-[6px]\n `,\n\n searchInput: `\n h-[28px] w-full rounded-[8px] px-[8px]\n text-[13px] text-black dark:text-white\n placeholder:text-[#3c3c43]/50 dark:placeholder:text-[#ebebf5]/50\n bg-black/5 dark:bg-white/10\n border border-transparent\n focus:outline-none focus:ring-2 focus:ring-[#0088ff]/60\n transition-all duration-150\n `,\n\n // Header area — traffic-light strip height, drag region\n header: `\n h-[52px] px-[21px] flex items-center gap-3\n `,\n\n headerAvatar: `\n w-[30px] h-[30px] rounded-full bg-black/10 dark:bg-white/15\n flex items-center justify-center text-[13px] font-semibold\n `,\n\n headerTitle: `\n text-[13px] font-medium text-black dark:text-white\n `,\n\n headerSubtitle: `\n text-[11px] text-[#3c3c43]/60 dark:text-[#ebebf5]/60\n `,\n\n // Footer — account row area, like Music\n footer: `\n px-[10px] pb-[8px] pt-[4px] flex items-center gap-2\n `,\n\n footerButton: `\n grid h-[28px] w-[28px] place-items-center rounded-[7px]\n text-[#3c3c43]/70 dark:text-[#ebebf5]/70\n hover:bg-black/5 dark:hover:bg-white/10\n transition-colors duration-150\n `,\n}\n\n// ============================================================================\n// Arc Style (Arc Browser)\n// ============================================================================\n\n/**\n * Arc sidebar - Arc browser vertical tabs style\n *\n * Features:\n * - Pill-shaped selection with gradient\n * - Collapsible to icon-only mode\n * - Colorful accent options\n * - Pinned items section\n * - Animated transitions\n */\nexport const arcStyles = {\n // Container - expanded\n sidebar: `\n w-64 h-full flex flex-col\n bg-neutral-100 dark:bg-neutral-900\n border-r border-neutral-200 dark:border-neutral-800\n transition-all duration-300 ease-out\n select-none\n `,\n\n // Container - collapsed (icon only)\n sidebarCollapsed: `\n w-12 h-full flex flex-col\n bg-neutral-100 dark:bg-neutral-900\n border-r border-neutral-200 dark:border-neutral-800\n transition-all duration-300 ease-out\n select-none\n `,\n\n // Top bar with controls\n topBar: `\n h-10 px-2 flex items-center justify-between\n border-b border-neutral-200 dark:border-neutral-800\n `,\n\n // Collapse toggle button\n collapseButton: `\n p-1.5 rounded-lg\n text-neutral-500 dark:text-neutral-400\n hover:bg-neutral-200 dark:hover:bg-neutral-800\n transition-colors duration-150\n `,\n\n // New tab button\n newTabButton: `\n p-1.5 rounded-lg\n text-neutral-500 dark:text-neutral-400\n hover:bg-neutral-200 dark:hover:bg-neutral-800\n transition-colors duration-150\n `,\n\n // Content area\n content: `\n flex-1 overflow-y-auto overflow-x-hidden\n py-2\n scrollbar-thin scrollbar-thumb-neutral-300 dark:scrollbar-thumb-neutral-700\n `,\n\n // Pinned section\n pinnedSection: `\n px-2 pb-3 mb-2 border-b border-neutral-200 dark:border-neutral-800\n `,\n\n pinnedLabel: `\n px-2 py-1 text-[10px] font-semibold uppercase tracking-wider\n text-neutral-400 dark:text-neutral-500\n `,\n\n // Section header\n sectionHeader: `\n px-3 py-2 flex items-center justify-between\n text-[11px] font-semibold uppercase tracking-wider\n text-neutral-500 dark:text-neutral-400\n `,\n\n // Space/folder container\n space: `\n mb-3\n `,\n\n spaceHeader: `\n px-2 py-1.5 mx-2 rounded-lg flex items-center gap-2\n cursor-pointer\n hover:bg-neutral-200/50 dark:hover:bg-neutral-800/50\n transition-colors duration-150\n `,\n\n spaceIcon: `\n w-5 h-5 rounded-md flex items-center justify-center text-xs\n `,\n\n spaceName: `\n flex-1 text-[12px] font-medium text-neutral-700 dark:text-neutral-200\n `,\n\n spaceCount: `\n text-[11px] text-neutral-400 dark:text-neutral-500\n `,\n\n // Item (tab)\n item: `\n flex items-center gap-2.5 px-3 py-2 mx-2 rounded-xl\n text-[13px] text-neutral-700 dark:text-neutral-300\n cursor-pointer transition-all duration-200\n hover:bg-neutral-200/70 dark:hover:bg-neutral-800/70\n group\n `,\n\n // Item selected - with gradient pill\n itemSelected: `\n flex items-center gap-2.5 px-3 py-2 mx-2 rounded-xl\n text-[13px] text-white font-medium\n cursor-pointer transition-all duration-200\n bg-gradient-to-r from-purple-500 to-pink-500\n shadow-lg shadow-purple-500/25\n `,\n\n // Item (collapsed mode - icon only)\n itemCollapsed: `\n flex items-center justify-center p-2.5 mx-1.5 rounded-xl\n cursor-pointer transition-all duration-200\n hover:bg-neutral-200/70 dark:hover:bg-neutral-800/70\n group relative\n `,\n\n itemCollapsedSelected: `\n flex items-center justify-center p-2.5 mx-1.5 rounded-xl\n cursor-pointer transition-all duration-200\n bg-gradient-to-r from-purple-500 to-pink-500\n shadow-lg shadow-purple-500/25\n `,\n\n // Favicon/icon container\n itemFavicon: `\n w-4 h-4 rounded flex-shrink-0\n bg-neutral-300 dark:bg-neutral-700\n `,\n\n itemFaviconSelected: `\n w-4 h-4 rounded flex-shrink-0\n `,\n\n // Item label\n itemLabel: `\n flex-1 truncate\n `,\n\n // Close button (visible on hover)\n itemClose: `\n p-0.5 rounded opacity-0 group-hover:opacity-100\n text-neutral-400 hover:text-neutral-600\n dark:text-neutral-500 dark:hover:text-neutral-300\n hover:bg-neutral-300/50 dark:hover:bg-neutral-700/50\n transition-all duration-150\n `,\n\n itemCloseSelected: `\n p-0.5 rounded opacity-0 group-hover:opacity-100\n text-white/60 hover:text-white\n hover:bg-white/20\n transition-all duration-150\n `,\n\n // Tooltip for collapsed mode\n tooltip: `\n absolute left-full ml-2 px-2 py-1 rounded-md\n text-[12px] text-white bg-neutral-800 dark:bg-neutral-700\n whitespace-nowrap opacity-0 group-hover:opacity-100\n pointer-events-none transition-opacity duration-150\n z-50\n `,\n\n // Today section\n todaySection: `\n px-2 pt-2\n `,\n\n todayLabel: `\n px-2 py-1 text-[10px] font-semibold uppercase tracking-wider\n text-neutral-400 dark:text-neutral-500\n `,\n\n // Bottom bar\n bottomBar: `\n px-2 py-2 border-t border-neutral-200 dark:border-neutral-800\n flex items-center gap-1\n `,\n\n bottomButton: `\n flex-1 py-2 rounded-lg flex items-center justify-center gap-2\n text-[12px] text-neutral-600 dark:text-neutral-400\n hover:bg-neutral-200 dark:hover:bg-neutral-800\n transition-colors duration-150\n `,\n\n // Color options for spaces\n spaceColors: {\n red: 'bg-red-500',\n orange: 'bg-orange-500',\n yellow: 'bg-yellow-500',\n green: 'bg-green-500',\n blue: 'bg-blue-500',\n purple: 'bg-purple-500',\n pink: 'bg-pink-500',\n },\n\n // Gradient options for selected items\n selectedGradients: {\n purple: 'bg-gradient-to-r from-purple-500 to-pink-500 shadow-purple-500/25',\n blue: 'bg-gradient-to-r from-blue-500 to-cyan-500 shadow-blue-500/25',\n green: 'bg-gradient-to-r from-green-500 to-emerald-500 shadow-green-500/25',\n orange: 'bg-gradient-to-r from-orange-500 to-amber-500 shadow-orange-500/25',\n red: 'bg-gradient-to-r from-red-500 to-rose-500 shadow-red-500/25',\n },\n}\n\n// ============================================================================\n// OrbStack Style (Dark Minimal)\n// ============================================================================\n\n/**\n * OrbStack sidebar - Dark minimal style\n *\n * Features:\n * - Dark theme optimized\n * - Compact spacing\n * - Subtle hover states\n * - Monochrome icons\n * - Clean, utilitarian design\n */\nexport const orbstackStyles = {\n // Container\n sidebar: `\n w-52 h-full flex flex-col\n bg-[#1a1a1a] dark:bg-[#1a1a1a]\n border-r border-[#2a2a2a]\n select-none\n `,\n\n // Header\n header: `\n h-12 px-3 flex items-center justify-between\n border-b border-[#2a2a2a]\n `,\n\n headerTitle: `\n text-[13px] font-semibold text-white\n `,\n\n headerAction: `\n p-1 rounded\n text-neutral-500 hover:text-neutral-300\n hover:bg-white/5\n transition-colors duration-150\n `,\n\n // Content\n content: `\n flex-1 overflow-y-auto overflow-x-hidden\n py-1\n scrollbar-thin scrollbar-thumb-neutral-700 scrollbar-track-transparent\n `,\n\n // Section\n section: `\n py-1\n `,\n\n sectionHeader: `\n px-3 py-2 flex items-center justify-between\n text-[11px] font-medium uppercase tracking-wider\n text-neutral-500\n `,\n\n sectionHeaderClickable: `\n px-3 py-2 flex items-center justify-between cursor-pointer\n text-[11px] font-medium uppercase tracking-wider\n text-neutral-500 hover:text-neutral-400\n transition-colors duration-150\n `,\n\n sectionCount: `\n text-[10px] px-1.5 py-0.5 rounded\n bg-neutral-800 text-neutral-400\n `,\n\n // Divider\n divider: `\n my-1 mx-3 border-t border-[#2a2a2a]\n `,\n\n // Item\n item: `\n flex items-center gap-2.5 px-3 py-1.5\n text-[13px] text-neutral-300\n cursor-pointer transition-colors duration-150\n hover:bg-white/5 hover:text-white\n `,\n\n // Item selected\n itemSelected: `\n flex items-center gap-2.5 px-3 py-1.5\n text-[13px] text-white font-medium\n cursor-pointer\n bg-white/10\n `,\n\n // Item with indicator (running state)\n itemWithIndicator: `\n flex items-center gap-2.5 px-3 py-1.5\n text-[13px] text-neutral-300\n cursor-pointer transition-colors duration-150\n hover:bg-white/5 hover:text-white\n relative\n `,\n\n // Running indicator dot\n runningIndicator: `\n w-1.5 h-1.5 rounded-full bg-green-500\n absolute left-1\n `,\n\n // Stopped indicator\n stoppedIndicator: `\n w-1.5 h-1.5 rounded-full bg-neutral-600\n absolute left-1\n `,\n\n // Item icon\n itemIcon: `\n w-4 h-4 flex-shrink-0\n text-neutral-500\n `,\n\n itemIconSelected: `\n w-4 h-4 flex-shrink-0\n text-white\n `,\n\n // Item label\n itemLabel: `\n flex-1 truncate\n `,\n\n // Item status text\n itemStatus: `\n text-[11px] text-neutral-500\n `,\n\n // Item actions (show on hover)\n itemActions: `\n flex items-center gap-1 opacity-0 group-hover:opacity-100\n transition-opacity duration-150\n `,\n\n itemActionButton: `\n p-1 rounded\n text-neutral-500 hover:text-white\n hover:bg-white/10\n transition-colors duration-150\n `,\n\n // Expandable group\n group: `\n group\n `,\n\n groupHeader: `\n flex items-center gap-2 px-3 py-1.5 cursor-pointer\n text-[13px] text-neutral-400\n hover:bg-white/5 hover:text-neutral-200\n transition-colors duration-150\n `,\n\n groupChevron: `\n w-3 h-3 text-neutral-600\n transition-transform duration-200\n `,\n\n groupChevronExpanded: `\n w-3 h-3 text-neutral-600\n transition-transform duration-200\n rotate-90\n `,\n\n groupContent: `\n overflow-hidden transition-all duration-200\n `,\n\n // Footer\n footer: `\n px-3 py-2 border-t border-[#2a2a2a]\n flex items-center justify-between\n `,\n\n footerText: `\n text-[11px] text-neutral-500\n `,\n\n footerButton: `\n p-1.5 rounded\n text-neutral-500 hover:text-white\n hover:bg-white/10\n transition-colors duration-150\n `,\n\n // Context menu\n contextMenu: `\n min-w-40 py-1 rounded-lg\n bg-[#252525] border border-[#3a3a3a]\n shadow-xl shadow-black/50\n `,\n\n contextMenuItem: `\n px-3 py-1.5 flex items-center gap-2\n text-[13px] text-neutral-300\n cursor-pointer\n hover:bg-white/10\n transition-colors duration-100\n `,\n\n contextMenuItemDanger: `\n px-3 py-1.5 flex items-center gap-2\n text-[13px] text-red-400\n cursor-pointer\n hover:bg-red-500/10\n transition-colors duration-100\n `,\n\n contextMenuDivider: `\n my-1 border-t border-[#3a3a3a]\n `,\n\n // Empty state\n emptyState: `\n flex flex-col items-center justify-center py-8\n text-neutral-500\n `,\n\n emptyStateIcon: `\n w-8 h-8 mb-2 text-neutral-600\n `,\n\n emptyStateText: `\n text-[13px]\n `,\n\n // Loading state\n loadingSpinner: `\n w-4 h-4 border-2 border-neutral-600 border-t-neutral-400\n rounded-full animate-spin\n `,\n}\n\n// ============================================================================\n// Utility Classes\n// ============================================================================\n\n/**\n * Common utility classes for all sidebar styles\n */\nexport const sidebarUtils = {\n // Transitions\n transitionFast: 'transition-all duration-150',\n transitionNormal: 'transition-all duration-200',\n transitionSlow: 'transition-all duration-300',\n\n // Scrollbar styles\n scrollbarThin: 'scrollbar-thin scrollbar-track-transparent',\n scrollbarLight: 'scrollbar-thumb-black/10 hover:scrollbar-thumb-black/20',\n scrollbarDark: 'scrollbar-thumb-white/10 hover:scrollbar-thumb-white/20',\n\n // Focus styles\n focusRing: 'focus:outline-none focus:ring-2 focus:ring-blue-500/50',\n focusRingInset: 'focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500/50',\n\n // Text truncation\n truncate: 'truncate',\n lineClamp2: 'line-clamp-2',\n\n // Flex utilities\n flexCenter: 'flex items-center justify-center',\n flexBetween: 'flex items-center justify-between',\n flexStart: 'flex items-center justify-start',\n\n // Hide scrollbar but keep functionality\n hideScrollbar: 'scrollbar-none [-ms-overflow-style:none] [scrollbar-width:none]',\n}\n\n// ============================================================================\n// CSS Custom Properties (for dynamic theming)\n// ============================================================================\n\n/**\n * CSS variables for sidebar theming\n * Inject these into your app's root styles\n */\nexport const sidebarCSSVariables = `\n:root {\n /* Tahoe style variables */\n --sidebar-tahoe-bg: rgba(255, 255, 255, 0.7);\n --sidebar-tahoe-bg-dark: rgba(30, 30, 30, 0.7);\n --sidebar-tahoe-border: rgba(0, 0, 0, 0.05);\n --sidebar-tahoe-border-dark: rgba(255, 255, 255, 0.05);\n --sidebar-tahoe-text: #404040;\n --sidebar-tahoe-text-dark: #e5e5e5;\n --sidebar-tahoe-text-muted: #737373;\n --sidebar-tahoe-text-muted-dark: #a3a3a3;\n --sidebar-tahoe-selected: #3b82f6;\n --sidebar-tahoe-hover: rgba(0, 0, 0, 0.05);\n --sidebar-tahoe-hover-dark: rgba(255, 255, 255, 0.05);\n\n /* Arc style variables */\n --sidebar-arc-bg: #f5f5f5;\n --sidebar-arc-bg-dark: #171717;\n --sidebar-arc-border: #e5e5e5;\n --sidebar-arc-border-dark: #262626;\n --sidebar-arc-selected-from: #a855f7;\n --sidebar-arc-selected-to: #ec4899;\n --sidebar-arc-hover: rgba(0, 0, 0, 0.05);\n --sidebar-arc-hover-dark: rgba(255, 255, 255, 0.05);\n\n /* OrbStack style variables */\n --sidebar-orb-bg: #1a1a1a;\n --sidebar-orb-border: #2a2a2a;\n --sidebar-orb-text: #d4d4d4;\n --sidebar-orb-text-muted: #737373;\n --sidebar-orb-selected: rgba(255, 255, 255, 0.1);\n --sidebar-orb-hover: rgba(255, 255, 255, 0.05);\n --sidebar-orb-accent: #22c55e;\n}\n`\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Combine multiple class strings\n */\nexport function cx(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(' ').replace(/\\s+/g, ' ').trim()\n}\n\n/**\n * Get style preset by name\n */\nexport function getSidebarStyle(name: 'tahoe' | 'arc' | 'orbstack'): typeof tahoeStyles | typeof arcStyles | typeof orbstackStyles {\n switch (name) {\n case 'tahoe':\n return tahoeStyles\n case 'arc':\n return arcStyles\n case 'orbstack':\n return orbstackStyles\n default:\n return tahoeStyles\n }\n}\n\n// ============================================================================\n// Export all styles\n// ============================================================================\n\nconst _exports: {\n tahoe: typeof tahoeStyles;\n arc: typeof arcStyles;\n orbstack: typeof orbstackStyles;\n utils: typeof sidebarUtils;\n cssVariables: typeof sidebarCSSVariables;\n cx: typeof cx;\n getSidebarStyle: typeof getSidebarStyle;\n} = {\n tahoe: tahoeStyles,\n arc: arcStyles,\n orbstack: orbstackStyles,\n utils: sidebarUtils,\n cssVariables: sidebarCSSVariables,\n cx,\n getSidebarStyle,\n};\nexport default _exports;\n",
|
|
37
|
+
"/**\n * Craft Sidebar HTML Templates\n * Ready-to-use HTML templates for each sidebar style\n *\n * These can be rendered directly in Craft WebView or used as\n * reference for building your own components.\n *\n * @module @craft-native/styles/sidebar-templates\n */\n\nimport { tahoeStyles, arcStyles, orbstackStyles, cx } from './sidebars'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SidebarItemData {\n id: string\n label: string\n icon?: string\n badge?: string | number\n selected?: boolean\n children?: SidebarItemData[]\n expanded?: boolean\n status?: 'running' | 'stopped' | 'none'\n color?: string\n}\n\nexport interface SidebarSectionData {\n id: string\n title?: string\n items: SidebarItemData[]\n collapsible?: boolean\n collapsed?: boolean\n}\n\nexport interface SidebarData {\n sections?: SidebarSectionData[]\n items?: SidebarItemData[]\n header?: {\n title?: string\n subtitle?: string\n avatar?: string\n }\n footer?: {\n items?: SidebarItemData[]\n }\n searchPlaceholder?: string\n showSearch?: boolean\n}\n\n// ============================================================================\n// Icon SVGs (SF Symbol-like)\n// ============================================================================\n\nconst icons = {\n home: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6'/></svg>`,\n folder: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z'/></svg>`,\n document: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z'/></svg>`,\n star: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z'/></svg>`,\n download: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4'/></svg>`,\n cloud: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z'/></svg>`,\n settings: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z'/><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M15 12a3 3 0 11-6 0 3 3 0 016 0z'/></svg>`,\n plus: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M12 4v16m8-8H4'/></svg>`,\n search: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z'/></svg>`,\n chevronRight: `<svg class='h-3 w-3' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5l7 7-7 7'/></svg>`,\n chevronDown: `<svg class='h-3 w-3' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'/></svg>`,\n x: `<svg class='h-3 w-3' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18L18 6M6 6l12 12'/></svg>`,\n menu: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 6h16M4 12h16M4 18h16'/></svg>`,\n container: `<svg class='h-4 w-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4'/></svg>`,\n linux: `<svg class='h-4 w-4' fill='currentColor' viewBox='0 0 24 24'><path d='M12.504 0c-.155 0-.311.001-.465.003-.653.014-1.304.07-1.952.17-1.328.205-2.607.596-3.796 1.157-1.189.56-2.28 1.293-3.234 2.174-.954.88-1.757 1.9-2.384 3.022-.627 1.122-1.07 2.342-1.313 3.608-.244 1.266-.286 2.575-.126 3.855.16 1.28.519 2.517 1.066 3.666.547 1.149 1.274 2.197 2.152 3.105.877.908 1.9 1.666 3.025 2.249 1.126.583 2.349.984 3.609 1.192 1.261.208 2.555.218 3.82.029 1.265-.189 2.497-.576 3.642-1.148 1.145-.572 2.187-1.32 3.086-2.212.898-.892 1.643-1.922 2.212-3.045.568-1.123.952-2.332 1.138-3.577.186-1.245.176-2.518-.03-3.766-.206-1.248-.607-2.462-1.191-3.588-.583-1.125-1.343-2.15-2.25-3.029-.907-.879-1.957-1.607-3.1-2.156-1.142-.548-2.377-.913-3.643-1.078-.653-.085-1.31-.125-1.966-.125z'/></svg>`,\n}\n\nfunction getIcon(name: string): string {\n return icons[name as keyof typeof icons] || icons.document\n}\n\n// ============================================================================\n// Tahoe Template (macOS Tahoe source list)\n// ============================================================================\n\n// eslint-disable-next-line pickier/no-unused-vars\nexport function renderTahoeSidebar(data: SidebarData): string {\n const s = tahoeStyles\n\n const renderItem = (item: SidebarItemData, depth = 0): string => {\n const isSelected = item.selected\n const itemClass = isSelected ? s.itemSelected : s.item\n const iconClass = isSelected ? s.itemIconSelected : s.itemIcon\n const badgeClass = isSelected ? s.itemBadgeSelected : s.itemBadge\n const hasChildren = (item.children?.length ?? 0) > 0\n // macOS reserves the disclosure gutter on every row so icons align;\n // the chevron only appears on expandable rows, pointing down when open.\n const chevron = hasChildren\n ? `<span class='${s.disclosureChevron}${item.expanded ? ' rotate-90' : ''}'>${icons.chevronRight}</span>`\n : ''\n // Icon tint accepts any CSS color; defaults to the class's system blue.\n const tint = item.color ? ` style='color: ${item.color}'` : ''\n\n let html = `\n <div class='${itemClass}' data-id='${item.id}'${depth > 0 ? ` style='padding-left: ${4 + depth * 16}px'` : ''}>\n <span class='${s.disclosure}'>${chevron}</span>\n <span class='${s.itemIconSlot}'><span class='${iconClass}'${tint}>${getIcon(item.icon || 'document')}</span></span>\n <span class='${s.itemLabel}'>${item.label}</span>\n ${item.badge ? `<span class='${badgeClass}'>${item.badge}</span>` : ''}\n </div>\n `\n\n if (item.children && item.expanded) {\n item.children.forEach(child => {\n html += renderItem(child, depth + 1)\n })\n }\n\n return html\n }\n\n // eslint-disable-next-line pickier/no-unused-vars\n const renderSection = (section: SidebarSectionData): string => {\n return `\n <div class='${s.section}'>\n ${section.title ? `\n <div class=\"${section.collapsible ? s.sectionHeaderCollapsible : s.sectionHeader}\" data-section=\"${section.id}\">\n <span class='truncate'>${section.title}</span>\n ${section.collapsible ? `<span class='${s.collapseChevron}${section.collapsed ? ' -rotate-90' : ''}'>${icons.chevronDown}</span>` : ''}\n </div>\n ` : ''}\n ${!section.collapsed ? section.items.map(item => renderItem(item)).join('') : ''}\n </div>\n `\n }\n\n return `\n <div class='${s.sidebar}'>\n ${data.header ? `\n <div class='${s.header}'>\n ${data.header.avatar ? `\n <div class=\"${s.headerAvatar}\">${data.header.avatar}</div>\n ` : ''}\n <div>\n ${data.header.title ? `<div class=\"${s.headerTitle}\">${data.header.title}</div>` : ''}\n ${data.header.subtitle ? `<div class=\"${s.headerSubtitle}\">${data.header.subtitle}</div>` : ''}\n </div>\n </div>\n ` : ''}\n\n ${data.showSearch ? `\n <div class='${s.searchContainer}'>\n <input type='text' class='${s.searchInput}' placeholder='${data.searchPlaceholder || 'Search'}' />\n </div>\n ` : ''}\n\n <div class='${s.content}'>\n ${data.sections ? data.sections.map(section => renderSection(section)).join('') : ''}\n ${data.items ? data.items.map(item => renderItem(item)).join('') : ''}\n </div>\n\n ${data.footer ? `\n <div class='${s.footer}'>\n ${data.footer.items?.map(item => `\n <button class=\"${s.footerButton}\" data-id=\"${item.id}\">\n ${getIcon(item.icon || 'settings')}\n </button>\n `).join('') || ''}\n </div>\n ` : ''}\n </div>\n `\n}\n\n// ============================================================================\n// Arc Template (Arc Browser)\n// ============================================================================\n\nexport function renderArcSidebar(data: SidebarData, collapsed = false): string {\n const s = arcStyles\n const sidebarClass = collapsed ? s.sidebarCollapsed : s.sidebar\n\n const renderItem = (item: SidebarItemData): string => {\n const isSelected = item.selected\n\n if (collapsed) {\n const itemClass = isSelected ? s.itemCollapsedSelected : s.itemCollapsed\n return `\n <div class='${itemClass}' data-id='${item.id}'>\n <span class=\"${isSelected ? s.itemFaviconSelected : s.itemFavicon}\">\n ${item.icon ? getIcon(item.icon) : ''}\n </span>\n <div class='${s.tooltip}'>${item.label}</div>\n </div>\n `\n }\n\n const itemClass = isSelected ? s.itemSelected : s.item\n const closeClass = isSelected ? s.itemCloseSelected : s.itemClose\n\n return `\n <div class='${itemClass} group' data-id='${item.id}'>\n <span class=\"${isSelected ? s.itemFaviconSelected : s.itemFavicon}\">\n ${item.icon ? getIcon(item.icon) : ''}\n </span>\n <span class='${s.itemLabel}'>${item.label}</span>\n <button class='${closeClass}'>${icons.x}</button>\n </div>\n `\n }\n\n const renderSpace = (section: SidebarSectionData): string => {\n const color = s.spaceColors[(section as any).color as keyof typeof s.spaceColors] || s.spaceColors.purple\n return `\n <div class='${s.space}'>\n <div class='${s.spaceHeader}' data-space='${section.id}'>\n <div class='${color} ${s.spaceIcon}'>${section.title?.[0] || '•'}</div>\n ${!collapsed ? `\n <span class='${s.spaceName}'>${section.title}</span>\n <span class='${s.spaceCount}'>${section.items.length}</span>\n ` : ''}\n </div>\n ${!section.collapsed ? section.items.map(item => renderItem(item)).join('') : ''}\n </div>\n `\n }\n\n return `\n <div class='${sidebarClass}'>\n <div class='${s.topBar}'>\n <button class='${s.collapseButton}' id='arc-collapse-toggle'>\n ${icons.menu}\n </button>\n ${!collapsed ? `\n <button class='${s.newTabButton}'>\n ${icons.plus}\n </button>\n ` : ''}\n </div>\n\n <div class='${s.content}'>\n ${data.sections?.[0]?.title === 'Pinned' ? `\n <div class='${s.pinnedSection}'>\n ${!collapsed ? `<div class=\"${s.pinnedLabel}\">Pinned</div>` : ''}\n ${data.sections[0].items.map(item => renderItem(item)).join('')}\n </div>\n ` : ''}\n\n ${data.sections?.slice(data.sections[0]?.title === 'Pinned' ? 1 : 0).map(section => renderSpace(section)).join('') || ''}\n ${data.items ? data.items.map(item => renderItem(item)).join('') : ''}\n </div>\n\n <div class='${s.bottomBar}'>\n ${!collapsed ? `\n <button class='${s.bottomButton}'>\n ${icons.download}\n <span>Downloads</span>\n </button>\n ` : `\n <button class='${s.collapseButton}'>\n ${icons.download}\n </button>\n `}\n </div>\n </div>\n `\n}\n\n// ============================================================================\n// OrbStack Template (Dark Minimal)\n// ============================================================================\n\nexport function renderOrbStackSidebar(data: SidebarData): string {\n const s = orbstackStyles\n\n const renderItem = (item: SidebarItemData): string => {\n const isSelected = item.selected\n const itemClass = isSelected ? s.itemSelected : s.item\n const iconClass = isSelected ? s.itemIconSelected : s.itemIcon\n\n const hasIndicator = item.status && item.status !== 'none'\n const indicatorClass = item.status === 'running' ? s.runningIndicator : s.stoppedIndicator\n\n return `\n <div class='${itemClass} group' data-id='${item.id}' ${hasIndicator ? `style='padding-left: 20px'` : ''}>\n ${hasIndicator ? `<div class='${indicatorClass}'></div>` : ''}\n <span class='${iconClass}'>${getIcon(item.icon || 'container')}</span>\n <span class='${s.itemLabel}'>${item.label}</span>\n ${item.status ? `<span class='${s.itemStatus}'>${item.status}</span>` : ''}\n <div class='${s.itemActions}'>\n <button class='${s.itemActionButton}'>${icons.settings}</button>\n </div>\n </div>\n `\n }\n\n const renderSection = (section: SidebarSectionData): string => {\n return `\n <div class='${s.section}'>\n ${section.title ? `\n <div class=\"${section.collapsible ? s.sectionHeaderClickable : s.sectionHeader}\" data-section=\"${section.id}\">\n <span>${section.title}</span>\n ${section.items.length > 0 ? `<span class=\"${s.sectionCount}\">${section.items.length}</span>` : ''}\n </div>\n ` : ''}\n ${!section.collapsed ? section.items.map(item => renderItem(item)).join('') : ''}\n </div>\n `\n }\n\n const renderGroup = (item: SidebarItemData): string => {\n const chevronClass = item.expanded ? s.groupChevronExpanded : s.groupChevron\n return `\n <div class='${s.group}'>\n <div class='${s.groupHeader}' data-group='${item.id}'>\n <span class='${chevronClass}'>${icons.chevronRight}</span>\n <span class='${s.itemIcon}'>${getIcon(item.icon || 'folder')}</span>\n <span class='${s.itemLabel}'>${item.label}</span>\n </div>\n ${item.expanded && item.children ? `\n <div class='${s.groupContent}'>\n ${item.children.map(child => renderItem(child)).join('')}\n </div>\n ` : ''}\n </div>\n `\n }\n\n return `\n <div class='${s.sidebar}'>\n <div class='${s.header}'>\n <span class='${s.headerTitle}'>${data.header?.title || 'OrbStack'}</span>\n <button class='${s.headerAction}'>${icons.plus}</button>\n </div>\n\n <div class='${s.content}'>\n ${data.sections ? data.sections.map(section => renderSection(section)).join('') : ''}\n ${data.items ? data.items.map(item =>\n item.children ? renderGroup(item) : renderItem(item)\n ).join('') : ''}\n </div>\n\n <div class='${s.footer}'>\n <span class='${s.footerText}'>v4.0.0</span>\n <button class='${s.footerButton}'>${icons.settings}</button>\n </div>\n </div>\n `\n}\n\n// ============================================================================\n// Demo Data\n// ============================================================================\n\nexport const tahoeDemoData: SidebarData = {\n header: {\n title: 'MacBook Pro',\n subtitle: '256 GB available',\n avatar: '💻',\n },\n showSearch: true,\n searchPlaceholder: 'Search',\n sections: [\n {\n id: 'favorites',\n title: 'Favorites',\n collapsible: true,\n items: [\n { id: 'airdrop', label: 'AirDrop', icon: 'cloud' },\n { id: 'recents', label: 'Recents', icon: 'document', badge: 12 },\n { id: 'applications', label: 'Applications', icon: 'folder' },\n { id: 'desktop', label: 'Desktop', icon: 'home', selected: true },\n { id: 'documents', label: 'Documents', icon: 'folder' },\n { id: 'downloads', label: 'Downloads', icon: 'download', badge: 3 },\n ],\n },\n {\n id: 'icloud',\n title: 'iCloud',\n collapsible: true,\n items: [\n { id: 'icloud-drive', label: 'iCloud Drive', icon: 'cloud' },\n { id: 'shared', label: 'Shared', icon: 'folder' },\n ],\n },\n {\n id: 'tags',\n title: 'Tags',\n collapsible: true,\n collapsed: true,\n items: [\n { id: 'red', label: 'Red' },\n { id: 'orange', label: 'Orange' },\n ],\n },\n ],\n footer: {\n items: [\n { id: 'settings', label: 'Settings', icon: 'settings' },\n ],\n },\n}\n\nexport const arcDemoData: SidebarData = {\n sections: [\n {\n id: 'pinned',\n title: 'Pinned',\n items: [\n { id: 'github', label: 'GitHub', icon: 'document', selected: true },\n { id: 'twitter', label: 'Twitter', icon: 'document' },\n { id: 'figma', label: 'Figma', icon: 'document' },\n ],\n },\n {\n id: 'work',\n title: 'Work',\n items: [\n { id: 'slack', label: 'Slack - Acme Inc', icon: 'document' },\n { id: 'notion', label: 'Notion', icon: 'document' },\n { id: 'linear', label: 'Linear', icon: 'document' },\n ],\n },\n {\n id: 'personal',\n title: 'Personal',\n items: [\n { id: 'youtube', label: 'YouTube', icon: 'document' },\n { id: 'spotify', label: 'Spotify', icon: 'document' },\n ],\n },\n ],\n}\n\nexport const orbstackDemoData: SidebarData = {\n header: {\n title: 'OrbStack',\n },\n sections: [\n {\n id: 'machines',\n title: 'Machines',\n items: [\n { id: 'ubuntu', label: 'ubuntu', icon: 'linux', status: 'running', selected: true },\n { id: 'fedora', label: 'fedora', icon: 'linux', status: 'stopped' },\n { id: 'alpine', label: 'alpine', icon: 'linux', status: 'stopped' },\n ],\n },\n {\n id: 'containers',\n title: 'Containers',\n items: [\n { id: 'postgres', label: 'postgres:15', icon: 'container', status: 'running' },\n { id: 'redis', label: 'redis:7', icon: 'container', status: 'running' },\n { id: 'nginx', label: 'nginx:latest', icon: 'container', status: 'stopped' },\n ],\n },\n ],\n}\n\n// ============================================================================\n// Full Page Templates (for quick testing)\n// ============================================================================\n\nexport function getFullPageHTML(sidebarHTML: string, style: 'tahoe' | 'arc' | 'orbstack'): string {\n const bgClass = style === 'orbstack'\n ? 'bg-[#0f0f0f]'\n : 'bg-neutral-50 dark:bg-neutral-900'\n\n return `\n<!DOCTYPE html>\n<html lang=\"en\" class=\"${style === 'orbstack' ? 'dark' : ''}\">\n<head>\n <meta charset='UTF-8'>\n <meta name='viewport' content='width=device-width, initial-scale=1.0'>\n <title>Craft Sidebar - ${style}</title>\n <script src='https://cdn.tailwindcss.com'></script>\n <style>\n /* Custom scrollbar */\n .scrollbar-thin::-webkit-scrollbar { width: 6px; }\n .scrollbar-thin::-webkit-scrollbar-track { background: transparent; }\n .scrollbar-thin::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.1); border-radius: 3px; }\n .dark .scrollbar-thin::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); }\n .scrollbar-none::-webkit-scrollbar { display: none; }\n\n /* Backdrop blur fallback */\n @supports not (backdrop-filter: blur(1px)) {\n .backdrop-blur-xl { background: rgba(255,255,255,0.95); }\n .dark .backdrop-blur-xl { background: rgba(30,30,30,0.95); }\n }\n </style>\n</head>\n<body class='flex min-h-screen ${bgClass}'>\n ${sidebarHTML}\n <div class='flex-1 p-8'>\n <div class='text-neutral-400 dark:text-neutral-500'>\n Content area - select items in the sidebar\n </div>\n </div>\n <script>\n // Add click handlers\n document.querySelectorAll('[data-id]').forEach(el => {\n el.addEventListener('click', () => {\n console.log('Selected:', el.dataset.id);\n // You would update selection state here\n });\n });\n </script>\n</body>\n</html>\n`\n}\n\n// ============================================================================\n// Export\n// ============================================================================\n\nconst _exports: {\n renderTahoeSidebar: typeof renderTahoeSidebar;\n renderArcSidebar: typeof renderArcSidebar;\n renderOrbStackSidebar: typeof renderOrbStackSidebar;\n tahoeDemoData: typeof tahoeDemoData;\n arcDemoData: typeof arcDemoData;\n orbstackDemoData: typeof orbstackDemoData;\n getFullPageHTML: typeof getFullPageHTML;\n icons: typeof icons;\n} = {\n renderTahoeSidebar,\n renderArcSidebar,\n renderOrbStackSidebar,\n tahoeDemoData,\n arcDemoData,\n orbstackDemoData,\n getFullPageHTML,\n icons,\n};\nexport default _exports;\n",
|
|
38
|
+
"/**\n * Craft Styles\n * CSS/Tailwind utilities and pre-built component styles\n * @module @craft-native/styles\n */\n\n// Headwind (Tailwind-compatible) utilities\nexport {\n tw,\n cx,\n variants,\n style,\n generateConfig,\n buildCSS\n} from './headwind'\nexport type {\n ClassValue,\n VariantConfig,\n HeadwindConfig\n} from './headwind'\n\n// Sidebar styles (Tahoe, Arc, OrbStack)\nexport {\n tahoeStyles,\n arcStyles,\n orbstackStyles,\n sidebarUtils,\n sidebarCSSVariables,\n getSidebarStyle\n} from './sidebars'\n\n// Sidebar HTML templates\nexport {\n renderTahoeSidebar,\n renderArcSidebar,\n renderOrbStackSidebar,\n tahoeDemoData,\n arcDemoData,\n orbstackDemoData,\n getFullPageHTML\n} from './sidebar-templates'\nexport type {\n SidebarItemData,\n SidebarSectionData,\n SidebarData\n} from './sidebar-templates'\n\n// Re-export cx as clsx alias for familiarity\nexport { cx as clsx } from './headwind'\n\n// Re-export sidebar defaults\nimport { tahoeStyles, arcStyles, orbstackStyles } from './sidebars'\nimport { renderTahoeSidebar, renderArcSidebar, renderOrbStackSidebar } from './sidebar-templates'\nimport { tw, cx, variants } from './headwind'\n\nexport const styles: {\n tw: typeof tw;\n cx: typeof cx;\n variants: typeof variants;\n sidebar: {\n tahoe: typeof tahoeStyles;\n arc: typeof arcStyles;\n orbstack: typeof orbstackStyles;\n };\n templates: {\n tahoe: typeof renderTahoeSidebar;\n arc: typeof renderArcSidebar;\n orbstack: typeof renderOrbStackSidebar;\n };\n} = {\n // Headwind utilities\n tw,\n cx,\n variants,\n\n // Sidebar style objects\n sidebar: {\n tahoe: tahoeStyles,\n arc: arcStyles,\n orbstack: orbstackStyles,\n },\n\n // HTML template renderers\n templates: {\n tahoe: renderTahoeSidebar,\n arc: renderArcSidebar,\n orbstack: renderOrbStackSidebar,\n }\n}\n\nexport default styles\n",
|
|
39
|
+
"/**\n * Framework-Specific Optimizations\n *\n * Performance optimizations for React, Vue, and Svelte.\n * These utilities are framework-agnostic at the core level\n * and integrate with specific frameworks when available.\n */\n\n// ============================================================================\n// React Optimizations\n// ============================================================================\n\n/**\n * Configuration for React-specific optimizations\n */\nexport interface ReactOptimizationConfig {\n /** Enable React DevTools in development */\n enableDevTools?: boolean\n /** Enable React Profiler */\n enableProfiler?: boolean\n /** Enable strict mode warnings */\n strictMode?: boolean\n /** Enable concurrent features */\n concurrent?: boolean\n /** Lazy loading chunk size limit in KB */\n lazyChunkLimit?: number\n /** Enable automatic batching */\n autoBatching?: boolean\n}\n\n/**\n * React optimization utilities\n *\n * Note: These functions require React to be installed in your project.\n * They gracefully handle cases where React is not available.\n */\nexport const reactOptimizations = {\n /**\n * Configure React for production\n */\n configureProduction(config: ReactOptimizationConfig = {}): void {\n if (typeof window !== 'undefined') {\n // Disable React DevTools in production\n if (!config.enableDevTools) {\n (window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__ = { isDisabled: true }\n }\n }\n },\n\n /**\n * Create a lazy component factory function\n * Returns a function that creates lazy components when React is available\n */\n createLazyFactory(): <T>(\n factory: () => Promise<{ default: T }>,\n options?: { preload?: boolean }\n ) => { load: () => Promise<void> } {\n return <T>(\n factory: () => Promise<{ default: T }>,\n options: { preload?: boolean } = {}\n ) => {\n let componentPromise: Promise<{ default: T }> | null = null\n\n const load = async () => {\n if (!componentPromise) {\n componentPromise = factory()\n }\n await componentPromise\n }\n\n // Auto-preload if enabled\n if (options.preload) {\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(() => load())\n }\nelse {\n setTimeout(() => load(), 0)\n }\n }\n\n return { load }\n }\n },\n\n /**\n * Create a debounce hook factory\n */\n createDebouncedValueHook<T>(delay: number): (value: T) => T {\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n let debouncedValue: T\n\n return (value: T): T => {\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n\n timeoutId = setTimeout(() => {\n debouncedValue = value\n timeoutId = null\n }, delay)\n\n return debouncedValue ?? value\n }\n },\n\n /**\n * Create a throttle function\n */\n createThrottle<T extends (...args: any[]) => any>(\n fn: T,\n delay: number\n ): T {\n let lastRan = 0\n\n return ((...args: Parameters<T>) => {\n const now = Date.now()\n if (now - lastRan >= delay) {\n fn(...args)\n lastRan = now\n }\n }) as T\n }\n}\n\n// ============================================================================\n// Vue Optimizations\n// ============================================================================\n\n/**\n * Configuration for Vue-specific optimizations\n */\nexport interface VueOptimizationConfig {\n /** Enable Vue DevTools in development */\n enableDevTools?: boolean\n /** Enable performance tracing */\n performance?: boolean\n /** Custom error handler */\n errorHandler?: (err: Error, vm: any, info: string) => void\n /** Custom warn handler */\n warnHandler?: (msg: string, vm: any, trace: string) => void\n}\n\n/**\n * Vue optimization utilities\n *\n * Note: These functions require Vue to be installed in your project.\n */\nexport const vueOptimizations = {\n /**\n * Configure Vue app for production\n */\n configureProduction(app: any, config: VueOptimizationConfig = {}): void {\n if (!app?.config) return\n\n // Disable devtools in production\n if (!config.enableDevTools && app.config.devtools !== undefined) {\n app.config.devtools = false\n }\n\n // Enable performance tracing if configured\n if (app.config.performance !== undefined) {\n app.config.performance = config.performance || false\n }\n\n // Set custom error handler\n if (config.errorHandler) {\n app.config.errorHandler = config.errorHandler\n }\n\n // Set custom warn handler\n if (config.warnHandler) {\n app.config.warnHandler = config.warnHandler\n }\n },\n\n /**\n * Create an async component loader configuration\n */\n createAsyncConfig(options: {\n delay?: number\n timeout?: number\n retries?: number\n } = {}): {\n delay: number\n timeout: number\n onError: (error: Error, retry: () => void, fail: () => void, attempts: number) => void\n } {\n const { delay = 200, timeout = 30000, retries = 3 } = options\n\n return {\n delay,\n timeout,\n onError(error: Error, retry: () => void, fail: () => void, attempts: number) {\n if (attempts <= retries) {\n retry()\n }\nelse {\n fail()\n }\n }\n }\n },\n\n /**\n * Create a cached computed factory.\n *\n * - `maxAge`: discard entries older than `maxAge` ms (0 = forever).\n * - `maxEntries`: hard cap on the number of cached entries (default\n * 1000). Once exceeded, the least-recently-used entry is evicted.\n * This prevents the unbounded growth that the previous version\n * exhibited — calling `get(uniqueKey, …)` in a loop with `maxAge=0`\n * would leak indefinitely.\n *\n * LRU is implemented via the `Map` insertion-order property: on hit,\n * we re-insert the entry to move it to the tail; on insert, the head\n * (`cache.keys().next().value`) is the LRU.\n */\n createCacheFactory<T>(options: { maxAge?: number; maxEntries?: number } = {}): {\n cache: Map<string, { value: T; timestamp: number }>\n get: (key: string, getter: () => T) => T\n invalidate: (key?: string) => void\n } {\n const { maxAge = 0, maxEntries = 1000 } = options\n if (!Number.isInteger(maxEntries) || maxEntries < 1) {\n throw new Error(`createCacheFactory: maxEntries must be a positive integer (got ${maxEntries})`)\n }\n const cache = new Map<string, { value: T; timestamp: number }>()\n\n return {\n cache,\n get(key: string, getter: () => T): T {\n const now = Date.now()\n const cached = cache.get(key)\n\n if (cached && (maxAge === 0 || now - cached.timestamp < maxAge)) {\n // Move to MRU position by deleting + reinserting.\n cache.delete(key)\n cache.set(key, cached)\n return cached.value\n }\n\n const value = getter()\n cache.set(key, { value, timestamp: now })\n // Evict LRU entries until we're back under the cap.\n while (cache.size > maxEntries) {\n const lruKey = cache.keys().next().value\n if (lruKey === undefined) break\n cache.delete(lruKey)\n }\n return value\n },\n invalidate(key?: string) {\n if (key) {\n cache.delete(key)\n }\nelse {\n cache.clear()\n }\n },\n }\n }\n}\n\n// ============================================================================\n// Svelte Optimizations\n// ============================================================================\n\n/**\n * Configuration for Svelte-specific optimizations\n */\nexport interface SvelteOptimizationConfig {\n /** Enable dev mode */\n dev?: boolean\n /** Enable CSS optimization */\n cssOptimization?: boolean\n /** Hydration strategy */\n hydration?: 'full' | 'partial' | 'none'\n}\n\n/**\n * Svelte optimization utilities\n *\n * Note: These functions require Svelte to be installed in your project.\n */\nexport const svelteOptimizations = {\n /**\n * Create a memoization wrapper for derived values\n */\n createMemoizer<T, U>(\n fn: (value: T) => U,\n isEqual?: (a: U, b: U) => boolean\n ): (value: T) => U {\n let lastInput: T | undefined\n let lastOutput: U | undefined\n\n return (value: T): U => {\n if (lastInput !== undefined && lastInput === value && lastOutput !== undefined) {\n return lastOutput\n }\n\n const newOutput = fn(value)\n\n if (lastOutput !== undefined && isEqual && isEqual(lastOutput, newOutput)) {\n return lastOutput\n }\n\n lastInput = value\n lastOutput = newOutput\n return newOutput\n }\n },\n\n /**\n * Create a debounced setter\n */\n createDebouncedSetter<T>(delay: number = 300): {\n set: (value: T, callback: (value: T) => void) => void\n cancel: () => void\n } {\n let timeout: ReturnType<typeof setTimeout> | undefined\n\n return {\n set(value: T, callback: (value: T) => void) {\n if (timeout) {\n clearTimeout(timeout)\n }\n timeout = setTimeout(() => {\n callback(value)\n timeout = undefined\n }, delay)\n },\n cancel() {\n if (timeout) {\n clearTimeout(timeout)\n timeout = undefined\n }\n }\n }\n },\n\n /**\n * Create a throttled setter\n */\n createThrottledSetter<T>(delay: number = 100): {\n set: (value: T, callback: (value: T) => void) => void\n } {\n let lastRan = 0\n let pending: { value: T; callback: (value: T) => void } | undefined\n let timeout: ReturnType<typeof setTimeout> | undefined\n\n return {\n set(value: T, callback: (value: T) => void) {\n const now = Date.now()\n\n if (now - lastRan >= delay) {\n callback(value)\n lastRan = now\n }\nelse {\n pending = { value, callback }\n\n if (!timeout) {\n timeout = setTimeout(() => {\n if (pending) {\n pending.callback(pending.value)\n pending = undefined\n }\n lastRan = Date.now()\n timeout = undefined\n }, delay - (now - lastRan))\n }\n }\n }\n }\n },\n\n /**\n * Create an intersection observer action config\n */\n createLazyActionConfig(options: {\n threshold?: number\n rootMargin?: string\n } = {}): IntersectionObserverInit {\n return {\n threshold: options.threshold ?? 0,\n rootMargin: options.rootMargin ?? '50px'\n }\n },\n\n /**\n * Create transition configuration with hardware acceleration hints\n */\n createAcceleratedTransitionConfig(\n type: 'fade' | 'slide' | 'scale',\n options: { duration?: number; easing?: string } = {}\n ): {\n type: string\n duration: number\n easing: string\n willChange: string\n } {\n const { duration = 300, easing = 'cubic-bezier(0.4, 0, 0.2, 1)' } = options\n\n const willChangeMap = {\n fade: 'opacity',\n slide: 'transform, opacity',\n scale: 'transform, opacity'\n }\n\n return {\n type,\n duration,\n easing,\n willChange: willChangeMap[type]\n }\n }\n}\n\n// ============================================================================\n// Common Optimizations\n// ============================================================================\n\n/**\n * Common optimization utilities for all frameworks\n */\nexport const commonOptimizations = {\n /**\n * Defer non-critical JavaScript execution\n */\n defer(fn: () => void): void {\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(fn)\n }\nelse {\n setTimeout(fn, 0)\n }\n },\n\n /**\n * Preload critical resources\n */\n preload(urls: string[], type: 'script' | 'style' | 'image' | 'font'): void {\n if (typeof document === 'undefined') return\n\n urls.forEach((url) => {\n const link = document.createElement('link')\n link.rel = 'preload'\n link.href = url\n link.as = type\n\n if (type === 'font') {\n link.crossOrigin = 'anonymous'\n }\n\n document.head.appendChild(link)\n })\n },\n\n /**\n * Prefetch resources for future navigation\n */\n prefetch(urls: string[]): void {\n if (typeof document === 'undefined') return\n\n urls.forEach((url) => {\n const link = document.createElement('link')\n link.rel = 'prefetch'\n link.href = url\n document.head.appendChild(link)\n })\n },\n\n /**\n * Create an intersection observer for lazy loading\n */\n createLazyLoader(\n callback: (entry: IntersectionObserverEntry) => void,\n options: IntersectionObserverInit = {}\n ): IntersectionObserver | null {\n if (typeof IntersectionObserver === 'undefined') {\n return null\n }\n\n return new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n callback(entry)\n }\n })\n }, {\n rootMargin: '50px',\n threshold: 0,\n ...options\n })\n },\n\n /**\n * Measure component render time\n */\n measureRender(name: string): { start: () => void; end: () => void } {\n let startTime: number\n\n return {\n start() {\n if (typeof performance !== 'undefined') {\n startTime = performance.now()\n performance.mark(`${name}-start`)\n }\n },\n end() {\n if (typeof performance !== 'undefined' && startTime) {\n const endTime = performance.now()\n performance.mark(`${name}-end`)\n performance.measure(name, `${name}-start`, `${name}-end`)\n\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') {\n console.log(`[Craft] ${name} rendered in ${(endTime - startTime).toFixed(2)}ms`)\n }\n }\n }\n }\n },\n\n /**\n * Create a memoized function\n */\n memoize<T extends (...args: any[]) => any>(\n fn: T,\n options: {\n maxSize?: number\n ttl?: number\n } = {}\n ): T {\n const { maxSize = 100, ttl = 0 } = options\n\n const cache = new Map<string, { value: ReturnType<T>; timestamp: number }>()\n const keys: string[] = []\n\n return ((...args: Parameters<T>) => {\n const key = JSON.stringify(args)\n const now = Date.now()\n\n const cached = cache.get(key)\n if (cached) {\n if (ttl === 0 || now - cached.timestamp < ttl) {\n return cached.value\n }\n cache.delete(key)\n keys.splice(keys.indexOf(key), 1)\n }\n\n const value = fn(...args)\n\n cache.set(key, { value, timestamp: now })\n keys.push(key)\n\n // Evict oldest entries if over max size\n while (keys.length > maxSize) {\n const oldKey = keys.shift()!\n cache.delete(oldKey)\n }\n\n return value\n }) as T\n },\n\n /**\n * Batch DOM updates using requestAnimationFrame\n */\n batchDOMUpdates(updates: Array<() => void>): void {\n if (typeof requestAnimationFrame !== 'undefined') {\n requestAnimationFrame(() => {\n updates.forEach((update) => update())\n })\n }\nelse {\n updates.forEach((update) => update())\n }\n },\n\n /**\n * Create a debounce function\n */\n debounce<T extends (...args: any[]) => any>(\n fn: T,\n delay: number\n ): T & { cancel: () => void } {\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n\n const debounced = ((...args: Parameters<T>) => {\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n timeoutId = setTimeout(() => {\n fn(...args)\n timeoutId = undefined\n }, delay)\n }) as T & { cancel: () => void }\n\n debounced.cancel = () => {\n if (timeoutId) {\n clearTimeout(timeoutId)\n timeoutId = undefined\n }\n }\n\n return debounced\n },\n\n /**\n * Create a throttle function\n */\n throttle<T extends (...args: any[]) => any>(\n fn: T,\n delay: number\n ): T {\n let lastRan = 0\n\n return ((...args: Parameters<T>) => {\n const now = Date.now()\n if (now - lastRan >= delay) {\n fn(...args)\n lastRan = now\n }\n }) as T\n },\n\n /**\n * Detect if running in a low-power mode or reduced motion preference\n */\n detectReducedMotion(): boolean {\n if (typeof window === 'undefined') return false\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n },\n\n /**\n * Detect if running on a low-end device\n */\n detectLowEndDevice(): boolean {\n if (typeof navigator === 'undefined') return false\n\n // Check for limited memory (< 4GB)\n const memory = (navigator as any).deviceMemory\n if (memory && memory < 4) return true\n\n // Check for limited CPU cores (< 4)\n const cores = navigator.hardwareConcurrency\n if (cores && cores < 4) return true\n\n // Check for save-data header preference\n const connection = (navigator as any).connection\n if (connection?.saveData) return true\n\n return false\n },\n\n /**\n * Create an adaptive quality level based on device capabilities\n */\n getAdaptiveQuality(): 'low' | 'medium' | 'high' {\n const isLowEnd = commonOptimizations.detectLowEndDevice()\n const prefersReducedMotion = commonOptimizations.detectReducedMotion()\n\n if (isLowEnd || prefersReducedMotion) return 'low'\n\n // Check for high refresh rate display\n if (typeof window !== 'undefined') {\n const dpr = window.devicePixelRatio || 1\n if (dpr >= 2) return 'high'\n }\n\n return 'medium'\n }\n}\n",
|
|
40
|
+
"/**\n * Craft Auto-Updater\n * Automatic updates with delta/differential update support\n */\n\nimport { createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from 'fs'\nimport { join, basename, dirname } from 'path'\nimport { execFileSync, spawn } from 'child_process'\nimport { createHash } from 'crypto'\nimport { pipeline } from 'stream/promises'\nimport { EventEmitter } from 'events'\n\n// Types\nexport interface UpdateInfo {\n version: string\n releaseDate: string\n releaseNotes?: string\n mandatory?: boolean\n minVersion?: string\n platforms: {\n [platform: string]: PlatformUpdate\n }\n}\n\nexport interface PlatformUpdate {\n url: string\n size: number\n sha256: string\n signature?: string\n delta?: DeltaUpdate[]\n}\n\nexport interface DeltaUpdate {\n fromVersion: string\n url: string\n size: number\n sha256: string\n}\n\nexport interface UpdaterConfig {\n /**\n * Manifest URL. Must be HTTPS in production (file:// is allowed for tests).\n * The constructor will throw on a plain `http://` URL.\n */\n updateUrl: string\n currentVersion: string\n appPath: string // Path to app bundle\n autoDownload?: boolean\n autoInstall?: boolean\n channel?: 'stable' | 'beta' | 'alpha'\n checkInterval?: number // ms\n /**\n * PEM-encoded public key (SPKI / RFC 5280) used to verify update bundle\n * signatures. When omitted, signed updates from the manifest are still\n * verified by SHA-256 hash but the signature field is rejected as\n * unverifiable (the updater refuses to install rather than fall back to\n * \"trust on first use\"). For ed25519 keys, supply the standard\n * `-----BEGIN PUBLIC KEY-----` PEM.\n */\n publicKeyPem?: string\n /**\n * Signature scheme used to sign manifest entries. Defaults to `'ed25519'`.\n * Must match how the build pipeline produced `PlatformUpdate.signature`.\n */\n signatureAlgorithm?: 'ed25519' | 'rsa-sha256'\n}\n\nexport interface UpdateProgress {\n phase: 'checking' | 'downloading' | 'extracting' | 'installing' | 'done' | 'error'\n percent: number\n bytesDownloaded?: number\n bytesTotal?: number\n speed?: number // bytes/sec\n}\n\nexport type UpdaterEvent =\n | 'checking-for-update'\n | 'update-available'\n | 'update-not-available'\n | 'download-progress'\n | 'update-downloaded'\n | 'before-quit-for-update'\n | 'error'\n\n/**\n * Run `find <root> -name <pattern> -type <kind> -print0` and return the\n * first match. Splitting on `\\0` is required because macOS/Linux paths\n * can legally contain newlines — splitting on `\\n` (the previous\n * implementation) corrupted those paths. Returns `''` when no match.\n */\nfunction findFirstByName(root: string, namePattern: string, kind: 'd' | 'f'): string {\n const out = execFileSync('find', [root, '-name', namePattern, '-type', kind, '-print0'])\n const nullByte = String.fromCharCode(0)\n const parts = out.toString('utf-8').split(nullByte).filter(s => s.length > 0)\n return parts[0] ?? ''\n}\n\n// Auto Updater\nexport class AutoUpdater extends EventEmitter {\n private config: UpdaterConfig\n private updateInfo: UpdateInfo | null = null\n private downloadPath: string | null = null\n private checkTimer: NodeJS.Timeout | null = null\n // Conditional-GET cache so repeat checks against the manifest server\n // return 304 instead of a full body. Cleared when the URL changes.\n private cachedEtag: string | null = null\n private cachedLastModified: string | null = null\n private cachedManifest: UpdateInfo | null = null\n\n private emitError(error: unknown): void {\n if (this.listenerCount('error') > 0) this.emit('error', error)\n else console.error('[Updater]', error)\n }\n\n constructor(config: UpdaterConfig) {\n super()\n\n // Refuse insecure manifest URLs at construction time so a typo can't\n // ship an HTTP-fetched manifest (which would defeat the signature\n // scheme by letting MITM rewrite it). file:// is allowed for tests.\n const url = config.updateUrl\n if (typeof url !== 'string' || url.length === 0) {\n throw new Error('Updater: updateUrl is required')\n }\n if (!/^(?:https:|file:)\\/\\//i.test(url)) {\n throw new Error(`Updater: updateUrl must use https:// (got: ${url})`)\n }\n\n this.config = {\n autoDownload: true,\n autoInstall: false,\n channel: 'stable',\n checkInterval: 60 * 60 * 1000, // 1 hour\n ...config,\n }\n }\n\n /**\n * Start automatic update checking\n */\n startAutoCheck(): void {\n this.checkForUpdates()\n\n if (this.config.checkInterval) {\n this.checkTimer = setInterval(() => {\n this.checkForUpdates()\n }, this.config.checkInterval)\n }\n }\n\n /**\n * Stop automatic update checking\n */\n stopAutoCheck(): void {\n if (this.checkTimer) {\n clearInterval(this.checkTimer)\n this.checkTimer = null\n }\n }\n\n /**\n * Check for available updates\n */\n async checkForUpdates(): Promise<UpdateInfo | null> {\n this.emit('checking-for-update')\n\n try {\n const platform = this.getPlatform()\n const url = `${this.config.updateUrl}?v=${this.config.currentVersion}&channel=${this.config.channel}&platform=${platform}`\n\n const headers: Record<string, string> = {}\n if (this.cachedEtag) headers['If-None-Match'] = this.cachedEtag\n if (this.cachedLastModified) headers['If-Modified-Since'] = this.cachedLastModified\n\n const response = await fetch(url, { headers })\n\n // 304 Not Modified — reuse the prior manifest. If the cached entry\n // already announces a newer version that the user hasn't acted on\n // yet (e.g. they dismissed the banner), re-emit `update-available`\n // so dismissed-but-still-relevant updates resurface on the next\n // poll instead of becoming silently invisible after the first 200.\n if (response.status === 304 && this.cachedManifest) {\n if (this.isNewerVersion(this.cachedManifest.version, this.config.currentVersion)) {\n this.updateInfo = this.cachedManifest\n this.emit('update-available', this.cachedManifest)\n return this.cachedManifest\n }\n this.emit('update-not-available')\n return null\n }\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`)\n }\n\n const updateInfo = await response.json() as UpdateInfo\n // Capture validators for the next check. response.headers.get is\n // case-insensitive per the Fetch spec.\n this.cachedEtag = response.headers.get('etag') || null\n this.cachedLastModified = response.headers.get('last-modified') || null\n this.cachedManifest = updateInfo\n\n if (this.isNewerVersion(updateInfo.version, this.config.currentVersion)) {\n // Check minimum version requirement\n if (updateInfo.minVersion && this.isNewerVersion(updateInfo.minVersion, this.config.currentVersion)) {\n console.log(`Update requires minimum version ${updateInfo.minVersion}`)\n }\n\n this.updateInfo = updateInfo\n this.emit('update-available', updateInfo)\n\n if (this.config.autoDownload) {\n await this.downloadUpdate()\n }\n\n return updateInfo\n }\nelse {\n this.emit('update-not-available')\n return null\n }\n }\ncatch (error) {\n this.emitError(error)\n return null\n }\n }\n\n /**\n * Download the update\n */\n async downloadUpdate(): Promise<string | null> {\n if (!this.updateInfo) {\n throw new Error('No update available')\n }\n\n const platform = this.getPlatform()\n const platformUpdate = this.updateInfo.platforms[platform]\n\n if (!platformUpdate) {\n throw new Error(`No update available for platform: ${platform}`)\n }\n\n // Check for delta update\n const deltaUpdate = platformUpdate.delta?.find(\n (d) => d.fromVersion === this.config.currentVersion\n )\n\n const _updateSource = deltaUpdate || platformUpdate\n const url = deltaUpdate?.url || platformUpdate.url\n const expectedSize = deltaUpdate?.size || platformUpdate.size\n const expectedHash = deltaUpdate?.sha256 || platformUpdate.sha256\n\n // Create download directory\n const downloadDir = join(this.config.appPath, '..', '.craft-updates')\n mkdirSync(downloadDir, { recursive: true })\n\n const fileName = basename(url)\n this.downloadPath = join(downloadDir, fileName)\n\n // Download with progress\n try {\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Download failed: HTTP ${response.status}`)\n }\n\n const contentLength = parseInt(response.headers.get('content-length') || '0', 10)\n const total = contentLength || expectedSize\n\n let downloaded = 0\n const startTime = Date.now()\n\n const fileStream = createWriteStream(this.downloadPath)\n const reader = response.body?.getReader()\n\n if (!reader) {\n throw new Error('Failed to get response reader')\n }\n\n while (true) {\n const { done, value } = await reader.read()\n\n if (done) break\n\n fileStream.write(value)\n downloaded += value.length\n\n const elapsed = (Date.now() - startTime) / 1000\n const speed = downloaded / elapsed\n\n const progress: UpdateProgress = {\n phase: 'downloading',\n percent: Math.round((downloaded / total) * 100),\n bytesDownloaded: downloaded,\n bytesTotal: total,\n speed,\n }\n\n this.emit('download-progress', progress)\n }\n\n fileStream.end()\n await new Promise<void>((resolve, reject) => {\n fileStream.once('finish', resolve)\n fileStream.once('error', reject)\n })\n\n // Verify hash\n const hash = await this.computeFileHash(this.downloadPath)\n if (hash !== expectedHash) {\n unlinkSync(this.downloadPath)\n throw new Error('Download verification failed: hash mismatch')\n }\n\n // A delta is a patch, not an installable bundle. Reconstruct the full\n // update first, then verify it against the full manifest entry.\n if (deltaUpdate) {\n if (!statSync(this.config.appPath).isFile()) {\n throw new Error('Delta updates require appPath to point to the installed bundle file')\n }\n const patchPath = this.downloadPath\n const reconstructedPath = join(downloadDir, `reconstructed-${basename(platformUpdate.url)}`)\n await DeltaGenerator.apply(this.config.appPath, patchPath, reconstructedPath)\n const reconstructedHash = await this.computeFileHash(reconstructedPath)\n if (reconstructedHash !== platformUpdate.sha256) {\n try { unlinkSync(reconstructedPath) } catch { /* best effort */ }\n throw new Error('Delta reconstruction failed: full bundle hash mismatch')\n }\n unlinkSync(patchPath)\n this.downloadPath = reconstructedPath\n }\n\n // When a public key is configured, every update MUST carry a\n // signature — otherwise an attacker who controlled the manifest could\n // publish unsigned updates and bypass verification entirely.\n if (this.config.publicKeyPem && !platformUpdate.signature) {\n unlinkSync(this.downloadPath)\n throw new Error(\n 'Updater: publicKeyPem is configured but the manifest entry has no signature. '\n + 'Refusing to install unsigned update.',\n )\n }\n\n // Verify signature if available\n if (platformUpdate.signature) {\n const valid = await this.verifySignature(this.downloadPath, platformUpdate.signature)\n if (!valid) {\n unlinkSync(this.downloadPath)\n throw new Error('Download verification failed: invalid signature')\n }\n }\n\n this.emit('update-downloaded', {\n path: this.downloadPath,\n version: this.updateInfo.version,\n isDelta: !!deltaUpdate,\n })\n\n if (this.config.autoInstall) {\n await this.installUpdate()\n }\n\n return this.downloadPath\n }\ncatch (error) {\n this.emitError(error)\n return null\n }\n }\n\n /**\n * Install the downloaded update.\n *\n * Re-verifies SHA-256 (and signature, if a public key is configured)\n * against the manifest entry immediately before invoking the privileged\n * installer. This is belt-and-suspenders insurance: `download()` already\n * verifies, but `installUpdate()` is a public method, the file lives on\n * disk between download and install, and a privileged installer\n * touching attacker-tampered bytes is the kind of mistake that turns\n * into a CVE.\n */\n async installUpdate(restartAfter = true): Promise<void> {\n if (!this.downloadPath || !existsSync(this.downloadPath)) {\n throw new Error('No update downloaded')\n }\n\n if (this.updateInfo) {\n const platform = this.getPlatform()\n const platformUpdate = this.updateInfo.platforms[platform]\n if (platformUpdate) {\n const hash = await this.computeFileHash(this.downloadPath)\n if (hash !== platformUpdate.sha256) {\n // Treat the local copy as compromised — drop it so a retry\n // forces a fresh download from the manifest URL.\n try { unlinkSync(this.downloadPath) } catch { /* best effort */ }\n throw new Error(\n `Updater.installUpdate: pre-install hash mismatch on ${this.downloadPath}. `\n + 'The downloaded bundle changed between download and install — refusing to run installer.',\n )\n }\n if (this.config.publicKeyPem && !platformUpdate.signature) {\n throw new Error(\n 'Updater.installUpdate: publicKeyPem is configured but manifest has no signature. '\n + 'Refusing to install unsigned update.',\n )\n }\n if (platformUpdate.signature) {\n const valid = await this.verifySignature(this.downloadPath, platformUpdate.signature)\n if (!valid) {\n try { unlinkSync(this.downloadPath) } catch { /* best effort */ }\n throw new Error('Updater.installUpdate: invalid signature on downloaded bundle')\n }\n }\n }\n }\n\n this.emit('before-quit-for-update')\n\n const platform = this.getPlatform()\n\n // Extract/install update\n const progress: UpdateProgress = { phase: 'installing', percent: 0 }\n this.emit('download-progress', progress)\n\n try {\n switch (platform) {\n case 'darwin':\n await this.installMacOSUpdate()\n break\n case 'win32':\n await this.installWindowsUpdate()\n break\n case 'linux':\n await this.installLinuxUpdate()\n break\n }\n\n // Clean up download\n if (this.downloadPath && existsSync(this.downloadPath)) {\n unlinkSync(this.downloadPath)\n }\n\n progress.phase = 'done'\n progress.percent = 100\n this.emit('download-progress', progress)\n\n if (restartAfter) {\n this.restartApp()\n }\n }\ncatch (error) {\n progress.phase = 'error'\n this.emitError(error)\n throw error\n }\n }\n\n private async installMacOSUpdate(): Promise<void> {\n const downloadPath = this.downloadPath!\n const appPath = this.config.appPath\n\n // Determine update type by extension\n if (downloadPath.endsWith('.zip')) {\n // Extract zip to temp location\n const tempDir = join(dirname(downloadPath), 'extracted')\n mkdirSync(tempDir, { recursive: true })\n\n execFileSync('unzip', ['-o', downloadPath, '-d', tempDir])\n\n // Find the .app in extracted contents. `-print0` + null-byte split\n // is required because macOS allows newlines in path names; the\n // previous `\\n`-split parse silently truncated such paths.\n const extractedApp = findFirstByName(tempDir, '*.app', 'd')\n\n if (extractedApp) {\n // Replace current app\n const { rmSync, renameSync } = await import('fs')\n rmSync(appPath, { recursive: true, force: true })\n renameSync(extractedApp, appPath)\n }\n\n // Clean up\n const { rmSync } = await import('fs')\n rmSync(tempDir, { recursive: true, force: true })\n }\nelse if (downloadPath.endsWith('.dmg')) {\n // Mount DMG\n const mountOutput = execFileSync('hdiutil', ['attach', downloadPath, '-nobrowse']).toString()\n const mountPoint = mountOutput.match(/\\/Volumes\\/[^\\n]+/)?.[0]\n\n if (mountPoint) {\n // Find and copy the app\n const dmgApp = findFirstByName(mountPoint, '*.app', 'd')\n\n if (dmgApp) {\n const { rmSync, cpSync } = await import('fs')\n rmSync(appPath, { recursive: true, force: true })\n cpSync(dmgApp, appPath, { recursive: true })\n }\n\n // Unmount\n execFileSync('hdiutil', ['detach', mountPoint])\n }\n }\nelse if (downloadPath.endsWith('.pkg')) {\n // Verify the .pkg's embedded signing chain BEFORE handing it to\n // root. `pkgutil --check-signature` exits non-zero on an unsigned\n // or revoked package; a clean exit means the chain is trusted by\n // the system. This is independent of the SDK's own\n // sha256/manifest-signature check (which already ran in\n // `installUpdate`) — both layers must hold for us to call sudo.\n try {\n execFileSync('pkgutil', ['--check-signature', downloadPath], { stdio: 'pipe' })\n }\n catch (e) {\n throw new Error(\n `Refusing to install ${downloadPath}: pkgutil --check-signature failed. `\n + 'The .pkg is not signed by a trusted Apple certificate chain. '\n + `Underlying error: ${(e as Error).message}`,\n )\n }\n // Install package. `installer` requires root, which we delegate to sudo —\n // this will prompt the user via their sudo configuration (TouchID on macOS).\n execFileSync('sudo', ['installer', '-pkg', downloadPath, '-target', '/'])\n }\n }\n\n private async installWindowsUpdate(): Promise<void> {\n const downloadPath = this.downloadPath!\n\n if (downloadPath.endsWith('.exe')) {\n // Run installer silently\n spawn(downloadPath, ['/S', '/SILENT', '/VERYSILENT'], {\n detached: true,\n stdio: 'ignore',\n })\n }\nelse if (downloadPath.endsWith('.msi')) {\n // Run MSI installer\n spawn('msiexec', ['/i', downloadPath, '/quiet', '/norestart'], {\n detached: true,\n stdio: 'ignore',\n })\n }\nelse if (downloadPath.endsWith('.zip')) {\n // Extract and replace. Use -File to run a script block with safe args.\n const appDir = dirname(this.config.appPath)\n execFileSync('powershell', [\n '-NoProfile',\n '-NonInteractive',\n '-Command',\n 'Expand-Archive -Force -Path $env:CRAFT_UPDATE_SRC -DestinationPath $env:CRAFT_UPDATE_DST',\n ], {\n env: { ...process.env, CRAFT_UPDATE_SRC: downloadPath, CRAFT_UPDATE_DST: appDir },\n })\n }\n }\n\n private async installLinuxUpdate(): Promise<void> {\n const downloadPath = this.downloadPath!\n\n if (downloadPath.endsWith('.AppImage')) {\n // Replace AppImage\n execFileSync('chmod', ['+x', downloadPath])\n const { renameSync } = await import('fs')\n renameSync(downloadPath, this.config.appPath)\n }\nelse if (downloadPath.endsWith('.deb')) {\n execFileSync('sudo', ['dpkg', '-i', downloadPath])\n }\nelse if (downloadPath.endsWith('.rpm')) {\n execFileSync('sudo', ['rpm', '-U', downloadPath])\n }\nelse if (downloadPath.endsWith('.tar.gz')) {\n const appDir = dirname(this.config.appPath)\n execFileSync('tar', ['-xzf', downloadPath, '-C', appDir])\n }\n }\n\n private restartApp(): void {\n const platform = this.getPlatform()\n const appPath = this.config.appPath\n\n // Spawn new process and exit current\n switch (platform) {\n case 'darwin':\n spawn('open', ['-n', appPath], { detached: true, stdio: 'ignore' })\n break\n case 'win32':\n spawn(appPath, [], { detached: true, stdio: 'ignore' })\n break\n case 'linux':\n spawn(appPath, [], { detached: true, stdio: 'ignore' })\n break\n }\n\n process.exit(0)\n }\n\n private getPlatform(): string {\n switch (process.platform) {\n case 'darwin':\n return 'darwin'\n case 'win32':\n return 'win32'\n default:\n return 'linux'\n }\n }\n\n private isNewerVersion(a: string, b: string): boolean {\n const partsA = a.split('.').map(Number)\n const partsB = b.split('.').map(Number)\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 true\n if (numA < numB) return false\n }\n\n return false\n }\n\n private async computeFileHash(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash('sha256')\n const stream = createReadStream(filePath)\n\n stream.on('data', (chunk) => hash.update(chunk))\n stream.on('end', () => resolve(hash.digest('hex')))\n stream.on('error', reject)\n })\n }\n\n /**\n * Verify a downloaded bundle against the signature published in the\n * manifest. Returns false if the signature doesn't validate; throws when\n * the updater is misconfigured (no key or bad PEM) so misconfiguration\n * cannot silently pass as \"valid\".\n */\n private async verifySignature(filePath: string, signature: string): Promise<boolean> {\n const pem = this.config.publicKeyPem\n if (!pem) {\n throw new Error(\n 'Updater.verifySignature: publicKeyPem is not configured. '\n + 'Refusing to install signed update without a verification key.'\n )\n }\n\n const algo = this.config.signatureAlgorithm ?? 'ed25519'\n const { createPublicKey, verify, createVerify } = await import('node:crypto')\n\n let publicKey: ReturnType<typeof createPublicKey>\n try {\n publicKey = createPublicKey({ key: pem, format: 'pem' })\n }\n catch (e) {\n throw new Error(`Updater.verifySignature: invalid publicKeyPem: ${(e as Error).message}`)\n }\n\n // Signature is base64-encoded in the manifest.\n let sigBytes: Buffer\n try {\n sigBytes = Buffer.from(signature, 'base64')\n }\n catch {\n return false\n }\n\n const data = readFileSync(filePath)\n\n if (algo === 'ed25519') {\n // ed25519 uses the one-shot `verify` (no createVerify hashing step).\n return verify(null, data, publicKey, sigBytes)\n }\n\n // rsa-sha256\n const verifier = createVerify('SHA256')\n verifier.update(data)\n verifier.end()\n return verifier.verify(publicKey, sigBytes)\n }\n\n /**\n * Get current update info\n */\n getUpdateInfo(): UpdateInfo | null {\n return this.updateInfo\n }\n\n /**\n * Get download path\n */\n getDownloadPath(): string | null {\n return this.downloadPath\n }\n}\n\n// Delta Update Generator\nexport class DeltaGenerator {\n /**\n * Generate a delta/patch file between two versions\n */\n static async generate(\n oldPath: string,\n newPath: string,\n outputPath: string\n ): Promise<{ size: number; sha256: string }> {\n // Use bsdiff for binary delta\n try {\n execFileSync('bsdiff', [oldPath, newPath, outputPath])\n\n const stats = statSync(outputPath)\n const hash = await DeltaGenerator.computeHash(outputPath)\n\n return {\n size: stats.size,\n sha256: hash,\n }\n }\ncatch {\n // Fall back to xdelta3\n execFileSync('xdelta3', ['-e', '-s', oldPath, newPath, outputPath])\n\n const stats = statSync(outputPath)\n const hash = await DeltaGenerator.computeHash(outputPath)\n\n return {\n size: stats.size,\n sha256: hash,\n }\n }\n }\n\n /**\n * Apply a delta/patch to create new version\n */\n static async apply(basePath: string, deltaPath: string, outputPath: string): Promise<void> {\n try {\n execFileSync('bspatch', [basePath, outputPath, deltaPath])\n }\ncatch {\n execFileSync('xdelta3', ['-d', '-s', basePath, deltaPath, outputPath])\n }\n }\n\n private static async computeHash(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash('sha256')\n const stream = createReadStream(filePath)\n\n stream.on('data', (chunk) => hash.update(chunk))\n stream.on('end', () => resolve(hash.digest('hex')))\n stream.on('error', reject)\n })\n }\n}\n\n// Update Server Generator\nexport function generateUpdateManifest(options: {\n version: string\n releaseNotes?: string\n platforms: {\n darwin?: { path: string; url: string }\n win32?: { path: string; url: string }\n linux?: { path: string; url: string }\n }\n deltas?: {\n platform: string\n fromVersion: string\n path: string\n url: string\n }[]\n}): UpdateInfo {\n const manifest: UpdateInfo = {\n version: options.version,\n releaseDate: new Date().toISOString(),\n releaseNotes: options.releaseNotes,\n platforms: {},\n }\n\n for (const [platform, info] of Object.entries(options.platforms)) {\n if (!info) continue\n\n // Hash and stat from the same buffer so a writer can't swap the file\n // between the size lookup and the digest. `readFileSync` opens with\n // O_RDONLY, but on POSIX another process can still rename underneath\n // us — copying the bytes once and deriving both metrics from that\n // snapshot is the cheapest way to make the manifest entry consistent.\n const bytes = readFileSync(info.path)\n const hash = createHash('sha256').update(bytes).digest('hex')\n\n manifest.platforms[platform] = {\n url: info.url,\n size: bytes.length,\n sha256: hash,\n delta: [],\n }\n\n const platformDeltas = options.deltas?.filter((d) => d.platform === platform) || []\n for (const delta of platformDeltas) {\n const deltaBytes = readFileSync(delta.path)\n const deltaHash = createHash('sha256').update(deltaBytes).digest('hex')\n\n manifest.platforms[platform].delta!.push({\n fromVersion: delta.fromVersion,\n url: delta.url,\n size: deltaBytes.length,\n sha256: deltaHash,\n })\n }\n }\n\n return manifest\n}\n\n// CLI Command\nexport async function updaterCommand(args: string[]): Promise<void> {\n const [subcommand, ...rest] = args\n\n switch (subcommand) {\n case 'check': {\n const url = rest[0]\n const version = rest[1] || '0.0.0'\n\n if (!url) {\n console.error('Usage: craft updater check <update-url> [current-version]')\n process.exit(1)\n }\n\n const updater = new AutoUpdater({\n updateUrl: url,\n currentVersion: version,\n appPath: process.cwd(),\n autoDownload: false,\n })\n\n const update = await updater.checkForUpdates()\n\n if (update) {\n console.log(`Update available: ${update.version}`)\n console.log(`Release date: ${update.releaseDate}`)\n if (update.releaseNotes) {\n console.log(`\\nRelease notes:\\n${update.releaseNotes}`)\n }\n }\nelse {\n console.log('No updates available')\n }\n break\n }\n\n case 'generate-delta': {\n const oldPath = rest[0]\n const newPath = rest[1]\n const outputPath = rest[2]\n\n if (!oldPath || !newPath || !outputPath) {\n console.error('Usage: craft updater generate-delta <old-file> <new-file> <output>')\n process.exit(1)\n }\n\n console.log('Generating delta update...')\n const result = await DeltaGenerator.generate(oldPath, newPath, outputPath)\n\n console.log(`Delta generated: ${outputPath}`)\n console.log(`Size: ${result.size} bytes`)\n console.log(`SHA256: ${result.sha256}`)\n break\n }\n\n case 'generate-manifest': {\n const version = rest[0]\n const outputPath = rest[1] || 'update.json'\n\n if (!version) {\n console.error('Usage: craft updater generate-manifest <version> [output]')\n process.exit(1)\n }\n\n const manifest: UpdateInfo = {\n version,\n releaseDate: new Date().toISOString(),\n platforms: {},\n }\n\n writeFileSync(outputPath, JSON.stringify(manifest, null, 2))\n console.log(`Manifest generated: ${outputPath}`)\n console.log('Edit the file to add platform-specific update URLs')\n break\n }\n\n default:\n console.log(`\nCraft Auto-Updater\n\nUsage: craft updater <command> [options]\n\nCommands:\n check <url> [version] Check for updates\n generate-delta <old> <new> <output> Generate delta update\n generate-manifest <version> [output] Generate update manifest\n\nExamples:\n craft updater check https://api.example.com/updates 1.0.0\n craft updater generate-delta app-1.0.0.zip app-1.1.0.zip delta-1.0.0-1.1.0.patch\n craft updater generate-manifest 1.1.0 update.json\n`)\n }\n}\n\nexport default AutoUpdater\n"
|
|
41
|
+
],
|
|
42
|
+
"mappings": "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",
|
|
43
|
+
"debugId": "141B94C437209F2B64756E2164756E21",
|
|
44
|
+
"names": []
|
|
45
|
+
}
|