@staticcanvas/typeflow 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +637 -0
- package/branding/dist/ico/typeflow-logo-16x16.ico +0 -0
- package/branding/dist/ico/typeflow-logo-256x256.ico +0 -0
- package/branding/dist/ico/typeflow-logo-32x32.ico +0 -0
- package/branding/dist/ico/typeflow-logo-48x48.ico +0 -0
- package/branding/dist/png/typeflow-logo-1024x1024.png +0 -0
- package/branding/dist/png/typeflow-logo-128x128.png +0 -0
- package/branding/dist/png/typeflow-logo-16x16.png +0 -0
- package/branding/dist/png/typeflow-logo-256x256.png +0 -0
- package/branding/dist/png/typeflow-logo-512x512.png +0 -0
- package/branding/dist/png/typeflow-logo-64x64.png +0 -0
- package/branding/dist/webp/typeflow-logo-1024x1024.webp +0 -0
- package/branding/dist/webp/typeflow-logo-128x128.webp +0 -0
- package/branding/dist/webp/typeflow-logo-16x16.webp +0 -0
- package/branding/dist/webp/typeflow-logo-256x256.webp +0 -0
- package/branding/dist/webp/typeflow-logo-32x32.webp +0 -0
- package/branding/dist/webp/typeflow-logo-48x48.webp +0 -0
- package/branding/dist/webp/typeflow-logo-512x512.webp +0 -0
- package/branding/dist/webp/typeflow-logo-64x64.webp +0 -0
- package/branding/gen-logo.ps1 +14 -0
- package/branding/typeflow-logo.svg +162 -0
- package/dist/typeflow/LICENSE +21 -0
- package/dist/typeflow/README.md +231 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-16x16.ico +0 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-256x256.ico +0 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-32x32.ico +0 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-48x48.ico +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-1024x1024.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-128x128.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-16x16.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-256x256.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-512x512.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-64x64.png +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-1024x1024.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-128x128.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-16x16.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-256x256.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-32x32.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-48x48.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-512x512.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-64x64.webp +0 -0
- package/dist/typeflow/branding/gen-logo.ps1 +14 -0
- package/dist/typeflow/branding/typeflow-logo.svg +162 -0
- package/dist/typeflow/dist/typeflow-caret.cjs +47 -0
- package/dist/typeflow/dist/typeflow-caret.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.esm.js +47 -0
- package/dist/typeflow/dist/typeflow-caret.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-caret.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.js +47 -0
- package/dist/typeflow/dist/typeflow-caret.js.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.min.js +2 -0
- package/dist/typeflow/dist/typeflow-caret.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.mjs +47 -0
- package/dist/typeflow/dist/typeflow-caret.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.cjs +109 -0
- package/dist/typeflow/dist/typeflow-debug.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.esm.js +109 -0
- package/dist/typeflow/dist/typeflow-debug.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-debug.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.js +109 -0
- package/dist/typeflow/dist/typeflow-debug.js.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.min.js +2 -0
- package/dist/typeflow/dist/typeflow-debug.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.mjs +109 -0
- package/dist/typeflow/dist/typeflow-debug.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.cjs +66 -0
- package/dist/typeflow/dist/typeflow-extchars.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.esm.js +66 -0
- package/dist/typeflow/dist/typeflow-extchars.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-extchars.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.js +66 -0
- package/dist/typeflow/dist/typeflow-extchars.js.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.min.js +2 -0
- package/dist/typeflow/dist/typeflow-extchars.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.mjs +66 -0
- package/dist/typeflow/dist/typeflow-extchars.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.cjs +47 -0
- package/dist/typeflow/dist/typeflow-keystroke.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.esm.js +47 -0
- package/dist/typeflow/dist/typeflow-keystroke.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-keystroke.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.js +47 -0
- package/dist/typeflow/dist/typeflow-keystroke.js.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.min.js +2 -0
- package/dist/typeflow/dist/typeflow-keystroke.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.mjs +47 -0
- package/dist/typeflow/dist/typeflow-keystroke.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.cjs +76 -0
- package/dist/typeflow/dist/typeflow-metrics.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.esm.js +76 -0
- package/dist/typeflow/dist/typeflow-metrics.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-metrics.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.js +76 -0
- package/dist/typeflow/dist/typeflow-metrics.js.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.min.js +2 -0
- package/dist/typeflow/dist/typeflow-metrics.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.mjs +76 -0
- package/dist/typeflow/dist/typeflow-metrics.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.cjs +3 -0
- package/dist/typeflow/dist/typeflow-parallel.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.esm.js +3 -0
- package/dist/typeflow/dist/typeflow-parallel.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-parallel.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.js +3 -0
- package/dist/typeflow/dist/typeflow-parallel.js.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.min.js +2 -0
- package/dist/typeflow/dist/typeflow-parallel.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.mjs +3 -0
- package/dist/typeflow/dist/typeflow-parallel.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.cjs +81 -0
- package/dist/typeflow/dist/typeflow-webaudio.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.esm.js +81 -0
- package/dist/typeflow/dist/typeflow-webaudio.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-webaudio.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.js +81 -0
- package/dist/typeflow/dist/typeflow-webaudio.js.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.min.js +2 -0
- package/dist/typeflow/dist/typeflow-webaudio.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.mjs +81 -0
- package/dist/typeflow/dist/typeflow-webaudio.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow.cjs +277 -0
- package/dist/typeflow/dist/typeflow.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow.esm.js +277 -0
- package/dist/typeflow/dist/typeflow.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow.js +277 -0
- package/dist/typeflow/dist/typeflow.js.map +1 -0
- package/dist/typeflow/dist/typeflow.min.js +2 -0
- package/dist/typeflow/dist/typeflow.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow.mjs +277 -0
- package/dist/typeflow/dist/typeflow.mjs.map +1 -0
- package/dist/typeflow/jsr.jsonc +27 -0
- package/dist/typeflow/package.json +79 -0
- package/dist/typeflow/src/typeflow-audio-presets.js +137 -0
- package/dist/typeflow/src/typeflow-caret.d.ts +65 -0
- package/dist/typeflow/src/typeflow-caret.js +303 -0
- package/dist/typeflow/src/typeflow-debug.d.ts +34 -0
- package/dist/typeflow/src/typeflow-debug.js +223 -0
- package/dist/typeflow/src/typeflow-extchars.d.ts +28 -0
- package/dist/typeflow/src/typeflow-extchars.js +132 -0
- package/dist/typeflow/src/typeflow-keystroke.d.ts +28 -0
- package/dist/typeflow/src/typeflow-keystroke.js +220 -0
- package/dist/typeflow/src/typeflow-metrics.d.ts +38 -0
- package/dist/typeflow/src/typeflow-metrics.js +556 -0
- package/dist/typeflow/src/typeflow-parallel.d.ts +36 -0
- package/dist/typeflow/src/typeflow-parallel.js +157 -0
- package/dist/typeflow/src/typeflow-webaudio.d.ts +83 -0
- package/dist/typeflow/src/typeflow-webaudio.js +517 -0
- package/dist/typeflow/src/typeflow.d.ts +328 -0
- package/dist/typeflow/src/typeflow.js +2119 -0
- package/jsr.jsonc +27 -0
- package/package.json +133 -0
- package/src/typeflow-audio-presets.js +137 -0
- package/src/typeflow-caret.d.ts +65 -0
- package/src/typeflow-caret.js +303 -0
- package/src/typeflow-debug.d.ts +34 -0
- package/src/typeflow-debug.js +223 -0
- package/src/typeflow-extchars.d.ts +28 -0
- package/src/typeflow-extchars.js +132 -0
- package/src/typeflow-keystroke.d.ts +28 -0
- package/src/typeflow-keystroke.js +220 -0
- package/src/typeflow-metrics.d.ts +38 -0
- package/src/typeflow-metrics.js +556 -0
- package/src/typeflow-parallel.d.ts +36 -0
- package/src/typeflow-parallel.js +157 -0
- package/src/typeflow-webaudio.d.ts +83 -0
- package/src/typeflow-webaudio.js +517 -0
- package/src/typeflow.d.ts +328 -0
- package/src/typeflow.js +2119 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeflow-metrics.min.js","sources":["../../../src/typeflow-metrics.js"],"sourcesContent":["/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description TypeFlow Metrics - Real-time Performance HUD & Diagnostic Tooltip.\n * Mounts an accessible, zero-CLS floating metrics badge/window in the viewport\n * tracking active animations, FPS, typed/erased units, render latency, and heap memory.\n *\n * @module @staticcanvas/typeflow/metrics\n */\n\nexport class TypeFlowMetrics {\n static instance = null;\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Constructs and initializes a TypeFlowMetrics tracker.\n * @param {Object} [options={}] - Configuration options.\n *\n * -------------\n *\n * @Properties\n * @param {'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'} [options.position='bottom-right'] - Screen corner location.\n * @param {boolean} [options.detailed=false] - Whether to start with the expanded modal open.\n * @param {boolean} [options.autoTrack=true] - Whether to observe global DOM mutations and animations.\n * @param {number} [options.updateInterval=250] - Metric polling interval in milliseconds.\n * @param {number} [options.zIndex=99999] - CSS z-index for floating badge.\n *\n * -------------\n *\n * @example\n * const metrics = new TypeFlowMetrics({ position: 'bottom-right', detailed: true });\n */\n constructor(options = {}) {\n this.options = {\n position: 'bottom-right',\n detailed: false,\n autoTrack: true,\n updateInterval: 250,\n zIndex: 99999,\n ...options,\n };\n\n this.stats = {\n fps: 60,\n activeInstances: 0,\n totalTyped: 0,\n totalErased: 0,\n renderLatencyMs: 0,\n domMutations: 0,\n interruptions: 0,\n startTime: performance.now(),\n lastFrameTime: performance.now(),\n frameCount: 0,\n history: [],\n };\n\n this.container = null;\n this.isExpanded = Boolean(this.options.detailed);\n this.rafId = null;\n this.intervalId = null;\n this.observer = null;\n\n if (typeof window !== 'undefined') {\n this.init();\n }\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Mounts the singleton floating HUD metrics badge into the active browser document.\n * @param {Object} [options={}] - Custom configuration options.\n * @returns {TypeFlowMetrics} The active singleton instance.\n *\n * -------------\n *\n * @Properties\n * @param {'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'} [options.position='bottom-right'] - Screen corner location.\n * @param {boolean} [options.detailed=false] - Whether to open expanded view initially.\n *\n * -------------\n *\n * @example\n * TypeFlowMetrics.mount({ position: 'bottom-right' });\n */\n static mount(options = {}) {\n if (!TypeFlowMetrics.instance) {\n TypeFlowMetrics.instance = new TypeFlowMetrics(options);\n }\n return TypeFlowMetrics.instance;\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Unmounts the singleton floating HUD metrics badge and stops all listeners.\n * @returns {void}\n *\n * -------------\n *\n * @example\n * TypeFlowMetrics.unmount();\n */\n static unmount() {\n if (TypeFlowMetrics.instance) {\n TypeFlowMetrics.instance.destroy();\n TypeFlowMetrics.instance = null;\n }\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Returns a snapshot object of current performance metrics.\n * @returns {Object | null} Metric snapshot data or null if not mounted.\n *\n * -------------\n *\n * @example\n * const stats = TypeFlowMetrics.getStats();\n * console.log('Active animations:', stats?.activeInstances);\n */\n static getStats() {\n return TypeFlowMetrics.instance ? TypeFlowMetrics.instance.getSnapshot() : null;\n }\n\n init() {\n this.createDom();\n this.startFpsTracker();\n this.startDomMutationObserver();\n\n this.intervalId = setInterval(() => {\n this.updateMetrics();\n }, this.options.updateInterval);\n }\n\n createDom() {\n if (this.container || typeof document === 'undefined') return;\n\n this.container = document.createElement('aside');\n this.container.id = 'typeflow-metrics-hud';\n this.container.setAttribute('aria-label', 'TypeFlow Performance Metrics HUD');\n this.container.setAttribute('role', 'region');\n\n const posStyles = {\n 'bottom-right': 'bottom: 16px; right: 16px;',\n 'bottom-left': 'bottom: 16px; left: 16px;',\n 'top-right': 'top: 16px; right: 16px;',\n 'top-left': 'top: 16px; left: 16px;',\n };\n\n const style = document.createElement('style');\n style.textContent = `\n #typeflow-metrics-hud {\n position: fixed;\n ${posStyles[this.options.position] || posStyles['bottom-right']}\n z-index: ${this.options.zIndex};\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 12px;\n color: #f1f5f9;\n user-select: none;\n box-sizing: border-box;\n transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n }\n #typeflow-metrics-hud * {\n box-sizing: border-box;\n }\n .tf-hud-pill {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: rgba(15, 23, 42, 0.85);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 9999px;\n box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.5), 0 0 15px rgba(255, 107, 43, 0.15);\n cursor: pointer;\n transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;\n }\n .tf-hud-pill:hover {\n transform: translateY(-2px);\n border-color: rgba(255, 107, 43, 0.5);\n box-shadow: 0 6px 24px -2px rgba(0, 0, 0, 0.6), 0 0 20px rgba(255, 107, 43, 0.3);\n }\n .tf-hud-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #10b981;\n box-shadow: 0 0 8px #10b981;\n transition: background 0.3s ease;\n }\n .tf-hud-dot.active {\n background: #ff6b2b;\n box-shadow: 0 0 10px #ff6b2b;\n animation: tf-hud-pulse 1.5s infinite;\n }\n @keyframes tf-hud-pulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.25); opacity: 0.7; }\n }\n .tf-hud-mono {\n font-family: 'JetBrains Mono', monospace;\n font-weight: 600;\n letter-spacing: -0.02em;\n }\n .tf-hud-label {\n color: #94a3b8;\n font-size: 11px;\n }\n .tf-hud-modal {\n display: none;\n width: 290px;\n background: rgba(15, 23, 42, 0.94);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 12px;\n box-shadow: 0 20px 40px -4px rgba(0, 0, 0, 0.6), 0 0 25px rgba(255, 107, 43, 0.15);\n padding: 14px;\n margin-top: 8px;\n animation: tf-hud-fade-in 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n }\n @keyframes tf-hud-fade-in {\n from { opacity: 0; transform: translateY(6px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .tf-hud-modal.open {\n display: block;\n }\n .tf-hud-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-bottom: 10px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n margin-bottom: 10px;\n }\n .tf-hud-title {\n font-family: 'Lexend', sans-serif;\n font-weight: 600;\n font-size: 13px;\n background: linear-gradient(135deg, #ff6b2b, #38bdf8);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n .tf-hud-close {\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 14px;\n line-height: 1;\n }\n .tf-hud-close:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n }\n .tf-hud-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n margin-bottom: 10px;\n }\n .tf-hud-card {\n background: rgba(30, 41, 59, 0.6);\n border: 1px solid rgba(255, 255, 255, 0.05);\n border-radius: 8px;\n padding: 8px 10px;\n }\n .tf-hud-card-label {\n font-size: 10px;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 2px;\n }\n .tf-hud-card-val {\n font-family: 'JetBrains Mono', monospace;\n font-size: 14px;\n font-weight: 600;\n color: #e2e8f0;\n }\n .tf-hud-accent {\n color: #ff6b2b;\n }\n .tf-hud-cyan {\n color: #38bdf8;\n }\n .tf-hud-green {\n color: #10b981;\n }\n .tf-hud-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-top: 8px;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n font-size: 10px;\n color: #64748b;\n }\n .tf-hud-btn {\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.1);\n color: #cbd5e1;\n padding: 3px 8px;\n border-radius: 4px;\n font-size: 10px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .tf-hud-btn:hover {\n background: rgba(255, 107, 43, 0.2);\n border-color: rgba(255, 107, 43, 0.4);\n color: #ff6b2b;\n }\n `;\n\n const pill = document.createElement('div');\n pill.className = 'tf-hud-pill';\n pill.setAttribute('role', 'button');\n pill.setAttribute('tabindex', '0');\n pill.innerHTML = `\n <span class=\"tf-hud-dot\" id=\"tf-hud-dot\"></span>\n <span class=\"tf-hud-mono\" id=\"tf-hud-fps\">60 FPS</span>\n <span class=\"tf-hud-label\">•</span>\n <span class=\"tf-hud-mono tf-hud-accent\" id=\"tf-hud-active\">0 Active</span>\n `;\n\n const modal = document.createElement('div');\n modal.className = `tf-hud-modal ${this.isExpanded ? 'open' : ''}`;\n modal.id = 'tf-hud-modal';\n modal.innerHTML = `\n <div class=\"tf-hud-header\">\n <span class=\"tf-hud-title\">TypeFlow Metrics</span>\n <button class=\"tf-hud-close\" id=\"tf-hud-close\" aria-label=\"Close Metrics Window\">✕</button>\n </div>\n <div class=\"tf-hud-grid\">\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Frame Rate</div>\n <div class=\"tf-hud-card-val tf-hud-green\" id=\"tf-hud-m-fps\">60.0 FPS</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Active Anim</div>\n <div class=\"tf-hud-card-val tf-hud-accent\" id=\"tf-hud-m-active\">0</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Typed Units</div>\n <div class=\"tf-hud-card-val tf-hud-cyan\" id=\"tf-hud-m-typed\">0</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Erased Units</div>\n <div class=\"tf-hud-card-val\" id=\"tf-hud-m-erased\">0</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">DOM Mut.</div>\n <div class=\"tf-hud-card-val\" id=\"tf-hud-m-mut\">0</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Heap Memory</div>\n <div class=\"tf-hud-card-val tf-hud-mono\" id=\"tf-hud-m-mem\">-- MB</div>\n </div>\n </div>\n <div class=\"tf-hud-footer\">\n <span id=\"tf-hud-uptime\">Uptime: 0s</span>\n <div style=\"display:flex;gap:4px;\">\n <button class=\"tf-hud-btn\" id=\"tf-hud-copy\">Copy JSON</button>\n <button class=\"tf-hud-btn\" id=\"tf-hud-reset\">Reset</button>\n </div>\n </div>\n `;\n\n this.container.appendChild(style);\n this.container.appendChild(pill);\n this.container.appendChild(modal);\n document.body.appendChild(this.container);\n\n pill.addEventListener('click', () => this.toggleModal());\n pill.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this.toggleModal();\n }\n });\n\n modal.querySelector('#tf-hud-close')?.addEventListener('click', () => this.toggleModal(false));\n modal.querySelector('#tf-hud-reset')?.addEventListener('click', () => this.resetStats());\n modal.querySelector('#tf-hud-copy')?.addEventListener('click', () => this.copyStats());\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Toggles or sets the visibility of the expanded metrics window modal.\n * @param {boolean} [forceState] - Optional explicit state boolean.\n * @returns {void}\n *\n * -------------\n *\n * @example\n * hud.toggleModal(true); // Open\n * hud.toggleModal(false); // Close\n */\n toggleModal(forceState) {\n this.isExpanded = forceState !== undefined ? forceState : !this.isExpanded;\n const modal = this.container?.querySelector('#tf-hud-modal');\n if (modal) {\n modal.classList.toggle('open', this.isExpanded);\n }\n }\n\n startFpsTracker() {\n let lastTime = performance.now();\n let frames = 0;\n\n const tick = (now) => {\n frames++;\n if (now >= lastTime + 1000) {\n this.stats.fps = Math.round((frames * 1000) / (now - lastTime));\n frames = 0;\n lastTime = now;\n }\n this.rafId = requestAnimationFrame(tick);\n };\n this.rafId = requestAnimationFrame(tick);\n }\n\n startDomMutationObserver() {\n if (typeof MutationObserver === 'undefined' || typeof document === 'undefined') return;\n this.observer = new MutationObserver((mutations) => {\n let relevant = 0;\n for (const m of mutations) {\n if (m.target === this.container || this.container?.contains(m.target)) continue;\n if (m.target.nodeType === 1 && m.target.classList?.contains('tf-cursor')) continue;\n relevant++;\n }\n this.stats.domMutations += relevant;\n });\n\n this.observer.observe(document.body, {\n childList: true,\n subtree: true,\n characterData: true,\n });\n }\n\n recordTyped(count = 1) {\n this.stats.totalTyped += count;\n }\n\n recordErased(count = 1) {\n this.stats.totalErased += count;\n }\n\n recordInterruption() {\n this.stats.interruptions += 1;\n }\n\n updateMetrics() {\n if (!this.container) return;\n\n if (typeof window !== 'undefined' && window.TypeFlow?.active) {\n this.stats.activeInstances = window.TypeFlow.active.size;\n }\n\n const dot = this.container.querySelector('#tf-hud-dot');\n const fpsEl = this.container.querySelector('#tf-hud-fps');\n const activeEl = this.container.querySelector('#tf-hud-active');\n\n if (dot) dot.classList.toggle('active', this.stats.activeInstances > 0);\n if (fpsEl) fpsEl.textContent = `${this.stats.fps} FPS`;\n if (activeEl) activeEl.textContent = `${this.stats.activeInstances} Active`;\n\n if (this.isExpanded) {\n const mFps = this.container.querySelector('#tf-hud-m-fps');\n const mActive = this.container.querySelector('#tf-hud-m-active');\n const mTyped = this.container.querySelector('#tf-hud-m-typed');\n const mErased = this.container.querySelector('#tf-hud-m-erased');\n const mMut = this.container.querySelector('#tf-hud-m-mut');\n const mMem = this.container.querySelector('#tf-hud-m-mem');\n const mUptime = this.container.querySelector('#tf-hud-uptime');\n\n if (mFps) mFps.textContent = `${this.stats.fps}.0 FPS`;\n if (mActive) mActive.textContent = `${this.stats.activeInstances}`;\n if (mTyped) mTyped.textContent = this.stats.totalTyped.toLocaleString();\n if (mErased) mErased.textContent = this.stats.totalErased.toLocaleString();\n if (mMut) mMut.textContent = this.stats.domMutations.toLocaleString();\n\n if (mMem) {\n if (performance.memory?.usedJSHeapSize) {\n const mb = (performance.memory.usedJSHeapSize / (1024 * 1024)).toFixed(1);\n mMem.textContent = `${mb} MB`;\n } else {\n mMem.textContent = 'Native';\n }\n }\n\n if (mUptime) {\n const sec = Math.floor((performance.now() - this.stats.startTime) / 1000);\n mUptime.textContent = `Uptime: ${sec}s`;\n }\n }\n }\n\n resetStats() {\n this.stats.totalTyped = 0;\n this.stats.totalErased = 0;\n this.stats.domMutations = 0;\n this.stats.interruptions = 0;\n this.stats.startTime = performance.now();\n this.updateMetrics();\n }\n\n copyStats() {\n const json = JSON.stringify(this.getSnapshot(), null, 2);\n if (navigator.clipboard?.writeText) {\n navigator.clipboard.writeText(json);\n const btn = this.container?.querySelector('#tf-hud-copy');\n if (btn) {\n const prev = btn.textContent;\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = prev;\n }, 1500);\n }\n }\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Returns a snapshot object of lifetime metrics.\n * @returns {Object} Metric data snapshot.\n */\n getSnapshot() {\n return {\n timestamp: new Date().toISOString(),\n fps: this.stats.fps,\n activeInstances: this.stats.activeInstances,\n totalTyped: this.stats.totalTyped,\n totalErased: this.stats.totalErased,\n domMutations: this.stats.domMutations,\n interruptions: this.stats.interruptions,\n uptimeSeconds: Math.floor((performance.now() - this.stats.startTime) / 1000),\n };\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Cleans up observers, timers, and removes the HUD from the DOM.\n * @returns {void}\n */\n destroy() {\n if (this.rafId) cancelAnimationFrame(this.rafId);\n if (this.intervalId) clearInterval(this.intervalId);\n if (this.observer) this.observer.disconnect();\n if (this.container?.parentNode) {\n this.container.parentNode.removeChild(this.container);\n }\n this.container = null;\n }\n}\n\nif (typeof window !== 'undefined') {\n window.TypeFlowMetrics = TypeFlowMetrics;\n}\n"],"names":["_TypeFlowMetrics","constructor","options","this","__spreadValues","position","detailed","autoTrack","updateInterval","zIndex","stats","fps","activeInstances","totalTyped","totalErased","renderLatencyMs","domMutations","interruptions","startTime","performance","now","lastFrameTime","frameCount","history","container","isExpanded","Boolean","rafId","intervalId","observer","window","init","mount","instance","unmount","destroy","getStats","getSnapshot","createDom","startFpsTracker","startDomMutationObserver","setInterval","updateMetrics","document","createElement","id","setAttribute","posStyles","style","textContent","pill","className","innerHTML","modal","appendChild","body","addEventListener","toggleModal","e","key","preventDefault","_a","querySelector","_b","resetStats","_c","copyStats","forceState","classList","toggle","lastTime","frames","tick","Math","round","requestAnimationFrame","MutationObserver","mutations","relevant","m","target","contains","nodeType","observe","childList","subtree","characterData","recordTyped","count","recordErased","recordInterruption","TypeFlow","active","size","dot","fpsEl","activeEl","mFps","mActive","mTyped","mErased","mMut","mMem","mUptime","toLocaleString","memory","usedJSHeapSize","mb","toFixed","sec","floor","json","JSON","stringify","navigator","clipboard","writeText","btn","prev","setTimeout","timestamp","Date","toISOString","uptimeSeconds","cancelAnimationFrame","clearInterval","disconnect","parentNode","removeChild","TypeFlowMetrics"],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/*! typeflow-metrics | MIT */
|
|
2
|
+
var t=Object.defineProperty,n=Object.getOwnPropertySymbols,e=Object.prototype.hasOwnProperty,s=Object.prototype.propertyIsEnumerable,i=(n,e,s)=>e in n?t(n,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):n[e]=s;const a=class t{
|
|
3
|
+
/** * * * * * * * * * * * * * * * * * * * * * * * * * * **
|
|
4
|
+
* @description Constructs and initializes a TypeFlowMetrics tracker.
|
|
5
|
+
* @param {Object} [options={}] - Configuration options.
|
|
6
|
+
*
|
|
7
|
+
* -------------
|
|
8
|
+
*
|
|
9
|
+
* @Properties
|
|
10
|
+
* @param {'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'} [options.position='bottom-right'] - Screen corner location.
|
|
11
|
+
* @param {boolean} [options.detailed=false] - Whether to start with the expanded modal open.
|
|
12
|
+
* @param {boolean} [options.autoTrack=true] - Whether to observe global DOM mutations and animations.
|
|
13
|
+
* @param {number} [options.updateInterval=250] - Metric polling interval in milliseconds.
|
|
14
|
+
* @param {number} [options.zIndex=99999] - CSS z-index for floating badge.
|
|
15
|
+
*
|
|
16
|
+
* -------------
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const metrics = new TypeFlowMetrics({ position: 'bottom-right', detailed: true });
|
|
20
|
+
*/
|
|
21
|
+
constructor(t={}){this.options=((t,a)=>{for(var o in a||(a={}))e.call(a,o)&&i(t,o,a[o]);if(n)for(var o of n(a))s.call(a,o)&&i(t,o,a[o]);return t})({position:"bottom-right",detailed:!1,autoTrack:!0,updateInterval:250,zIndex:99999},t),this.stats={fps:60,activeInstances:0,totalTyped:0,totalErased:0,renderLatencyMs:0,domMutations:0,interruptions:0,startTime:performance.now(),lastFrameTime:performance.now(),frameCount:0,history:[]},this.container=null,this.isExpanded=Boolean(this.options.detailed),this.rafId=null,this.intervalId=null,this.observer=null,"undefined"!=typeof window&&this.init()}
|
|
22
|
+
/** * * * * * * * * * * * * * * * * * * * * * * * * * * **
|
|
23
|
+
* @description Mounts the singleton floating HUD metrics badge into the active browser document.
|
|
24
|
+
* @param {Object} [options={}] - Custom configuration options.
|
|
25
|
+
* @returns {TypeFlowMetrics} The active singleton instance.
|
|
26
|
+
*
|
|
27
|
+
* -------------
|
|
28
|
+
*
|
|
29
|
+
* @Properties
|
|
30
|
+
* @param {'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'} [options.position='bottom-right'] - Screen corner location.
|
|
31
|
+
* @param {boolean} [options.detailed=false] - Whether to open expanded view initially.
|
|
32
|
+
*
|
|
33
|
+
* -------------
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* TypeFlowMetrics.mount({ position: 'bottom-right' });
|
|
37
|
+
*/static mount(n={}){return t.instance||(t.instance=new t(n)),t.instance}
|
|
38
|
+
/** * * * * * * * * * * * * * * * * * * * * * * * * * * **
|
|
39
|
+
* @description Unmounts the singleton floating HUD metrics badge and stops all listeners.
|
|
40
|
+
* @returns {void}
|
|
41
|
+
*
|
|
42
|
+
* -------------
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* TypeFlowMetrics.unmount();
|
|
46
|
+
*/static unmount(){t.instance&&(t.instance.destroy(),t.instance=null)}
|
|
47
|
+
/** * * * * * * * * * * * * * * * * * * * * * * * * * * **
|
|
48
|
+
* @description Returns a snapshot object of current performance metrics.
|
|
49
|
+
* @returns {Object | null} Metric snapshot data or null if not mounted.
|
|
50
|
+
*
|
|
51
|
+
* -------------
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const stats = TypeFlowMetrics.getStats();
|
|
55
|
+
* console.log('Active animations:', stats?.activeInstances);
|
|
56
|
+
*/static getStats(){return t.instance?t.instance.getSnapshot():null}init(){this.createDom(),this.startFpsTracker(),this.startDomMutationObserver(),this.intervalId=setInterval(()=>{this.updateMetrics()},this.options.updateInterval)}createDom(){var t,n,e;if(this.container||"undefined"==typeof document)return;this.container=document.createElement("aside"),this.container.id="typeflow-metrics-hud",this.container.setAttribute("aria-label","TypeFlow Performance Metrics HUD"),this.container.setAttribute("role","region");const s={"bottom-right":"bottom: 16px; right: 16px;","bottom-left":"bottom: 16px; left: 16px;","top-right":"top: 16px; right: 16px;","top-left":"top: 16px; left: 16px;"},i=document.createElement("style");i.textContent=`\n #typeflow-metrics-hud {\n position: fixed;\n ${s[this.options.position]||s["bottom-right"]}\n z-index: ${this.options.zIndex};\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 12px;\n color: #f1f5f9;\n user-select: none;\n box-sizing: border-box;\n transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n }\n #typeflow-metrics-hud * {\n box-sizing: border-box;\n }\n .tf-hud-pill {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: rgba(15, 23, 42, 0.85);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 9999px;\n box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.5), 0 0 15px rgba(255, 107, 43, 0.15);\n cursor: pointer;\n transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;\n }\n .tf-hud-pill:hover {\n transform: translateY(-2px);\n border-color: rgba(255, 107, 43, 0.5);\n box-shadow: 0 6px 24px -2px rgba(0, 0, 0, 0.6), 0 0 20px rgba(255, 107, 43, 0.3);\n }\n .tf-hud-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #10b981;\n box-shadow: 0 0 8px #10b981;\n transition: background 0.3s ease;\n }\n .tf-hud-dot.active {\n background: #ff6b2b;\n box-shadow: 0 0 10px #ff6b2b;\n animation: tf-hud-pulse 1.5s infinite;\n }\n @keyframes tf-hud-pulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.25); opacity: 0.7; }\n }\n .tf-hud-mono {\n font-family: 'JetBrains Mono', monospace;\n font-weight: 600;\n letter-spacing: -0.02em;\n }\n .tf-hud-label {\n color: #94a3b8;\n font-size: 11px;\n }\n .tf-hud-modal {\n display: none;\n width: 290px;\n background: rgba(15, 23, 42, 0.94);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 12px;\n box-shadow: 0 20px 40px -4px rgba(0, 0, 0, 0.6), 0 0 25px rgba(255, 107, 43, 0.15);\n padding: 14px;\n margin-top: 8px;\n animation: tf-hud-fade-in 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n }\n @keyframes tf-hud-fade-in {\n from { opacity: 0; transform: translateY(6px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .tf-hud-modal.open {\n display: block;\n }\n .tf-hud-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-bottom: 10px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n margin-bottom: 10px;\n }\n .tf-hud-title {\n font-family: 'Lexend', sans-serif;\n font-weight: 600;\n font-size: 13px;\n background: linear-gradient(135deg, #ff6b2b, #38bdf8);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n .tf-hud-close {\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 14px;\n line-height: 1;\n }\n .tf-hud-close:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n }\n .tf-hud-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n margin-bottom: 10px;\n }\n .tf-hud-card {\n background: rgba(30, 41, 59, 0.6);\n border: 1px solid rgba(255, 255, 255, 0.05);\n border-radius: 8px;\n padding: 8px 10px;\n }\n .tf-hud-card-label {\n font-size: 10px;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 2px;\n }\n .tf-hud-card-val {\n font-family: 'JetBrains Mono', monospace;\n font-size: 14px;\n font-weight: 600;\n color: #e2e8f0;\n }\n .tf-hud-accent {\n color: #ff6b2b;\n }\n .tf-hud-cyan {\n color: #38bdf8;\n }\n .tf-hud-green {\n color: #10b981;\n }\n .tf-hud-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-top: 8px;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n font-size: 10px;\n color: #64748b;\n }\n .tf-hud-btn {\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.1);\n color: #cbd5e1;\n padding: 3px 8px;\n border-radius: 4px;\n font-size: 10px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .tf-hud-btn:hover {\n background: rgba(255, 107, 43, 0.2);\n border-color: rgba(255, 107, 43, 0.4);\n color: #ff6b2b;\n }\n `;const a=document.createElement("div");a.className="tf-hud-pill",a.setAttribute("role","button"),a.setAttribute("tabindex","0"),a.innerHTML='\n <span class="tf-hud-dot" id="tf-hud-dot"></span>\n <span class="tf-hud-mono" id="tf-hud-fps">60 FPS</span>\n <span class="tf-hud-label">•</span>\n <span class="tf-hud-mono tf-hud-accent" id="tf-hud-active">0 Active</span>\n ';const o=document.createElement("div");o.className="tf-hud-modal "+(this.isExpanded?"open":""),o.id="tf-hud-modal",o.innerHTML='\n <div class="tf-hud-header">\n <span class="tf-hud-title">TypeFlow Metrics</span>\n <button class="tf-hud-close" id="tf-hud-close" aria-label="Close Metrics Window">✕</button>\n </div>\n <div class="tf-hud-grid">\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Frame Rate</div>\n <div class="tf-hud-card-val tf-hud-green" id="tf-hud-m-fps">60.0 FPS</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Active Anim</div>\n <div class="tf-hud-card-val tf-hud-accent" id="tf-hud-m-active">0</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Typed Units</div>\n <div class="tf-hud-card-val tf-hud-cyan" id="tf-hud-m-typed">0</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Erased Units</div>\n <div class="tf-hud-card-val" id="tf-hud-m-erased">0</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">DOM Mut.</div>\n <div class="tf-hud-card-val" id="tf-hud-m-mut">0</div>\n </div>\n <div class="tf-hud-card">\n <div class="tf-hud-card-label">Heap Memory</div>\n <div class="tf-hud-card-val tf-hud-mono" id="tf-hud-m-mem">-- MB</div>\n </div>\n </div>\n <div class="tf-hud-footer">\n <span id="tf-hud-uptime">Uptime: 0s</span>\n <div style="display:flex;gap:4px;">\n <button class="tf-hud-btn" id="tf-hud-copy">Copy JSON</button>\n <button class="tf-hud-btn" id="tf-hud-reset">Reset</button>\n </div>\n </div>\n ',this.container.appendChild(i),this.container.appendChild(a),this.container.appendChild(o),document.body.appendChild(this.container),a.addEventListener("click",()=>this.toggleModal()),a.addEventListener("keydown",t=>{"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.toggleModal())}),null==(t=o.querySelector("#tf-hud-close"))||t.addEventListener("click",()=>this.toggleModal(!1)),null==(n=o.querySelector("#tf-hud-reset"))||n.addEventListener("click",()=>this.resetStats()),null==(e=o.querySelector("#tf-hud-copy"))||e.addEventListener("click",()=>this.copyStats())}
|
|
57
|
+
/** * * * * * * * * * * * * * * * * * * * * * * * * * * **
|
|
58
|
+
* @description Toggles or sets the visibility of the expanded metrics window modal.
|
|
59
|
+
* @param {boolean} [forceState] - Optional explicit state boolean.
|
|
60
|
+
* @returns {void}
|
|
61
|
+
*
|
|
62
|
+
* -------------
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* hud.toggleModal(true); // Open
|
|
66
|
+
* hud.toggleModal(false); // Close
|
|
67
|
+
*/toggleModal(t){var n;this.isExpanded=void 0!==t?t:!this.isExpanded;const e=null==(n=this.container)?void 0:n.querySelector("#tf-hud-modal");e&&e.classList.toggle("open",this.isExpanded)}startFpsTracker(){let t=performance.now(),n=0;const e=s=>{n++,s>=t+1e3&&(this.stats.fps=Math.round(1e3*n/(s-t)),n=0,t=s),this.rafId=requestAnimationFrame(e)};this.rafId=requestAnimationFrame(e)}startDomMutationObserver(){"undefined"!=typeof MutationObserver&&"undefined"!=typeof document&&(this.observer=new MutationObserver(t=>{var n,e;let s=0;for(const i of t)i.target===this.container||(null==(n=this.container)?void 0:n.contains(i.target))||1===i.target.nodeType&&(null==(e=i.target.classList)?void 0:e.contains("tf-cursor"))||s++;this.stats.domMutations+=s}),this.observer.observe(document.body,{childList:!0,subtree:!0,characterData:!0}))}recordTyped(t=1){this.stats.totalTyped+=t}recordErased(t=1){this.stats.totalErased+=t}recordInterruption(){this.stats.interruptions+=1}updateMetrics(){var t,n;if(!this.container)return;"undefined"!=typeof window&&(null==(t=window.TypeFlow)?void 0:t.active)&&(this.stats.activeInstances=window.TypeFlow.active.size);const e=this.container.querySelector("#tf-hud-dot"),s=this.container.querySelector("#tf-hud-fps"),i=this.container.querySelector("#tf-hud-active");if(e&&e.classList.toggle("active",this.stats.activeInstances>0),s&&(s.textContent=`${this.stats.fps} FPS`),i&&(i.textContent=`${this.stats.activeInstances} Active`),this.isExpanded){const t=this.container.querySelector("#tf-hud-m-fps"),e=this.container.querySelector("#tf-hud-m-active"),s=this.container.querySelector("#tf-hud-m-typed"),i=this.container.querySelector("#tf-hud-m-erased"),a=this.container.querySelector("#tf-hud-m-mut"),o=this.container.querySelector("#tf-hud-m-mem"),r=this.container.querySelector("#tf-hud-uptime");if(t&&(t.textContent=`${this.stats.fps}.0 FPS`),e&&(e.textContent=`${this.stats.activeInstances}`),s&&(s.textContent=this.stats.totalTyped.toLocaleString()),i&&(i.textContent=this.stats.totalErased.toLocaleString()),a&&(a.textContent=this.stats.domMutations.toLocaleString()),o)if(null==(n=performance.memory)?void 0:n.usedJSHeapSize){const t=(performance.memory.usedJSHeapSize/1048576).toFixed(1);o.textContent=`${t} MB`}else o.textContent="Native";if(r){const t=Math.floor((performance.now()-this.stats.startTime)/1e3);r.textContent=`Uptime: ${t}s`}}}resetStats(){this.stats.totalTyped=0,this.stats.totalErased=0,this.stats.domMutations=0,this.stats.interruptions=0,this.stats.startTime=performance.now(),this.updateMetrics()}copyStats(){var t,n;const e=JSON.stringify(this.getSnapshot(),null,2);if(null==(t=navigator.clipboard)?void 0:t.writeText){navigator.clipboard.writeText(e);const t=null==(n=this.container)?void 0:n.querySelector("#tf-hud-copy");if(t){const n=t.textContent;t.textContent="Copied!",setTimeout(()=>{t.textContent=n},1500)}}}
|
|
68
|
+
/** * * * * * * * * * * * * * * * * * * * * * * * * * * **
|
|
69
|
+
* @description Returns a snapshot object of lifetime metrics.
|
|
70
|
+
* @returns {Object} Metric data snapshot.
|
|
71
|
+
*/getSnapshot(){return{timestamp:(new Date).toISOString(),fps:this.stats.fps,activeInstances:this.stats.activeInstances,totalTyped:this.stats.totalTyped,totalErased:this.stats.totalErased,domMutations:this.stats.domMutations,interruptions:this.stats.interruptions,uptimeSeconds:Math.floor((performance.now()-this.stats.startTime)/1e3)}}
|
|
72
|
+
/** * * * * * * * * * * * * * * * * * * * * * * * * * * **
|
|
73
|
+
* @description Cleans up observers, timers, and removes the HUD from the DOM.
|
|
74
|
+
* @returns {void}
|
|
75
|
+
*/destroy(){var t;this.rafId&&cancelAnimationFrame(this.rafId),this.intervalId&&clearInterval(this.intervalId),this.observer&&this.observer.disconnect(),(null==(t=this.container)?void 0:t.parentNode)&&this.container.parentNode.removeChild(this.container),this.container=null}};var o;i(a,"symbol"!=typeof(o="instance")?o+"":o,null);let r=a;"undefined"!=typeof window&&(window.TypeFlowMetrics=r);export{r as TypeFlowMetrics};
|
|
76
|
+
//# sourceMappingURL=typeflow-metrics.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeflow-metrics.mjs","sources":["../../../src/typeflow-metrics.js"],"sourcesContent":["/** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description TypeFlow Metrics - Real-time Performance HUD & Diagnostic Tooltip.\n * Mounts an accessible, zero-CLS floating metrics badge/window in the viewport\n * tracking active animations, FPS, typed/erased units, render latency, and heap memory.\n *\n * @module @staticcanvas/typeflow/metrics\n */\n\nexport class TypeFlowMetrics {\n static instance = null;\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Constructs and initializes a TypeFlowMetrics tracker.\n * @param {Object} [options={}] - Configuration options.\n *\n * -------------\n *\n * @Properties\n * @param {'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'} [options.position='bottom-right'] - Screen corner location.\n * @param {boolean} [options.detailed=false] - Whether to start with the expanded modal open.\n * @param {boolean} [options.autoTrack=true] - Whether to observe global DOM mutations and animations.\n * @param {number} [options.updateInterval=250] - Metric polling interval in milliseconds.\n * @param {number} [options.zIndex=99999] - CSS z-index for floating badge.\n *\n * -------------\n *\n * @example\n * const metrics = new TypeFlowMetrics({ position: 'bottom-right', detailed: true });\n */\n constructor(options = {}) {\n this.options = {\n position: 'bottom-right',\n detailed: false,\n autoTrack: true,\n updateInterval: 250,\n zIndex: 99999,\n ...options,\n };\n\n this.stats = {\n fps: 60,\n activeInstances: 0,\n totalTyped: 0,\n totalErased: 0,\n renderLatencyMs: 0,\n domMutations: 0,\n interruptions: 0,\n startTime: performance.now(),\n lastFrameTime: performance.now(),\n frameCount: 0,\n history: [],\n };\n\n this.container = null;\n this.isExpanded = Boolean(this.options.detailed);\n this.rafId = null;\n this.intervalId = null;\n this.observer = null;\n\n if (typeof window !== 'undefined') {\n this.init();\n }\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Mounts the singleton floating HUD metrics badge into the active browser document.\n * @param {Object} [options={}] - Custom configuration options.\n * @returns {TypeFlowMetrics} The active singleton instance.\n *\n * -------------\n *\n * @Properties\n * @param {'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'} [options.position='bottom-right'] - Screen corner location.\n * @param {boolean} [options.detailed=false] - Whether to open expanded view initially.\n *\n * -------------\n *\n * @example\n * TypeFlowMetrics.mount({ position: 'bottom-right' });\n */\n static mount(options = {}) {\n if (!TypeFlowMetrics.instance) {\n TypeFlowMetrics.instance = new TypeFlowMetrics(options);\n }\n return TypeFlowMetrics.instance;\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Unmounts the singleton floating HUD metrics badge and stops all listeners.\n * @returns {void}\n *\n * -------------\n *\n * @example\n * TypeFlowMetrics.unmount();\n */\n static unmount() {\n if (TypeFlowMetrics.instance) {\n TypeFlowMetrics.instance.destroy();\n TypeFlowMetrics.instance = null;\n }\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Returns a snapshot object of current performance metrics.\n * @returns {Object | null} Metric snapshot data or null if not mounted.\n *\n * -------------\n *\n * @example\n * const stats = TypeFlowMetrics.getStats();\n * console.log('Active animations:', stats?.activeInstances);\n */\n static getStats() {\n return TypeFlowMetrics.instance ? TypeFlowMetrics.instance.getSnapshot() : null;\n }\n\n init() {\n this.createDom();\n this.startFpsTracker();\n this.startDomMutationObserver();\n\n this.intervalId = setInterval(() => {\n this.updateMetrics();\n }, this.options.updateInterval);\n }\n\n createDom() {\n if (this.container || typeof document === 'undefined') return;\n\n this.container = document.createElement('aside');\n this.container.id = 'typeflow-metrics-hud';\n this.container.setAttribute('aria-label', 'TypeFlow Performance Metrics HUD');\n this.container.setAttribute('role', 'region');\n\n const posStyles = {\n 'bottom-right': 'bottom: 16px; right: 16px;',\n 'bottom-left': 'bottom: 16px; left: 16px;',\n 'top-right': 'top: 16px; right: 16px;',\n 'top-left': 'top: 16px; left: 16px;',\n };\n\n const style = document.createElement('style');\n style.textContent = `\n #typeflow-metrics-hud {\n position: fixed;\n ${posStyles[this.options.position] || posStyles['bottom-right']}\n z-index: ${this.options.zIndex};\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 12px;\n color: #f1f5f9;\n user-select: none;\n box-sizing: border-box;\n transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n }\n #typeflow-metrics-hud * {\n box-sizing: border-box;\n }\n .tf-hud-pill {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: rgba(15, 23, 42, 0.85);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 9999px;\n box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.5), 0 0 15px rgba(255, 107, 43, 0.15);\n cursor: pointer;\n transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;\n }\n .tf-hud-pill:hover {\n transform: translateY(-2px);\n border-color: rgba(255, 107, 43, 0.5);\n box-shadow: 0 6px 24px -2px rgba(0, 0, 0, 0.6), 0 0 20px rgba(255, 107, 43, 0.3);\n }\n .tf-hud-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #10b981;\n box-shadow: 0 0 8px #10b981;\n transition: background 0.3s ease;\n }\n .tf-hud-dot.active {\n background: #ff6b2b;\n box-shadow: 0 0 10px #ff6b2b;\n animation: tf-hud-pulse 1.5s infinite;\n }\n @keyframes tf-hud-pulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.25); opacity: 0.7; }\n }\n .tf-hud-mono {\n font-family: 'JetBrains Mono', monospace;\n font-weight: 600;\n letter-spacing: -0.02em;\n }\n .tf-hud-label {\n color: #94a3b8;\n font-size: 11px;\n }\n .tf-hud-modal {\n display: none;\n width: 290px;\n background: rgba(15, 23, 42, 0.94);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 12px;\n box-shadow: 0 20px 40px -4px rgba(0, 0, 0, 0.6), 0 0 25px rgba(255, 107, 43, 0.15);\n padding: 14px;\n margin-top: 8px;\n animation: tf-hud-fade-in 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n }\n @keyframes tf-hud-fade-in {\n from { opacity: 0; transform: translateY(6px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .tf-hud-modal.open {\n display: block;\n }\n .tf-hud-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-bottom: 10px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n margin-bottom: 10px;\n }\n .tf-hud-title {\n font-family: 'Lexend', sans-serif;\n font-weight: 600;\n font-size: 13px;\n background: linear-gradient(135deg, #ff6b2b, #38bdf8);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n .tf-hud-close {\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 14px;\n line-height: 1;\n }\n .tf-hud-close:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #fff;\n }\n .tf-hud-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 8px;\n margin-bottom: 10px;\n }\n .tf-hud-card {\n background: rgba(30, 41, 59, 0.6);\n border: 1px solid rgba(255, 255, 255, 0.05);\n border-radius: 8px;\n padding: 8px 10px;\n }\n .tf-hud-card-label {\n font-size: 10px;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 2px;\n }\n .tf-hud-card-val {\n font-family: 'JetBrains Mono', monospace;\n font-size: 14px;\n font-weight: 600;\n color: #e2e8f0;\n }\n .tf-hud-accent {\n color: #ff6b2b;\n }\n .tf-hud-cyan {\n color: #38bdf8;\n }\n .tf-hud-green {\n color: #10b981;\n }\n .tf-hud-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-top: 8px;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n font-size: 10px;\n color: #64748b;\n }\n .tf-hud-btn {\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.1);\n color: #cbd5e1;\n padding: 3px 8px;\n border-radius: 4px;\n font-size: 10px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .tf-hud-btn:hover {\n background: rgba(255, 107, 43, 0.2);\n border-color: rgba(255, 107, 43, 0.4);\n color: #ff6b2b;\n }\n `;\n\n const pill = document.createElement('div');\n pill.className = 'tf-hud-pill';\n pill.setAttribute('role', 'button');\n pill.setAttribute('tabindex', '0');\n pill.innerHTML = `\n <span class=\"tf-hud-dot\" id=\"tf-hud-dot\"></span>\n <span class=\"tf-hud-mono\" id=\"tf-hud-fps\">60 FPS</span>\n <span class=\"tf-hud-label\">•</span>\n <span class=\"tf-hud-mono tf-hud-accent\" id=\"tf-hud-active\">0 Active</span>\n `;\n\n const modal = document.createElement('div');\n modal.className = `tf-hud-modal ${this.isExpanded ? 'open' : ''}`;\n modal.id = 'tf-hud-modal';\n modal.innerHTML = `\n <div class=\"tf-hud-header\">\n <span class=\"tf-hud-title\">TypeFlow Metrics</span>\n <button class=\"tf-hud-close\" id=\"tf-hud-close\" aria-label=\"Close Metrics Window\">✕</button>\n </div>\n <div class=\"tf-hud-grid\">\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Frame Rate</div>\n <div class=\"tf-hud-card-val tf-hud-green\" id=\"tf-hud-m-fps\">60.0 FPS</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Active Anim</div>\n <div class=\"tf-hud-card-val tf-hud-accent\" id=\"tf-hud-m-active\">0</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Typed Units</div>\n <div class=\"tf-hud-card-val tf-hud-cyan\" id=\"tf-hud-m-typed\">0</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Erased Units</div>\n <div class=\"tf-hud-card-val\" id=\"tf-hud-m-erased\">0</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">DOM Mut.</div>\n <div class=\"tf-hud-card-val\" id=\"tf-hud-m-mut\">0</div>\n </div>\n <div class=\"tf-hud-card\">\n <div class=\"tf-hud-card-label\">Heap Memory</div>\n <div class=\"tf-hud-card-val tf-hud-mono\" id=\"tf-hud-m-mem\">-- MB</div>\n </div>\n </div>\n <div class=\"tf-hud-footer\">\n <span id=\"tf-hud-uptime\">Uptime: 0s</span>\n <div style=\"display:flex;gap:4px;\">\n <button class=\"tf-hud-btn\" id=\"tf-hud-copy\">Copy JSON</button>\n <button class=\"tf-hud-btn\" id=\"tf-hud-reset\">Reset</button>\n </div>\n </div>\n `;\n\n this.container.appendChild(style);\n this.container.appendChild(pill);\n this.container.appendChild(modal);\n document.body.appendChild(this.container);\n\n pill.addEventListener('click', () => this.toggleModal());\n pill.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this.toggleModal();\n }\n });\n\n modal.querySelector('#tf-hud-close')?.addEventListener('click', () => this.toggleModal(false));\n modal.querySelector('#tf-hud-reset')?.addEventListener('click', () => this.resetStats());\n modal.querySelector('#tf-hud-copy')?.addEventListener('click', () => this.copyStats());\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Toggles or sets the visibility of the expanded metrics window modal.\n * @param {boolean} [forceState] - Optional explicit state boolean.\n * @returns {void}\n *\n * -------------\n *\n * @example\n * hud.toggleModal(true); // Open\n * hud.toggleModal(false); // Close\n */\n toggleModal(forceState) {\n this.isExpanded = forceState !== undefined ? forceState : !this.isExpanded;\n const modal = this.container?.querySelector('#tf-hud-modal');\n if (modal) {\n modal.classList.toggle('open', this.isExpanded);\n }\n }\n\n startFpsTracker() {\n let lastTime = performance.now();\n let frames = 0;\n\n const tick = (now) => {\n frames++;\n if (now >= lastTime + 1000) {\n this.stats.fps = Math.round((frames * 1000) / (now - lastTime));\n frames = 0;\n lastTime = now;\n }\n this.rafId = requestAnimationFrame(tick);\n };\n this.rafId = requestAnimationFrame(tick);\n }\n\n startDomMutationObserver() {\n if (typeof MutationObserver === 'undefined' || typeof document === 'undefined') return;\n this.observer = new MutationObserver((mutations) => {\n let relevant = 0;\n for (const m of mutations) {\n if (m.target === this.container || this.container?.contains(m.target)) continue;\n if (m.target.nodeType === 1 && m.target.classList?.contains('tf-cursor')) continue;\n relevant++;\n }\n this.stats.domMutations += relevant;\n });\n\n this.observer.observe(document.body, {\n childList: true,\n subtree: true,\n characterData: true,\n });\n }\n\n recordTyped(count = 1) {\n this.stats.totalTyped += count;\n }\n\n recordErased(count = 1) {\n this.stats.totalErased += count;\n }\n\n recordInterruption() {\n this.stats.interruptions += 1;\n }\n\n updateMetrics() {\n if (!this.container) return;\n\n if (typeof window !== 'undefined' && window.TypeFlow?.active) {\n this.stats.activeInstances = window.TypeFlow.active.size;\n }\n\n const dot = this.container.querySelector('#tf-hud-dot');\n const fpsEl = this.container.querySelector('#tf-hud-fps');\n const activeEl = this.container.querySelector('#tf-hud-active');\n\n if (dot) dot.classList.toggle('active', this.stats.activeInstances > 0);\n if (fpsEl) fpsEl.textContent = `${this.stats.fps} FPS`;\n if (activeEl) activeEl.textContent = `${this.stats.activeInstances} Active`;\n\n if (this.isExpanded) {\n const mFps = this.container.querySelector('#tf-hud-m-fps');\n const mActive = this.container.querySelector('#tf-hud-m-active');\n const mTyped = this.container.querySelector('#tf-hud-m-typed');\n const mErased = this.container.querySelector('#tf-hud-m-erased');\n const mMut = this.container.querySelector('#tf-hud-m-mut');\n const mMem = this.container.querySelector('#tf-hud-m-mem');\n const mUptime = this.container.querySelector('#tf-hud-uptime');\n\n if (mFps) mFps.textContent = `${this.stats.fps}.0 FPS`;\n if (mActive) mActive.textContent = `${this.stats.activeInstances}`;\n if (mTyped) mTyped.textContent = this.stats.totalTyped.toLocaleString();\n if (mErased) mErased.textContent = this.stats.totalErased.toLocaleString();\n if (mMut) mMut.textContent = this.stats.domMutations.toLocaleString();\n\n if (mMem) {\n if (performance.memory?.usedJSHeapSize) {\n const mb = (performance.memory.usedJSHeapSize / (1024 * 1024)).toFixed(1);\n mMem.textContent = `${mb} MB`;\n } else {\n mMem.textContent = 'Native';\n }\n }\n\n if (mUptime) {\n const sec = Math.floor((performance.now() - this.stats.startTime) / 1000);\n mUptime.textContent = `Uptime: ${sec}s`;\n }\n }\n }\n\n resetStats() {\n this.stats.totalTyped = 0;\n this.stats.totalErased = 0;\n this.stats.domMutations = 0;\n this.stats.interruptions = 0;\n this.stats.startTime = performance.now();\n this.updateMetrics();\n }\n\n copyStats() {\n const json = JSON.stringify(this.getSnapshot(), null, 2);\n if (navigator.clipboard?.writeText) {\n navigator.clipboard.writeText(json);\n const btn = this.container?.querySelector('#tf-hud-copy');\n if (btn) {\n const prev = btn.textContent;\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = prev;\n }, 1500);\n }\n }\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Returns a snapshot object of lifetime metrics.\n * @returns {Object} Metric data snapshot.\n */\n getSnapshot() {\n return {\n timestamp: new Date().toISOString(),\n fps: this.stats.fps,\n activeInstances: this.stats.activeInstances,\n totalTyped: this.stats.totalTyped,\n totalErased: this.stats.totalErased,\n domMutations: this.stats.domMutations,\n interruptions: this.stats.interruptions,\n uptimeSeconds: Math.floor((performance.now() - this.stats.startTime) / 1000),\n };\n }\n\n /** * * * * * * * * * * * * * * * * * * * * * * * * * * **\n * @description Cleans up observers, timers, and removes the HUD from the DOM.\n * @returns {void}\n */\n destroy() {\n if (this.rafId) cancelAnimationFrame(this.rafId);\n if (this.intervalId) clearInterval(this.intervalId);\n if (this.observer) this.observer.disconnect();\n if (this.container?.parentNode) {\n this.container.parentNode.removeChild(this.container);\n }\n this.container = null;\n }\n}\n\nif (typeof window !== 'undefined') {\n window.TypeFlowMetrics = TypeFlowMetrics;\n}\n"],"names":["_TypeFlowMetrics","constructor","options","this","__spreadValues","position","detailed","autoTrack","updateInterval","zIndex","stats","fps","activeInstances","totalTyped","totalErased","renderLatencyMs","domMutations","interruptions","startTime","performance","now","lastFrameTime","frameCount","history","container","isExpanded","Boolean","rafId","intervalId","observer","window","init","mount","instance","unmount","destroy","getStats","getSnapshot","createDom","startFpsTracker","startDomMutationObserver","setInterval","updateMetrics","_a","_b","_c","document","createElement","id","setAttribute","posStyles","style","textContent","pill","className","innerHTML","modal","appendChild","body","addEventListener","toggleModal","e","key","preventDefault","querySelector","resetStats","copyStats","forceState","classList","toggle","lastTime","frames","tick","Math","round","requestAnimationFrame","MutationObserver","mutations","relevant","m","target","contains","nodeType","observe","childList","subtree","characterData","recordTyped","count","recordErased","recordInterruption","TypeFlow","active","size","dot","fpsEl","activeEl","mFps","mActive","mTyped","mErased","mMut","mMem","mUptime","toLocaleString","memory","usedJSHeapSize","mb","toFixed","sec","floor","json","JSON","stringify","navigator","clipboard","writeText","btn","prev","setTimeout","timestamp","Date","toISOString","uptimeSeconds","cancelAnimationFrame","clearInterval","disconnect","parentNode","removeChild","TypeFlowMetrics"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/*! typeflow-parallel | MIT */
|
|
2
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TypeflowParallel={})}(this,function(e){"use strict";var t=Object.defineProperty,r=Object.defineProperties,l=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,a=(e,r,l)=>r in e?t(e,r,{enumerable:!0,configurable:!0,writable:!0,value:l}):e[r]=l,s=(e,t,r)=>new Promise((l,n)=>{var o=e=>{try{a(r.next(e))}catch(e){n(e)}},i=e=>{try{a(r.throw(e))}catch(e){n(e)}},a=e=>e.done?l(e.value):Promise.resolve(e.value).then(o,i);a((r=r.apply(e,t)).next())});const u=(e,t)=>({kind:"parallel",steps:e,options:t});function p(e){if(!(null==e?void 0:e.type)||!(null==e?void 0:e.erase))throw new TypeError("TypeFlow parallel: a TypeFlow engine instance is required.");const t=(u,p={})=>{const c=Array.isArray(u)?u:[];if(0===c.length)return{stop:()=>{},promise:Promise.resolve({completed:!0,text:"",results:[]})};const f=Number(p.concurrency),d=Number.isFinite(f)?Math.max(1,Math.min(c.length,Math.floor(f))):c.length,y="fail-fast"===p.settlement?"fail-fast":"all-settled",m=new Set,h=new Set,g=new Array(c.length);let b=0,w=!1,v=!1;const P=()=>{m.forEach(e=>e.stop()),h.forEach(e=>e()),m.clear(),h.clear()},T={stop:()=>{w||(w=!0,v=!0,P())},promise:null},x=e=>{var t;const r=null!=(t=e.target)?t:p.target;if(!r)throw new Error("TypeFlow parallel: a step requires a target or default `target`.");return r},O=e=>new Promise(t=>{var r;if("undefined"==typeof IntersectionObserver)return t(!0);let l=!1;const n=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&o(!0)},{threshold:null!=(r=e.threshold)?r:.1}),o=e=>{l||(l=!0,n.disconnect(),h.delete(i),t(e))},i=()=>o(!1);h.add(i);const a="string"==typeof x(e)?document.querySelector(x(e)):x(e);if(!a)throw new Error("TypeFlow parallel: visibility target not found.");n.observe(a)}),j=u=>s(null,null,function*(){var s,c,f;if(!u||"object"!=typeof u)throw new TypeError("TypeFlow parallel: invalid step.");if("pause"===u.kind)return{completed:yield(f=u.duration,new Promise(e=>{let t=!1;const r=r=>{t||(t=!0,clearTimeout(l),h.delete(n),e(r))},l=setTimeout(()=>r(!0),Math.max(0,Number(f)||0)),n=()=>r(!1);h.add(n)})),text:""};if("visible"===u.kind)return{completed:yield O(u),text:""};if("call"===u.kind)return yield u.fn(),{completed:!0,text:""};let d;if("type"===u.kind)d=e.type(x(u),u.text,u.config);else if("erase"===u.kind)d=e.erase(x(u),u.config);else{if("parallel"!==u.kind)throw new TypeError(`TypeFlow parallel: unsupported step kind \`${String(u.kind)}\`.`);d=t(u.steps,(y=((e,t)=>{for(var r in t||(t={}))o.call(t,r)&&a(e,r,t[r]);if(n)for(var r of n(t))i.call(t,r)&&a(e,r,t[r]);return e})({},u.options),g={target:null!=(c=null==(s=u.options)?void 0:s.target)?c:p.target},r(y,l(g))))}var y,g;m.add(d);try{return yield d.promise}finally{m.delete(d)}});return T.promise=Promise.all(Array.from({length:d},()=>s(null,null,function*(){for(;!v;){const e=b++;if(e>=c.length)return;try{const t=yield j(c[e]);g[e]={status:t.completed?"fulfilled":"interrupted",value:t}}catch(t){g[e]={status:"rejected",reason:t}}"fulfilled"!==g[e].status&&"fail-fast"===y&&(v=!0,P())}}))).then(()=>{for(let e=0;e<c.length;e+=1)null!=g[e]||(g[e]={status:"interrupted",value:{completed:!1,text:""}});return{completed:!w&&g.every(({status:e})=>"fulfilled"===e),text:"",results:g}}),T};return t}e.createParallel=p,e.installParallel=function(e,t){const r=p(e);return Object.defineProperty(e,"parallel",{configurable:!0,value:r}),t&&Object.defineProperty(t,"parallel",{configurable:!0,value:u}),e},e.parallelStep=u,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
|
|
3
|
+
//# sourceMappingURL=typeflow-parallel.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeflow-parallel.cjs","sources":["../../../src/typeflow-parallel.js"],"sourcesContent":["/**\n * EXPERIMENTAL opt-in parallel orchestration for TypeFlow.\n * This module intentionally does not import core, keeping stable bundles small.\n */\n\nexport const parallelStep = (steps, options) => ({ kind: 'parallel', steps, options });\n\nexport function createParallel(engine) {\n if (!engine?.type || !engine?.erase)\n throw new TypeError('TypeFlow parallel: a TypeFlow engine instance is required.');\n\n const parallel = (steps, options = {}) => {\n const input = Array.isArray(steps) ? steps : [];\n if (input.length === 0)\n return {\n stop: () => {},\n promise: Promise.resolve({ completed: true, text: '', results: [] }),\n };\n\n const requested = Number(options.concurrency);\n const concurrency = Number.isFinite(requested)\n ? Math.max(1, Math.min(input.length, Math.floor(requested)))\n : input.length;\n const settlement = options.settlement === 'fail-fast' ? 'fail-fast' : 'all-settled';\n const activeChildren = new Set();\n const cancelWaits = new Set();\n const results = new Array(input.length);\n let nextIndex = 0;\n let interrupted = false;\n let halted = false;\n\n const stopActive = () => {\n activeChildren.forEach((child) => child.stop());\n cancelWaits.forEach((cancel) => cancel());\n activeChildren.clear();\n cancelWaits.clear();\n };\n const controller = {\n stop: () => {\n if (interrupted) return;\n interrupted = true;\n halted = true;\n stopActive();\n },\n promise: null,\n };\n const targetFor = (step) => {\n const target = step.target ?? options.target;\n if (!target)\n throw new Error('TypeFlow parallel: a step requires a target or default `target`.');\n return target;\n };\n const wait = (duration) =>\n new Promise((resolve) => {\n let done = false;\n const finish = (completed) => {\n if (done) return;\n done = true;\n clearTimeout(id);\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const id = setTimeout(() => finish(true), Math.max(0, Number(duration) || 0));\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n });\n const visible = (step) =>\n new Promise((resolve) => {\n if (typeof IntersectionObserver === 'undefined') return resolve(true);\n let done = false;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) finish(true);\n },\n { threshold: step.threshold ?? 0.1 }\n );\n const finish = (completed) => {\n if (done) return;\n done = true;\n observer.disconnect();\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n const target =\n typeof targetFor(step) === 'string'\n ? document.querySelector(targetFor(step))\n : targetFor(step);\n if (!target) throw new Error('TypeFlow parallel: visibility target not found.');\n observer.observe(target);\n });\n const runStep = async (step) => {\n if (!step || typeof step !== 'object')\n throw new TypeError('TypeFlow parallel: invalid step.');\n if (step.kind === 'pause') return { completed: await wait(step.duration), text: '' };\n if (step.kind === 'visible') return { completed: await visible(step), text: '' };\n if (step.kind === 'call') {\n await step.fn();\n return { completed: true, text: '' };\n }\n let child;\n if (step.kind === 'type') child = engine.type(targetFor(step), step.text, step.config);\n else if (step.kind === 'erase') child = engine.erase(targetFor(step), step.config);\n else if (step.kind === 'parallel')\n child = parallel(step.steps, {\n ...step.options,\n target: step.options?.target ?? options.target,\n });\n else\n throw new TypeError(`TypeFlow parallel: unsupported step kind \\`${String(step.kind)}\\`.`);\n activeChildren.add(child);\n try {\n return await child.promise;\n } finally {\n activeChildren.delete(child);\n }\n };\n const worker = async () => {\n while (!halted) {\n const index = nextIndex++;\n if (index >= input.length) return;\n try {\n const value = await runStep(input[index]);\n results[index] = { status: value.completed ? 'fulfilled' : 'interrupted', value };\n } catch (error) {\n results[index] = { status: 'rejected', reason: error };\n }\n if (results[index].status !== 'fulfilled' && settlement === 'fail-fast') {\n halted = true;\n stopActive();\n }\n }\n };\n controller.promise = Promise.all(Array.from({ length: concurrency }, worker)).then(() => {\n for (let index = 0; index < input.length; index += 1) {\n results[index] ??= { status: 'interrupted', value: { completed: false, text: '' } };\n }\n return {\n completed: !interrupted && results.every(({ status }) => status === 'fulfilled'),\n text: '',\n results,\n };\n });\n return controller;\n };\n return parallel;\n}\n\n/** Explicitly installs the experimental methods onto caller-provided core objects. */\nexport function installParallel(engine, sequenceHelpers) {\n const parallel = createParallel(engine);\n Object.defineProperty(engine, 'parallel', { configurable: true, value: parallel });\n if (sequenceHelpers)\n Object.defineProperty(sequenceHelpers, 'parallel', { configurable: true, value: parallelStep });\n return engine;\n}\n"],"names":["parallelStep","steps","options","kind","createParallel","engine","type","erase","TypeError","parallel","input","Array","isArray","length","stop","promise","Promise","resolve","completed","text","results","requested","Number","concurrency","isFinite","Math","max","min","floor","settlement","activeChildren","Set","cancelWaits","nextIndex","interrupted","halted","stopActive","forEach","child","cancel","clear","controller","targetFor","step","target","_a","Error","visible","IntersectionObserver","done","observer","entries","some","entry","isIntersecting","threshold","finish","disconnect","delete","add","document","querySelector","observe","runStep","__async","duration","clearTimeout","id","setTimeout","fn","config","String","__spreadValues","_b","all","from","index","value","status","error","reason","then","every","sequenceHelpers","Object","defineProperty","configurable"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/*! typeflow-parallel | MIT */
|
|
2
|
+
var e=Object.defineProperty,t=Object.defineProperties,r=Object.getOwnPropertyDescriptors,l=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,i=(t,r,l)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:l}):t[r]=l,a=(e,t,r)=>new Promise((l,n)=>{var o=e=>{try{a(r.next(e))}catch(e){n(e)}},i=e=>{try{a(r.throw(e))}catch(e){n(e)}},a=e=>e.done?l(e.value):Promise.resolve(e.value).then(o,i);a((r=r.apply(e,t)).next())});const s=(e,t)=>({kind:"parallel",steps:e,options:t});function u(e){if(!(null==e?void 0:e.type)||!(null==e?void 0:e.erase))throw new TypeError("TypeFlow parallel: a TypeFlow engine instance is required.");const s=(u,p={})=>{const c=Array.isArray(u)?u:[];if(0===c.length)return{stop:()=>{},promise:Promise.resolve({completed:!0,text:"",results:[]})};const d=Number(p.concurrency),f=Number.isFinite(d)?Math.max(1,Math.min(c.length,Math.floor(d))):c.length,y="fail-fast"===p.settlement?"fail-fast":"all-settled",m=new Set,h=new Set,w=new Array(c.length);let v=0,g=!1,b=!1;const O=()=>{m.forEach(e=>e.stop()),h.forEach(e=>e()),m.clear(),h.clear()},P={stop:()=>{g||(g=!0,b=!0,O())},promise:null},x=e=>{var t;const r=null!=(t=e.target)?t:p.target;if(!r)throw new Error("TypeFlow parallel: a step requires a target or default `target`.");return r},T=e=>new Promise(t=>{var r;if("undefined"==typeof IntersectionObserver)return t(!0);let l=!1;const n=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&o(!0)},{threshold:null!=(r=e.threshold)?r:.1}),o=e=>{l||(l=!0,n.disconnect(),h.delete(i),t(e))},i=()=>o(!1);h.add(i);const a="string"==typeof x(e)?document.querySelector(x(e)):x(e);if(!a)throw new Error("TypeFlow parallel: visibility target not found.");n.observe(a)}),j=u=>a(null,null,function*(){var a,c,d;if(!u||"object"!=typeof u)throw new TypeError("TypeFlow parallel: invalid step.");if("pause"===u.kind)return{completed:yield(d=u.duration,new Promise(e=>{let t=!1;const r=r=>{t||(t=!0,clearTimeout(l),h.delete(n),e(r))},l=setTimeout(()=>r(!0),Math.max(0,Number(d)||0)),n=()=>r(!1);h.add(n)})),text:""};if("visible"===u.kind)return{completed:yield T(u),text:""};if("call"===u.kind)return yield u.fn(),{completed:!0,text:""};let f;if("type"===u.kind)f=e.type(x(u),u.text,u.config);else if("erase"===u.kind)f=e.erase(x(u),u.config);else{if("parallel"!==u.kind)throw new TypeError(`TypeFlow parallel: unsupported step kind \`${String(u.kind)}\`.`);f=s(u.steps,(y=((e,t)=>{for(var r in t||(t={}))n.call(t,r)&&i(e,r,t[r]);if(l)for(var r of l(t))o.call(t,r)&&i(e,r,t[r]);return e})({},u.options),w={target:null!=(c=null==(a=u.options)?void 0:a.target)?c:p.target},t(y,r(w))))}var y,w;m.add(f);try{return yield f.promise}finally{m.delete(f)}});return P.promise=Promise.all(Array.from({length:f},()=>a(null,null,function*(){for(;!b;){const e=v++;if(e>=c.length)return;try{const t=yield j(c[e]);w[e]={status:t.completed?"fulfilled":"interrupted",value:t}}catch(t){w[e]={status:"rejected",reason:t}}"fulfilled"!==w[e].status&&"fail-fast"===y&&(b=!0,O())}}))).then(()=>{for(let e=0;e<c.length;e+=1)null!=w[e]||(w[e]={status:"interrupted",value:{completed:!1,text:""}});return{completed:!g&&w.every(({status:e})=>"fulfilled"===e),text:"",results:w}}),P};return s}function p(e,t){const r=u(e);return Object.defineProperty(e,"parallel",{configurable:!0,value:r}),t&&Object.defineProperty(t,"parallel",{configurable:!0,value:s}),e}export{u as createParallel,p as installParallel,s as parallelStep};
|
|
3
|
+
//# sourceMappingURL=typeflow-parallel.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeflow-parallel.esm.js","sources":["../../../src/typeflow-parallel.js"],"sourcesContent":["/**\n * EXPERIMENTAL opt-in parallel orchestration for TypeFlow.\n * This module intentionally does not import core, keeping stable bundles small.\n */\n\nexport const parallelStep = (steps, options) => ({ kind: 'parallel', steps, options });\n\nexport function createParallel(engine) {\n if (!engine?.type || !engine?.erase)\n throw new TypeError('TypeFlow parallel: a TypeFlow engine instance is required.');\n\n const parallel = (steps, options = {}) => {\n const input = Array.isArray(steps) ? steps : [];\n if (input.length === 0)\n return {\n stop: () => {},\n promise: Promise.resolve({ completed: true, text: '', results: [] }),\n };\n\n const requested = Number(options.concurrency);\n const concurrency = Number.isFinite(requested)\n ? Math.max(1, Math.min(input.length, Math.floor(requested)))\n : input.length;\n const settlement = options.settlement === 'fail-fast' ? 'fail-fast' : 'all-settled';\n const activeChildren = new Set();\n const cancelWaits = new Set();\n const results = new Array(input.length);\n let nextIndex = 0;\n let interrupted = false;\n let halted = false;\n\n const stopActive = () => {\n activeChildren.forEach((child) => child.stop());\n cancelWaits.forEach((cancel) => cancel());\n activeChildren.clear();\n cancelWaits.clear();\n };\n const controller = {\n stop: () => {\n if (interrupted) return;\n interrupted = true;\n halted = true;\n stopActive();\n },\n promise: null,\n };\n const targetFor = (step) => {\n const target = step.target ?? options.target;\n if (!target)\n throw new Error('TypeFlow parallel: a step requires a target or default `target`.');\n return target;\n };\n const wait = (duration) =>\n new Promise((resolve) => {\n let done = false;\n const finish = (completed) => {\n if (done) return;\n done = true;\n clearTimeout(id);\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const id = setTimeout(() => finish(true), Math.max(0, Number(duration) || 0));\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n });\n const visible = (step) =>\n new Promise((resolve) => {\n if (typeof IntersectionObserver === 'undefined') return resolve(true);\n let done = false;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) finish(true);\n },\n { threshold: step.threshold ?? 0.1 }\n );\n const finish = (completed) => {\n if (done) return;\n done = true;\n observer.disconnect();\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n const target =\n typeof targetFor(step) === 'string'\n ? document.querySelector(targetFor(step))\n : targetFor(step);\n if (!target) throw new Error('TypeFlow parallel: visibility target not found.');\n observer.observe(target);\n });\n const runStep = async (step) => {\n if (!step || typeof step !== 'object')\n throw new TypeError('TypeFlow parallel: invalid step.');\n if (step.kind === 'pause') return { completed: await wait(step.duration), text: '' };\n if (step.kind === 'visible') return { completed: await visible(step), text: '' };\n if (step.kind === 'call') {\n await step.fn();\n return { completed: true, text: '' };\n }\n let child;\n if (step.kind === 'type') child = engine.type(targetFor(step), step.text, step.config);\n else if (step.kind === 'erase') child = engine.erase(targetFor(step), step.config);\n else if (step.kind === 'parallel')\n child = parallel(step.steps, {\n ...step.options,\n target: step.options?.target ?? options.target,\n });\n else\n throw new TypeError(`TypeFlow parallel: unsupported step kind \\`${String(step.kind)}\\`.`);\n activeChildren.add(child);\n try {\n return await child.promise;\n } finally {\n activeChildren.delete(child);\n }\n };\n const worker = async () => {\n while (!halted) {\n const index = nextIndex++;\n if (index >= input.length) return;\n try {\n const value = await runStep(input[index]);\n results[index] = { status: value.completed ? 'fulfilled' : 'interrupted', value };\n } catch (error) {\n results[index] = { status: 'rejected', reason: error };\n }\n if (results[index].status !== 'fulfilled' && settlement === 'fail-fast') {\n halted = true;\n stopActive();\n }\n }\n };\n controller.promise = Promise.all(Array.from({ length: concurrency }, worker)).then(() => {\n for (let index = 0; index < input.length; index += 1) {\n results[index] ??= { status: 'interrupted', value: { completed: false, text: '' } };\n }\n return {\n completed: !interrupted && results.every(({ status }) => status === 'fulfilled'),\n text: '',\n results,\n };\n });\n return controller;\n };\n return parallel;\n}\n\n/** Explicitly installs the experimental methods onto caller-provided core objects. */\nexport function installParallel(engine, sequenceHelpers) {\n const parallel = createParallel(engine);\n Object.defineProperty(engine, 'parallel', { configurable: true, value: parallel });\n if (sequenceHelpers)\n Object.defineProperty(sequenceHelpers, 'parallel', { configurable: true, value: parallelStep });\n return engine;\n}\n"],"names":["parallelStep","steps","options","kind","createParallel","engine","type","erase","TypeError","parallel","input","Array","isArray","length","stop","promise","Promise","resolve","completed","text","results","requested","Number","concurrency","isFinite","Math","max","min","floor","settlement","activeChildren","Set","cancelWaits","nextIndex","interrupted","halted","stopActive","forEach","child","cancel","clear","controller","targetFor","step","_a","target","Error","visible","IntersectionObserver","done","observer","entries","some","entry","isIntersecting","threshold","finish","disconnect","delete","add","document","querySelector","observe","runStep","__async","_b","duration","clearTimeout","id","setTimeout","fn","config","String","__spreadValues","all","from","index","value","status","error","reason","then","every","installParallel","sequenceHelpers","Object","defineProperty","configurable"],"mappings":";+dAKY,MAACA,EAAe,CAACC,EAAOC,KAAA,CAAeC,KAAM,WAAYF,QAAOC,YAErE,SAASE,EAAeC,GAC7B,KAAK,MAAAA,OAAA,EAAAA,EAAQC,SAAS,MAAAD,OAAA,EAAAA,EAAQE,OAC5B,MAAM,IAAIC,UAAU,8DAEtB,MAAMC,EAAW,CAACR,EAAOC,EAAU,CAAA,KACjC,MAAMQ,EAAQC,MAAMC,QAAQX,GAASA,EAAQ,GAC7C,GAAqB,IAAjBS,EAAMG,OACR,MAAO,CACLC,KAAM,OACNC,QAASC,QAAQC,QAAQ,CAAEC,WAAW,EAAMC,KAAM,GAAIC,QAAS,MAGnE,MAAMC,EAAYC,OAAOpB,EAAQqB,aAC3BA,EAAcD,OAAOE,SAASH,GAChCI,KAAKC,IAAI,EAAGD,KAAKE,IAAIjB,EAAMG,OAAQY,KAAKG,MAAMP,KAC9CX,EAAMG,OACJgB,EAAoC,cAAvB3B,EAAQ2B,WAA6B,YAAc,cAChEC,MAAqBC,IACrBC,MAAkBD,IAClBX,EAAU,IAAIT,MAAMD,EAAMG,QAChC,IAAIoB,EAAY,EACZC,GAAc,EACdC,GAAS,EAEb,MAAMC,EAAa,KACjBN,EAAeO,QAASC,GAAUA,EAAMxB,QACxCkB,EAAYK,QAASE,GAAWA,KAChCT,EAAeU,QACfR,EAAYQ,SAERC,EAAa,CACjB3B,KAAM,KACAoB,IACJA,GAAc,EACdC,GAAS,EACTC,MAEFrB,QAAS,MAEL2B,EAAaC,IA9CvB,IAAAC,EA+CM,MAAMC,EAAS,OAAAD,EAAAD,EAAKE,QAALD,EAAe1C,EAAQ2C,OACtC,IAAKA,EACH,MAAM,IAAIC,MAAM,oEAClB,OAAOD,GAgBHE,EAAWJ,GACf,IAAI3B,QAASC,IAnEnB,IAAA2B,EAoEQ,GAAoC,oBAAzBI,qBAAsC,OAAO/B,GAAQ,GAChE,IAAIgC,GAAO,EACX,MAAMC,EAAW,IAAIF,qBAClBG,IACKA,EAAQC,KAAMC,GAAUA,EAAMC,oBAAwB,IAE5D,CAAEC,UAAW,OAAAX,EAAAD,EAAKY,aAAa,KAE3BC,EAAUtC,IACV+B,IACJA,GAAO,EACPC,EAASO,aACTzB,EAAY0B,OAAOnB,GACnBtB,EAAQC,KAEJqB,EAAS,IAAMiB,GAAO,GAC5BxB,EAAY2B,IAAIpB,GAChB,MAAMM,EACuB,iBAApBH,EAAUC,GACbiB,SAASC,cAAcnB,EAAUC,IACjCD,EAAUC,GAChB,IAAKE,EAAQ,MAAM,IAAIC,MAAM,mDAC7BI,EAASY,QAAQjB,KAEfkB,EAAiBpB,GAASqB,EAAA,KAAA,KAAA,YA5FpC,IAAApB,EAAAqB,EAoDkBC,EAyCZ,IAAKvB,GAAwB,iBAATA,EAClB,MAAM,IAAInC,UAAU,oCACtB,GAAkB,UAAdmC,EAAKxC,KAAkB,MAAO,CAAEe,gBA3CxBgD,EA2C8CvB,EAAKuB,SA1C/D,IAAIlD,QAASC,IACX,IAAIgC,GAAO,EACX,MAAMO,EAAUtC,IACV+B,IACJA,GAAO,EACPkB,aAAaC,GACbpC,EAAY0B,OAAOnB,GACnBtB,EAAQC,KAEJkD,EAAKC,WAAW,IAAMb,GAAO,GAAO/B,KAAKC,IAAI,EAAGJ,OAAO4C,IAAa,IACpE3B,EAAS,IAAMiB,GAAO,GAC5BxB,EAAY2B,IAAIpB,MA+BwDpB,KAAM,IAChF,GAAkB,YAAdwB,EAAKxC,KAAoB,MAAO,CAAEe,gBAAiB6B,EAAQJ,GAAOxB,KAAM,IAC5E,GAAkB,SAAdwB,EAAKxC,KAEP,aADMwC,EAAK2B,KACJ,CAAEpD,WAAW,EAAMC,KAAM,IAElC,IAAImB,EACJ,GAAkB,SAAdK,EAAKxC,KAAiBmC,EAAQjC,EAAOC,KAAKoC,EAAUC,GAAOA,EAAKxB,KAAMwB,EAAK4B,aAAM,GAC9D,UAAd5B,EAAKxC,KAAkBmC,EAAQjC,EAAOE,MAAMmC,EAAUC,GAAOA,EAAK4B,YAAM,IAC1D,aAAd5B,EAAKxC,KAMZ,MAAM,IAAIK,UAAU,8CAA8CgE,OAAO7B,EAAKxC,YAL9EmC,EAAQ7B,EAASkC,EAAK1C,4HAAOwE,CAAA,CAAA,EACxB9B,EAAKzC,WADmB,CAE3B2C,OAAQ,OAAAoB,EAAA,OAAArB,EAAAD,EAAKzC,cAAL,EAAA0C,EAAcC,UAAU3C,EAAQ2C,mBAG8C,SAC1Ff,EAAe6B,IAAIrB,GACnB,IACE,aAAaA,EAAMvB,OACrB,CAAA,QACEe,EAAe4B,OAAOpB,EACxB,CACF,GA2BA,OAVAG,EAAW1B,QAAUC,QAAQ0D,IAAI/D,MAAMgE,KAAK,CAAE9D,OAAQU,GAhBvC,IAAYyC,EAAA,KAAA,KAAA,YACzB,MAAQ7B,GAAQ,CACd,MAAMyC,EAAQ3C,IACd,GAAI2C,GAASlE,EAAMG,OAAQ,OAC3B,IACE,MAAMgE,QAAcd,EAAQrD,EAAMkE,IAClCxD,EAAQwD,GAAS,CAAEE,OAAQD,EAAM3D,UAAY,YAAc,cAAe2D,QAC5E,OAASE,GACP3D,EAAQwD,GAAS,CAAEE,OAAQ,WAAYE,OAAQD,EACjD,CAC8B,cAA1B3D,EAAQwD,GAAOE,QAAyC,cAAfjD,IAC3CM,GAAS,EACTC,IAEJ,CACF,KAC8E6C,KAAK,KACjF,IAAA,IAASL,EAAQ,EAAGA,EAAQlE,EAAMG,OAAQ+D,GAAS,EACjD,MAAAxD,EAAAwD,KAAAxD,EAAAwD,GAAmB,CAAEE,OAAQ,cAAeD,MAAO,CAAE3D,WAAW,EAAOC,KAAM,MAE/E,MAAO,CACLD,WAAYgB,GAAed,EAAQ8D,MAAM,EAAGJ,YAAwB,cAAXA,GACzD3D,KAAM,GACNC,aAGGqB,GAET,OAAOhC,CACT,CAGO,SAAS0E,EAAgB9E,EAAQ+E,GACtC,MAAM3E,EAAWL,EAAeC,GAIhC,OAHAgF,OAAOC,eAAejF,EAAQ,WAAY,CAAEkF,cAAc,EAAMV,MAAOpE,IACnE2E,GACFC,OAAOC,eAAeF,EAAiB,WAAY,CAAEG,cAAc,EAAMV,MAAO7E,IAC3EK,CACT"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=Object.defineProperty,t=Object.defineProperties,r=Object.getOwnPropertyDescriptors,l=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,i=(t,r,l)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:l}):t[r]=l,a=(e,t,r)=>new Promise((l,n)=>{var o=e=>{try{a(r.next(e))}catch(e){n(e)}},i=e=>{try{a(r.throw(e))}catch(e){n(e)}},a=e=>e.done?l(e.value):Promise.resolve(e.value).then(o,i);a((r=r.apply(e,t)).next())});const s=(e,t)=>({kind:"parallel",steps:e,options:t});function u(e){if(!(null==e?void 0:e.type)||!(null==e?void 0:e.erase))throw new TypeError("TypeFlow parallel: a TypeFlow engine instance is required.");const s=(u,p={})=>{const c=Array.isArray(u)?u:[];if(0===c.length)return{stop:()=>{},promise:Promise.resolve({completed:!0,text:"",results:[]})};const d=Number(p.concurrency),f=Number.isFinite(d)?Math.max(1,Math.min(c.length,Math.floor(d))):c.length,y="fail-fast"===p.settlement?"fail-fast":"all-settled",m=new Set,h=new Set,w=new Array(c.length);let v=0,g=!1,b=!1;const O=()=>{m.forEach(e=>e.stop()),h.forEach(e=>e()),m.clear(),h.clear()},P={stop:()=>{g||(g=!0,b=!0,O())},promise:null},x=e=>{var t;const r=null!=(t=e.target)?t:p.target;if(!r)throw new Error("TypeFlow parallel: a step requires a target or default `target`.");return r},T=e=>new Promise(t=>{var r;if("undefined"==typeof IntersectionObserver)return t(!0);let l=!1;const n=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&o(!0)},{threshold:null!=(r=e.threshold)?r:.1}),o=e=>{l||(l=!0,n.disconnect(),h.delete(i),t(e))},i=()=>o(!1);h.add(i);const a="string"==typeof x(e)?document.querySelector(x(e)):x(e);if(!a)throw new Error("TypeFlow parallel: visibility target not found.");n.observe(a)}),j=u=>a(null,null,function*(){var a,c,d;if(!u||"object"!=typeof u)throw new TypeError("TypeFlow parallel: invalid step.");if("pause"===u.kind)return{completed:yield(d=u.duration,new Promise(e=>{let t=!1;const r=r=>{t||(t=!0,clearTimeout(l),h.delete(n),e(r))},l=setTimeout(()=>r(!0),Math.max(0,Number(d)||0)),n=()=>r(!1);h.add(n)})),text:""};if("visible"===u.kind)return{completed:yield T(u),text:""};if("call"===u.kind)return yield u.fn(),{completed:!0,text:""};let f;if("type"===u.kind)f=e.type(x(u),u.text,u.config);else if("erase"===u.kind)f=e.erase(x(u),u.config);else{if("parallel"!==u.kind)throw new TypeError(`TypeFlow parallel: unsupported step kind \`${String(u.kind)}\`.`);f=s(u.steps,(y=((e,t)=>{for(var r in t||(t={}))n.call(t,r)&&i(e,r,t[r]);if(l)for(var r of l(t))o.call(t,r)&&i(e,r,t[r]);return e})({},u.options),w={target:null!=(c=null==(a=u.options)?void 0:a.target)?c:p.target},t(y,r(w))))}var y,w;m.add(f);try{return yield f.promise}finally{m.delete(f)}});return P.promise=Promise.all(Array.from({length:f},()=>a(null,null,function*(){for(;!b;){const e=v++;if(e>=c.length)return;try{const t=yield j(c[e]);w[e]={status:t.completed?"fulfilled":"interrupted",value:t}}catch(t){w[e]={status:"rejected",reason:t}}"fulfilled"!==w[e].status&&"fail-fast"===y&&(b=!0,O())}}))).then(()=>{for(let e=0;e<c.length;e+=1)null!=w[e]||(w[e]={status:"interrupted",value:{completed:!1,text:""}});return{completed:!g&&w.every(({status:e})=>"fulfilled"===e),text:"",results:w}}),P};return s}function p(e,t){const r=u(e);return Object.defineProperty(e,"parallel",{configurable:!0,value:r}),t&&Object.defineProperty(t,"parallel",{configurable:!0,value:s}),e}export{u as createParallel,p as installParallel,s as parallelStep};
|
|
2
|
+
//# sourceMappingURL=typeflow-parallel.esm.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeflow-parallel.esm.min.js","sources":["../../../src/typeflow-parallel.js"],"sourcesContent":["/**\n * EXPERIMENTAL opt-in parallel orchestration for TypeFlow.\n * This module intentionally does not import core, keeping stable bundles small.\n */\n\nexport const parallelStep = (steps, options) => ({ kind: 'parallel', steps, options });\n\nexport function createParallel(engine) {\n if (!engine?.type || !engine?.erase)\n throw new TypeError('TypeFlow parallel: a TypeFlow engine instance is required.');\n\n const parallel = (steps, options = {}) => {\n const input = Array.isArray(steps) ? steps : [];\n if (input.length === 0)\n return {\n stop: () => {},\n promise: Promise.resolve({ completed: true, text: '', results: [] }),\n };\n\n const requested = Number(options.concurrency);\n const concurrency = Number.isFinite(requested)\n ? Math.max(1, Math.min(input.length, Math.floor(requested)))\n : input.length;\n const settlement = options.settlement === 'fail-fast' ? 'fail-fast' : 'all-settled';\n const activeChildren = new Set();\n const cancelWaits = new Set();\n const results = new Array(input.length);\n let nextIndex = 0;\n let interrupted = false;\n let halted = false;\n\n const stopActive = () => {\n activeChildren.forEach((child) => child.stop());\n cancelWaits.forEach((cancel) => cancel());\n activeChildren.clear();\n cancelWaits.clear();\n };\n const controller = {\n stop: () => {\n if (interrupted) return;\n interrupted = true;\n halted = true;\n stopActive();\n },\n promise: null,\n };\n const targetFor = (step) => {\n const target = step.target ?? options.target;\n if (!target)\n throw new Error('TypeFlow parallel: a step requires a target or default `target`.');\n return target;\n };\n const wait = (duration) =>\n new Promise((resolve) => {\n let done = false;\n const finish = (completed) => {\n if (done) return;\n done = true;\n clearTimeout(id);\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const id = setTimeout(() => finish(true), Math.max(0, Number(duration) || 0));\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n });\n const visible = (step) =>\n new Promise((resolve) => {\n if (typeof IntersectionObserver === 'undefined') return resolve(true);\n let done = false;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) finish(true);\n },\n { threshold: step.threshold ?? 0.1 }\n );\n const finish = (completed) => {\n if (done) return;\n done = true;\n observer.disconnect();\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n const target =\n typeof targetFor(step) === 'string'\n ? document.querySelector(targetFor(step))\n : targetFor(step);\n if (!target) throw new Error('TypeFlow parallel: visibility target not found.');\n observer.observe(target);\n });\n const runStep = async (step) => {\n if (!step || typeof step !== 'object')\n throw new TypeError('TypeFlow parallel: invalid step.');\n if (step.kind === 'pause') return { completed: await wait(step.duration), text: '' };\n if (step.kind === 'visible') return { completed: await visible(step), text: '' };\n if (step.kind === 'call') {\n await step.fn();\n return { completed: true, text: '' };\n }\n let child;\n if (step.kind === 'type') child = engine.type(targetFor(step), step.text, step.config);\n else if (step.kind === 'erase') child = engine.erase(targetFor(step), step.config);\n else if (step.kind === 'parallel')\n child = parallel(step.steps, {\n ...step.options,\n target: step.options?.target ?? options.target,\n });\n else\n throw new TypeError(`TypeFlow parallel: unsupported step kind \\`${String(step.kind)}\\`.`);\n activeChildren.add(child);\n try {\n return await child.promise;\n } finally {\n activeChildren.delete(child);\n }\n };\n const worker = async () => {\n while (!halted) {\n const index = nextIndex++;\n if (index >= input.length) return;\n try {\n const value = await runStep(input[index]);\n results[index] = { status: value.completed ? 'fulfilled' : 'interrupted', value };\n } catch (error) {\n results[index] = { status: 'rejected', reason: error };\n }\n if (results[index].status !== 'fulfilled' && settlement === 'fail-fast') {\n halted = true;\n stopActive();\n }\n }\n };\n controller.promise = Promise.all(Array.from({ length: concurrency }, worker)).then(() => {\n for (let index = 0; index < input.length; index += 1) {\n results[index] ??= { status: 'interrupted', value: { completed: false, text: '' } };\n }\n return {\n completed: !interrupted && results.every(({ status }) => status === 'fulfilled'),\n text: '',\n results,\n };\n });\n return controller;\n };\n return parallel;\n}\n\n/** Explicitly installs the experimental methods onto caller-provided core objects. */\nexport function installParallel(engine, sequenceHelpers) {\n const parallel = createParallel(engine);\n Object.defineProperty(engine, 'parallel', { configurable: true, value: parallel });\n if (sequenceHelpers)\n Object.defineProperty(sequenceHelpers, 'parallel', { configurable: true, value: parallelStep });\n return engine;\n}\n"],"names":["parallelStep","steps","options","kind","createParallel","engine","type","erase","TypeError","parallel","input","Array","isArray","length","stop","promise","Promise","resolve","completed","text","results","requested","Number","concurrency","isFinite","Math","max","min","floor","settlement","activeChildren","Set","cancelWaits","nextIndex","interrupted","halted","stopActive","forEach","child","cancel","clear","controller","targetFor","step","_a","target","Error","visible","IntersectionObserver","done","observer","entries","some","entry","isIntersecting","threshold","finish","disconnect","delete","add","document","querySelector","observe","runStep","__async","_b","duration","clearTimeout","id","setTimeout","fn","config","String","__spreadValues","all","from","index","value","status","error","reason","then","every","installParallel","sequenceHelpers","Object","defineProperty","configurable"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/*! typeflow-parallel | MIT */
|
|
2
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TypeflowParallel={})}(this,function(e){"use strict";var t=Object.defineProperty,r=Object.defineProperties,l=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,a=(e,r,l)=>r in e?t(e,r,{enumerable:!0,configurable:!0,writable:!0,value:l}):e[r]=l,s=(e,t,r)=>new Promise((l,n)=>{var o=e=>{try{a(r.next(e))}catch(e){n(e)}},i=e=>{try{a(r.throw(e))}catch(e){n(e)}},a=e=>e.done?l(e.value):Promise.resolve(e.value).then(o,i);a((r=r.apply(e,t)).next())});const u=(e,t)=>({kind:"parallel",steps:e,options:t});function p(e){if(!(null==e?void 0:e.type)||!(null==e?void 0:e.erase))throw new TypeError("TypeFlow parallel: a TypeFlow engine instance is required.");const t=(u,p={})=>{const c=Array.isArray(u)?u:[];if(0===c.length)return{stop:()=>{},promise:Promise.resolve({completed:!0,text:"",results:[]})};const f=Number(p.concurrency),d=Number.isFinite(f)?Math.max(1,Math.min(c.length,Math.floor(f))):c.length,y="fail-fast"===p.settlement?"fail-fast":"all-settled",m=new Set,h=new Set,g=new Array(c.length);let b=0,w=!1,v=!1;const P=()=>{m.forEach(e=>e.stop()),h.forEach(e=>e()),m.clear(),h.clear()},T={stop:()=>{w||(w=!0,v=!0,P())},promise:null},x=e=>{var t;const r=null!=(t=e.target)?t:p.target;if(!r)throw new Error("TypeFlow parallel: a step requires a target or default `target`.");return r},O=e=>new Promise(t=>{var r;if("undefined"==typeof IntersectionObserver)return t(!0);let l=!1;const n=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&o(!0)},{threshold:null!=(r=e.threshold)?r:.1}),o=e=>{l||(l=!0,n.disconnect(),h.delete(i),t(e))},i=()=>o(!1);h.add(i);const a="string"==typeof x(e)?document.querySelector(x(e)):x(e);if(!a)throw new Error("TypeFlow parallel: visibility target not found.");n.observe(a)}),j=u=>s(null,null,function*(){var s,c,f;if(!u||"object"!=typeof u)throw new TypeError("TypeFlow parallel: invalid step.");if("pause"===u.kind)return{completed:yield(f=u.duration,new Promise(e=>{let t=!1;const r=r=>{t||(t=!0,clearTimeout(l),h.delete(n),e(r))},l=setTimeout(()=>r(!0),Math.max(0,Number(f)||0)),n=()=>r(!1);h.add(n)})),text:""};if("visible"===u.kind)return{completed:yield O(u),text:""};if("call"===u.kind)return yield u.fn(),{completed:!0,text:""};let d;if("type"===u.kind)d=e.type(x(u),u.text,u.config);else if("erase"===u.kind)d=e.erase(x(u),u.config);else{if("parallel"!==u.kind)throw new TypeError(`TypeFlow parallel: unsupported step kind \`${String(u.kind)}\`.`);d=t(u.steps,(y=((e,t)=>{for(var r in t||(t={}))o.call(t,r)&&a(e,r,t[r]);if(n)for(var r of n(t))i.call(t,r)&&a(e,r,t[r]);return e})({},u.options),g={target:null!=(c=null==(s=u.options)?void 0:s.target)?c:p.target},r(y,l(g))))}var y,g;m.add(d);try{return yield d.promise}finally{m.delete(d)}});return T.promise=Promise.all(Array.from({length:d},()=>s(null,null,function*(){for(;!v;){const e=b++;if(e>=c.length)return;try{const t=yield j(c[e]);g[e]={status:t.completed?"fulfilled":"interrupted",value:t}}catch(t){g[e]={status:"rejected",reason:t}}"fulfilled"!==g[e].status&&"fail-fast"===y&&(v=!0,P())}}))).then(()=>{for(let e=0;e<c.length;e+=1)null!=g[e]||(g[e]={status:"interrupted",value:{completed:!1,text:""}});return{completed:!w&&g.every(({status:e})=>"fulfilled"===e),text:"",results:g}}),T};return t}e.createParallel=p,e.installParallel=function(e,t){const r=p(e);return Object.defineProperty(e,"parallel",{configurable:!0,value:r}),t&&Object.defineProperty(t,"parallel",{configurable:!0,value:u}),e},e.parallelStep=u,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
|
|
3
|
+
//# sourceMappingURL=typeflow-parallel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeflow-parallel.js","sources":["../../../src/typeflow-parallel.js"],"sourcesContent":["/**\n * EXPERIMENTAL opt-in parallel orchestration for TypeFlow.\n * This module intentionally does not import core, keeping stable bundles small.\n */\n\nexport const parallelStep = (steps, options) => ({ kind: 'parallel', steps, options });\n\nexport function createParallel(engine) {\n if (!engine?.type || !engine?.erase)\n throw new TypeError('TypeFlow parallel: a TypeFlow engine instance is required.');\n\n const parallel = (steps, options = {}) => {\n const input = Array.isArray(steps) ? steps : [];\n if (input.length === 0)\n return {\n stop: () => {},\n promise: Promise.resolve({ completed: true, text: '', results: [] }),\n };\n\n const requested = Number(options.concurrency);\n const concurrency = Number.isFinite(requested)\n ? Math.max(1, Math.min(input.length, Math.floor(requested)))\n : input.length;\n const settlement = options.settlement === 'fail-fast' ? 'fail-fast' : 'all-settled';\n const activeChildren = new Set();\n const cancelWaits = new Set();\n const results = new Array(input.length);\n let nextIndex = 0;\n let interrupted = false;\n let halted = false;\n\n const stopActive = () => {\n activeChildren.forEach((child) => child.stop());\n cancelWaits.forEach((cancel) => cancel());\n activeChildren.clear();\n cancelWaits.clear();\n };\n const controller = {\n stop: () => {\n if (interrupted) return;\n interrupted = true;\n halted = true;\n stopActive();\n },\n promise: null,\n };\n const targetFor = (step) => {\n const target = step.target ?? options.target;\n if (!target)\n throw new Error('TypeFlow parallel: a step requires a target or default `target`.');\n return target;\n };\n const wait = (duration) =>\n new Promise((resolve) => {\n let done = false;\n const finish = (completed) => {\n if (done) return;\n done = true;\n clearTimeout(id);\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const id = setTimeout(() => finish(true), Math.max(0, Number(duration) || 0));\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n });\n const visible = (step) =>\n new Promise((resolve) => {\n if (typeof IntersectionObserver === 'undefined') return resolve(true);\n let done = false;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) finish(true);\n },\n { threshold: step.threshold ?? 0.1 }\n );\n const finish = (completed) => {\n if (done) return;\n done = true;\n observer.disconnect();\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n const target =\n typeof targetFor(step) === 'string'\n ? document.querySelector(targetFor(step))\n : targetFor(step);\n if (!target) throw new Error('TypeFlow parallel: visibility target not found.');\n observer.observe(target);\n });\n const runStep = async (step) => {\n if (!step || typeof step !== 'object')\n throw new TypeError('TypeFlow parallel: invalid step.');\n if (step.kind === 'pause') return { completed: await wait(step.duration), text: '' };\n if (step.kind === 'visible') return { completed: await visible(step), text: '' };\n if (step.kind === 'call') {\n await step.fn();\n return { completed: true, text: '' };\n }\n let child;\n if (step.kind === 'type') child = engine.type(targetFor(step), step.text, step.config);\n else if (step.kind === 'erase') child = engine.erase(targetFor(step), step.config);\n else if (step.kind === 'parallel')\n child = parallel(step.steps, {\n ...step.options,\n target: step.options?.target ?? options.target,\n });\n else\n throw new TypeError(`TypeFlow parallel: unsupported step kind \\`${String(step.kind)}\\`.`);\n activeChildren.add(child);\n try {\n return await child.promise;\n } finally {\n activeChildren.delete(child);\n }\n };\n const worker = async () => {\n while (!halted) {\n const index = nextIndex++;\n if (index >= input.length) return;\n try {\n const value = await runStep(input[index]);\n results[index] = { status: value.completed ? 'fulfilled' : 'interrupted', value };\n } catch (error) {\n results[index] = { status: 'rejected', reason: error };\n }\n if (results[index].status !== 'fulfilled' && settlement === 'fail-fast') {\n halted = true;\n stopActive();\n }\n }\n };\n controller.promise = Promise.all(Array.from({ length: concurrency }, worker)).then(() => {\n for (let index = 0; index < input.length; index += 1) {\n results[index] ??= { status: 'interrupted', value: { completed: false, text: '' } };\n }\n return {\n completed: !interrupted && results.every(({ status }) => status === 'fulfilled'),\n text: '',\n results,\n };\n });\n return controller;\n };\n return parallel;\n}\n\n/** Explicitly installs the experimental methods onto caller-provided core objects. */\nexport function installParallel(engine, sequenceHelpers) {\n const parallel = createParallel(engine);\n Object.defineProperty(engine, 'parallel', { configurable: true, value: parallel });\n if (sequenceHelpers)\n Object.defineProperty(sequenceHelpers, 'parallel', { configurable: true, value: parallelStep });\n return engine;\n}\n"],"names":["parallelStep","steps","options","kind","createParallel","engine","type","erase","TypeError","parallel","input","Array","isArray","length","stop","promise","Promise","resolve","completed","text","results","requested","Number","concurrency","isFinite","Math","max","min","floor","settlement","activeChildren","Set","cancelWaits","nextIndex","interrupted","halted","stopActive","forEach","child","cancel","clear","controller","targetFor","step","target","_a","Error","visible","IntersectionObserver","done","observer","entries","some","entry","isIntersecting","threshold","finish","disconnect","delete","add","document","querySelector","observe","runStep","__async","duration","clearTimeout","id","setTimeout","fn","config","String","__spreadValues","_b","all","from","index","value","status","error","reason","then","every","sequenceHelpers","Object","defineProperty","configurable"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TypeflowParallel={})}(this,function(e){"use strict";var t=Object.defineProperty,r=Object.defineProperties,l=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,a=(e,r,l)=>r in e?t(e,r,{enumerable:!0,configurable:!0,writable:!0,value:l}):e[r]=l,s=(e,t,r)=>new Promise((l,n)=>{var o=e=>{try{a(r.next(e))}catch(e){n(e)}},i=e=>{try{a(r.throw(e))}catch(e){n(e)}},a=e=>e.done?l(e.value):Promise.resolve(e.value).then(o,i);a((r=r.apply(e,t)).next())});const u=(e,t)=>({kind:"parallel",steps:e,options:t});function p(e){if(!(null==e?void 0:e.type)||!(null==e?void 0:e.erase))throw new TypeError("TypeFlow parallel: a TypeFlow engine instance is required.");const t=(u,p={})=>{const c=Array.isArray(u)?u:[];if(0===c.length)return{stop:()=>{},promise:Promise.resolve({completed:!0,text:"",results:[]})};const f=Number(p.concurrency),d=Number.isFinite(f)?Math.max(1,Math.min(c.length,Math.floor(f))):c.length,y="fail-fast"===p.settlement?"fail-fast":"all-settled",m=new Set,h=new Set,g=new Array(c.length);let b=0,w=!1,v=!1;const P=()=>{m.forEach(e=>e.stop()),h.forEach(e=>e()),m.clear(),h.clear()},T={stop:()=>{w||(w=!0,v=!0,P())},promise:null},x=e=>{var t;const r=null!=(t=e.target)?t:p.target;if(!r)throw new Error("TypeFlow parallel: a step requires a target or default `target`.");return r},O=e=>new Promise(t=>{var r;if("undefined"==typeof IntersectionObserver)return t(!0);let l=!1;const n=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&o(!0)},{threshold:null!=(r=e.threshold)?r:.1}),o=e=>{l||(l=!0,n.disconnect(),h.delete(i),t(e))},i=()=>o(!1);h.add(i);const a="string"==typeof x(e)?document.querySelector(x(e)):x(e);if(!a)throw new Error("TypeFlow parallel: visibility target not found.");n.observe(a)}),j=u=>s(null,null,function*(){var s,c,f;if(!u||"object"!=typeof u)throw new TypeError("TypeFlow parallel: invalid step.");if("pause"===u.kind)return{completed:yield(f=u.duration,new Promise(e=>{let t=!1;const r=r=>{t||(t=!0,clearTimeout(l),h.delete(n),e(r))},l=setTimeout(()=>r(!0),Math.max(0,Number(f)||0)),n=()=>r(!1);h.add(n)})),text:""};if("visible"===u.kind)return{completed:yield O(u),text:""};if("call"===u.kind)return yield u.fn(),{completed:!0,text:""};let d;if("type"===u.kind)d=e.type(x(u),u.text,u.config);else if("erase"===u.kind)d=e.erase(x(u),u.config);else{if("parallel"!==u.kind)throw new TypeError(`TypeFlow parallel: unsupported step kind \`${String(u.kind)}\`.`);d=t(u.steps,(y=((e,t)=>{for(var r in t||(t={}))o.call(t,r)&&a(e,r,t[r]);if(n)for(var r of n(t))i.call(t,r)&&a(e,r,t[r]);return e})({},u.options),g={target:null!=(c=null==(s=u.options)?void 0:s.target)?c:p.target},r(y,l(g))))}var y,g;m.add(d);try{return yield d.promise}finally{m.delete(d)}});return T.promise=Promise.all(Array.from({length:d},()=>s(null,null,function*(){for(;!v;){const e=b++;if(e>=c.length)return;try{const t=yield j(c[e]);g[e]={status:t.completed?"fulfilled":"interrupted",value:t}}catch(t){g[e]={status:"rejected",reason:t}}"fulfilled"!==g[e].status&&"fail-fast"===y&&(v=!0,P())}}))).then(()=>{for(let e=0;e<c.length;e+=1)null!=g[e]||(g[e]={status:"interrupted",value:{completed:!1,text:""}});return{completed:!w&&g.every(({status:e})=>"fulfilled"===e),text:"",results:g}}),T};return t}e.createParallel=p,e.installParallel=function(e,t){const r=p(e);return Object.defineProperty(e,"parallel",{configurable:!0,value:r}),t&&Object.defineProperty(t,"parallel",{configurable:!0,value:u}),e},e.parallelStep=u,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
|
|
2
|
+
//# sourceMappingURL=typeflow-parallel.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeflow-parallel.min.js","sources":["../../../src/typeflow-parallel.js"],"sourcesContent":["/**\n * EXPERIMENTAL opt-in parallel orchestration for TypeFlow.\n * This module intentionally does not import core, keeping stable bundles small.\n */\n\nexport const parallelStep = (steps, options) => ({ kind: 'parallel', steps, options });\n\nexport function createParallel(engine) {\n if (!engine?.type || !engine?.erase)\n throw new TypeError('TypeFlow parallel: a TypeFlow engine instance is required.');\n\n const parallel = (steps, options = {}) => {\n const input = Array.isArray(steps) ? steps : [];\n if (input.length === 0)\n return {\n stop: () => {},\n promise: Promise.resolve({ completed: true, text: '', results: [] }),\n };\n\n const requested = Number(options.concurrency);\n const concurrency = Number.isFinite(requested)\n ? Math.max(1, Math.min(input.length, Math.floor(requested)))\n : input.length;\n const settlement = options.settlement === 'fail-fast' ? 'fail-fast' : 'all-settled';\n const activeChildren = new Set();\n const cancelWaits = new Set();\n const results = new Array(input.length);\n let nextIndex = 0;\n let interrupted = false;\n let halted = false;\n\n const stopActive = () => {\n activeChildren.forEach((child) => child.stop());\n cancelWaits.forEach((cancel) => cancel());\n activeChildren.clear();\n cancelWaits.clear();\n };\n const controller = {\n stop: () => {\n if (interrupted) return;\n interrupted = true;\n halted = true;\n stopActive();\n },\n promise: null,\n };\n const targetFor = (step) => {\n const target = step.target ?? options.target;\n if (!target)\n throw new Error('TypeFlow parallel: a step requires a target or default `target`.');\n return target;\n };\n const wait = (duration) =>\n new Promise((resolve) => {\n let done = false;\n const finish = (completed) => {\n if (done) return;\n done = true;\n clearTimeout(id);\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const id = setTimeout(() => finish(true), Math.max(0, Number(duration) || 0));\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n });\n const visible = (step) =>\n new Promise((resolve) => {\n if (typeof IntersectionObserver === 'undefined') return resolve(true);\n let done = false;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) finish(true);\n },\n { threshold: step.threshold ?? 0.1 }\n );\n const finish = (completed) => {\n if (done) return;\n done = true;\n observer.disconnect();\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n const target =\n typeof targetFor(step) === 'string'\n ? document.querySelector(targetFor(step))\n : targetFor(step);\n if (!target) throw new Error('TypeFlow parallel: visibility target not found.');\n observer.observe(target);\n });\n const runStep = async (step) => {\n if (!step || typeof step !== 'object')\n throw new TypeError('TypeFlow parallel: invalid step.');\n if (step.kind === 'pause') return { completed: await wait(step.duration), text: '' };\n if (step.kind === 'visible') return { completed: await visible(step), text: '' };\n if (step.kind === 'call') {\n await step.fn();\n return { completed: true, text: '' };\n }\n let child;\n if (step.kind === 'type') child = engine.type(targetFor(step), step.text, step.config);\n else if (step.kind === 'erase') child = engine.erase(targetFor(step), step.config);\n else if (step.kind === 'parallel')\n child = parallel(step.steps, {\n ...step.options,\n target: step.options?.target ?? options.target,\n });\n else\n throw new TypeError(`TypeFlow parallel: unsupported step kind \\`${String(step.kind)}\\`.`);\n activeChildren.add(child);\n try {\n return await child.promise;\n } finally {\n activeChildren.delete(child);\n }\n };\n const worker = async () => {\n while (!halted) {\n const index = nextIndex++;\n if (index >= input.length) return;\n try {\n const value = await runStep(input[index]);\n results[index] = { status: value.completed ? 'fulfilled' : 'interrupted', value };\n } catch (error) {\n results[index] = { status: 'rejected', reason: error };\n }\n if (results[index].status !== 'fulfilled' && settlement === 'fail-fast') {\n halted = true;\n stopActive();\n }\n }\n };\n controller.promise = Promise.all(Array.from({ length: concurrency }, worker)).then(() => {\n for (let index = 0; index < input.length; index += 1) {\n results[index] ??= { status: 'interrupted', value: { completed: false, text: '' } };\n }\n return {\n completed: !interrupted && results.every(({ status }) => status === 'fulfilled'),\n text: '',\n results,\n };\n });\n return controller;\n };\n return parallel;\n}\n\n/** Explicitly installs the experimental methods onto caller-provided core objects. */\nexport function installParallel(engine, sequenceHelpers) {\n const parallel = createParallel(engine);\n Object.defineProperty(engine, 'parallel', { configurable: true, value: parallel });\n if (sequenceHelpers)\n Object.defineProperty(sequenceHelpers, 'parallel', { configurable: true, value: parallelStep });\n return engine;\n}\n"],"names":["parallelStep","steps","options","kind","createParallel","engine","type","erase","TypeError","parallel","input","Array","isArray","length","stop","promise","Promise","resolve","completed","text","results","requested","Number","concurrency","isFinite","Math","max","min","floor","settlement","activeChildren","Set","cancelWaits","nextIndex","interrupted","halted","stopActive","forEach","child","cancel","clear","controller","targetFor","step","target","_a","Error","visible","IntersectionObserver","done","observer","entries","some","entry","isIntersecting","threshold","finish","disconnect","delete","add","document","querySelector","observe","runStep","__async","duration","clearTimeout","id","setTimeout","fn","config","String","__spreadValues","_b","all","from","index","value","status","error","reason","then","every","sequenceHelpers","Object","defineProperty","configurable"],"mappings":"stBAKY,MAACA,EAAe,CAACC,EAAOC,KAAA,CAAeC,KAAM,WAAYF,QAAOC,YAErE,SAASE,EAAeC,GAC7B,KAAK,MAAAA,OAAA,EAAAA,EAAQC,SAAS,MAAAD,OAAA,EAAAA,EAAQE,OAC5B,MAAM,IAAIC,UAAU,8DAEtB,MAAMC,EAAW,CAACR,EAAOC,EAAU,CAAA,KACjC,MAAMQ,EAAQC,MAAMC,QAAQX,GAASA,EAAQ,GAC7C,GAAqB,IAAjBS,EAAMG,OACR,MAAO,CACLC,KAAM,OACNC,QAASC,QAAQC,QAAQ,CAAEC,WAAW,EAAMC,KAAM,GAAIC,QAAS,MAGnE,MAAMC,EAAYC,OAAOpB,EAAQqB,aAC3BA,EAAcD,OAAOE,SAASH,GAChCI,KAAKC,IAAI,EAAGD,KAAKE,IAAIjB,EAAMG,OAAQY,KAAKG,MAAMP,KAC9CX,EAAMG,OACJgB,EAAoC,cAAvB3B,EAAQ2B,WAA6B,YAAc,cAChEC,MAAqBC,IACrBC,MAAkBD,IAClBX,EAAU,IAAIT,MAAMD,EAAMG,QAChC,IAAIoB,EAAY,EACZC,GAAc,EACdC,GAAS,EAEb,MAAMC,EAAa,KACjBN,EAAeO,QAASC,GAAUA,EAAMxB,QACxCkB,EAAYK,QAASE,GAAWA,KAChCT,EAAeU,QACfR,EAAYQ,SAERC,EAAa,CACjB3B,KAAM,KACAoB,IACJA,GAAc,EACdC,GAAS,EACTC,MAEFrB,QAAS,MAEL2B,EAAaC,UACjB,MAAMC,EAAS,OAAAC,EAAAF,EAAKC,QAALC,EAAe3C,EAAQ0C,OACtC,IAAKA,EACH,MAAM,IAAIE,MAAM,oEAClB,OAAOF,GAgBHG,EAAWJ,GACf,IAAI3B,QAASC,UACX,GAAoC,oBAAzB+B,qBAAsC,OAAO/B,GAAQ,GAChE,IAAIgC,GAAO,EACX,MAAMC,EAAW,IAAIF,qBAClBG,IACKA,EAAQC,KAAMC,GAAUA,EAAMC,oBAAwB,IAE5D,CAAEC,UAAW,OAAAV,EAAAF,EAAKY,aAAa,KAE3BC,EAAUtC,IACV+B,IACJA,GAAO,EACPC,EAASO,aACTzB,EAAY0B,OAAOnB,GACnBtB,EAAQC,KAEJqB,EAAS,IAAMiB,GAAO,GAC5BxB,EAAY2B,IAAIpB,GAChB,MAAMK,EACuB,iBAApBF,EAAUC,GACbiB,SAASC,cAAcnB,EAAUC,IACjCD,EAAUC,GAChB,IAAKC,EAAQ,MAAM,IAAIE,MAAM,mDAC7BI,EAASY,QAAQlB,KAEfmB,EAAiBpB,GAASqB,EAAA,KAAA,KAAA,oBAxClBC,EAyCZ,IAAKtB,GAAwB,iBAATA,EAClB,MAAM,IAAInC,UAAU,oCACtB,GAAkB,UAAdmC,EAAKxC,KAAkB,MAAO,CAAEe,gBA3CxB+C,EA2C8CtB,EAAKsB,SA1C/D,IAAIjD,QAASC,IACX,IAAIgC,GAAO,EACX,MAAMO,EAAUtC,IACV+B,IACJA,GAAO,EACPiB,aAAaC,GACbnC,EAAY0B,OAAOnB,GACnBtB,EAAQC,KAEJiD,EAAKC,WAAW,IAAMZ,GAAO,GAAO/B,KAAKC,IAAI,EAAGJ,OAAO2C,IAAa,IACpE1B,EAAS,IAAMiB,GAAO,GAC5BxB,EAAY2B,IAAIpB,MA+BwDpB,KAAM,IAChF,GAAkB,YAAdwB,EAAKxC,KAAoB,MAAO,CAAEe,gBAAiB6B,EAAQJ,GAAOxB,KAAM,IAC5E,GAAkB,SAAdwB,EAAKxC,KAEP,aADMwC,EAAK0B,KACJ,CAAEnD,WAAW,EAAMC,KAAM,IAElC,IAAImB,EACJ,GAAkB,SAAdK,EAAKxC,KAAiBmC,EAAQjC,EAAOC,KAAKoC,EAAUC,GAAOA,EAAKxB,KAAMwB,EAAK2B,aAAM,GAC9D,UAAd3B,EAAKxC,KAAkBmC,EAAQjC,EAAOE,MAAMmC,EAAUC,GAAOA,EAAK2B,YAAM,IAC1D,aAAd3B,EAAKxC,KAMZ,MAAM,IAAIK,UAAU,8CAA8C+D,OAAO5B,EAAKxC,YAL9EmC,EAAQ7B,EAASkC,EAAK1C,4HAAOuE,CAAA,CAAA,EACxB7B,EAAKzC,WADmB,CAE3B0C,OAAQ,OAAA6B,EAAA,OAAA5B,EAAAF,EAAKzC,cAAL,EAAA2C,EAAcD,UAAU1C,EAAQ0C,mBAG8C,SAC1Fd,EAAe6B,IAAIrB,GACnB,IACE,aAAaA,EAAMvB,OACrB,CAAA,QACEe,EAAe4B,OAAOpB,EACxB,CACF,GA2BA,OAVAG,EAAW1B,QAAUC,QAAQ0D,IAAI/D,MAAMgE,KAAK,CAAE9D,OAAQU,GAhBvC,IAAYyC,EAAA,KAAA,KAAA,YACzB,MAAQ7B,GAAQ,CACd,MAAMyC,EAAQ3C,IACd,GAAI2C,GAASlE,EAAMG,OAAQ,OAC3B,IACE,MAAMgE,QAAcd,EAAQrD,EAAMkE,IAClCxD,EAAQwD,GAAS,CAAEE,OAAQD,EAAM3D,UAAY,YAAc,cAAe2D,QAC5E,OAASE,GACP3D,EAAQwD,GAAS,CAAEE,OAAQ,WAAYE,OAAQD,EACjD,CAC8B,cAA1B3D,EAAQwD,GAAOE,QAAyC,cAAfjD,IAC3CM,GAAS,EACTC,IAEJ,CACF,KAC8E6C,KAAK,KACjF,IAAA,IAASL,EAAQ,EAAGA,EAAQlE,EAAMG,OAAQ+D,GAAS,EACjD,MAAAxD,EAAAwD,KAAAxD,EAAAwD,GAAmB,CAAEE,OAAQ,cAAeD,MAAO,CAAE3D,WAAW,EAAOC,KAAM,MAE/E,MAAO,CACLD,WAAYgB,GAAed,EAAQ8D,MAAM,EAAGJ,YAAwB,cAAXA,GACzD3D,KAAM,GACNC,aAGGqB,GAET,OAAOhC,CACT,sCAGO,SAAyBJ,EAAQ8E,GACtC,MAAM1E,EAAWL,EAAeC,GAIhC,OAHA+E,OAAOC,eAAehF,EAAQ,WAAY,CAAEiF,cAAc,EAAMT,MAAOpE,IACnE0E,GACFC,OAAOC,eAAeF,EAAiB,WAAY,CAAEG,cAAc,EAAMT,MAAO7E,IAC3EK,CACT"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/*! typeflow-parallel | MIT */
|
|
2
|
+
var e=Object.defineProperty,t=Object.defineProperties,r=Object.getOwnPropertyDescriptors,l=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,i=(t,r,l)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:l}):t[r]=l,a=(e,t,r)=>new Promise((l,n)=>{var o=e=>{try{a(r.next(e))}catch(e){n(e)}},i=e=>{try{a(r.throw(e))}catch(e){n(e)}},a=e=>e.done?l(e.value):Promise.resolve(e.value).then(o,i);a((r=r.apply(e,t)).next())});const s=(e,t)=>({kind:"parallel",steps:e,options:t});function u(e){if(!(null==e?void 0:e.type)||!(null==e?void 0:e.erase))throw new TypeError("TypeFlow parallel: a TypeFlow engine instance is required.");const s=(u,p={})=>{const c=Array.isArray(u)?u:[];if(0===c.length)return{stop:()=>{},promise:Promise.resolve({completed:!0,text:"",results:[]})};const d=Number(p.concurrency),f=Number.isFinite(d)?Math.max(1,Math.min(c.length,Math.floor(d))):c.length,y="fail-fast"===p.settlement?"fail-fast":"all-settled",m=new Set,h=new Set,w=new Array(c.length);let v=0,g=!1,b=!1;const O=()=>{m.forEach(e=>e.stop()),h.forEach(e=>e()),m.clear(),h.clear()},P={stop:()=>{g||(g=!0,b=!0,O())},promise:null},x=e=>{var t;const r=null!=(t=e.target)?t:p.target;if(!r)throw new Error("TypeFlow parallel: a step requires a target or default `target`.");return r},T=e=>new Promise(t=>{var r;if("undefined"==typeof IntersectionObserver)return t(!0);let l=!1;const n=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&o(!0)},{threshold:null!=(r=e.threshold)?r:.1}),o=e=>{l||(l=!0,n.disconnect(),h.delete(i),t(e))},i=()=>o(!1);h.add(i);const a="string"==typeof x(e)?document.querySelector(x(e)):x(e);if(!a)throw new Error("TypeFlow parallel: visibility target not found.");n.observe(a)}),j=u=>a(null,null,function*(){var a,c,d;if(!u||"object"!=typeof u)throw new TypeError("TypeFlow parallel: invalid step.");if("pause"===u.kind)return{completed:yield(d=u.duration,new Promise(e=>{let t=!1;const r=r=>{t||(t=!0,clearTimeout(l),h.delete(n),e(r))},l=setTimeout(()=>r(!0),Math.max(0,Number(d)||0)),n=()=>r(!1);h.add(n)})),text:""};if("visible"===u.kind)return{completed:yield T(u),text:""};if("call"===u.kind)return yield u.fn(),{completed:!0,text:""};let f;if("type"===u.kind)f=e.type(x(u),u.text,u.config);else if("erase"===u.kind)f=e.erase(x(u),u.config);else{if("parallel"!==u.kind)throw new TypeError(`TypeFlow parallel: unsupported step kind \`${String(u.kind)}\`.`);f=s(u.steps,(y=((e,t)=>{for(var r in t||(t={}))n.call(t,r)&&i(e,r,t[r]);if(l)for(var r of l(t))o.call(t,r)&&i(e,r,t[r]);return e})({},u.options),w={target:null!=(c=null==(a=u.options)?void 0:a.target)?c:p.target},t(y,r(w))))}var y,w;m.add(f);try{return yield f.promise}finally{m.delete(f)}});return P.promise=Promise.all(Array.from({length:f},()=>a(null,null,function*(){for(;!b;){const e=v++;if(e>=c.length)return;try{const t=yield j(c[e]);w[e]={status:t.completed?"fulfilled":"interrupted",value:t}}catch(t){w[e]={status:"rejected",reason:t}}"fulfilled"!==w[e].status&&"fail-fast"===y&&(b=!0,O())}}))).then(()=>{for(let e=0;e<c.length;e+=1)null!=w[e]||(w[e]={status:"interrupted",value:{completed:!1,text:""}});return{completed:!g&&w.every(({status:e})=>"fulfilled"===e),text:"",results:w}}),P};return s}function p(e,t){const r=u(e);return Object.defineProperty(e,"parallel",{configurable:!0,value:r}),t&&Object.defineProperty(t,"parallel",{configurable:!0,value:s}),e}export{u as createParallel,p as installParallel,s as parallelStep};
|
|
3
|
+
//# sourceMappingURL=typeflow-parallel.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeflow-parallel.mjs","sources":["../../../src/typeflow-parallel.js"],"sourcesContent":["/**\n * EXPERIMENTAL opt-in parallel orchestration for TypeFlow.\n * This module intentionally does not import core, keeping stable bundles small.\n */\n\nexport const parallelStep = (steps, options) => ({ kind: 'parallel', steps, options });\n\nexport function createParallel(engine) {\n if (!engine?.type || !engine?.erase)\n throw new TypeError('TypeFlow parallel: a TypeFlow engine instance is required.');\n\n const parallel = (steps, options = {}) => {\n const input = Array.isArray(steps) ? steps : [];\n if (input.length === 0)\n return {\n stop: () => {},\n promise: Promise.resolve({ completed: true, text: '', results: [] }),\n };\n\n const requested = Number(options.concurrency);\n const concurrency = Number.isFinite(requested)\n ? Math.max(1, Math.min(input.length, Math.floor(requested)))\n : input.length;\n const settlement = options.settlement === 'fail-fast' ? 'fail-fast' : 'all-settled';\n const activeChildren = new Set();\n const cancelWaits = new Set();\n const results = new Array(input.length);\n let nextIndex = 0;\n let interrupted = false;\n let halted = false;\n\n const stopActive = () => {\n activeChildren.forEach((child) => child.stop());\n cancelWaits.forEach((cancel) => cancel());\n activeChildren.clear();\n cancelWaits.clear();\n };\n const controller = {\n stop: () => {\n if (interrupted) return;\n interrupted = true;\n halted = true;\n stopActive();\n },\n promise: null,\n };\n const targetFor = (step) => {\n const target = step.target ?? options.target;\n if (!target)\n throw new Error('TypeFlow parallel: a step requires a target or default `target`.');\n return target;\n };\n const wait = (duration) =>\n new Promise((resolve) => {\n let done = false;\n const finish = (completed) => {\n if (done) return;\n done = true;\n clearTimeout(id);\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const id = setTimeout(() => finish(true), Math.max(0, Number(duration) || 0));\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n });\n const visible = (step) =>\n new Promise((resolve) => {\n if (typeof IntersectionObserver === 'undefined') return resolve(true);\n let done = false;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) finish(true);\n },\n { threshold: step.threshold ?? 0.1 }\n );\n const finish = (completed) => {\n if (done) return;\n done = true;\n observer.disconnect();\n cancelWaits.delete(cancel);\n resolve(completed);\n };\n const cancel = () => finish(false);\n cancelWaits.add(cancel);\n const target =\n typeof targetFor(step) === 'string'\n ? document.querySelector(targetFor(step))\n : targetFor(step);\n if (!target) throw new Error('TypeFlow parallel: visibility target not found.');\n observer.observe(target);\n });\n const runStep = async (step) => {\n if (!step || typeof step !== 'object')\n throw new TypeError('TypeFlow parallel: invalid step.');\n if (step.kind === 'pause') return { completed: await wait(step.duration), text: '' };\n if (step.kind === 'visible') return { completed: await visible(step), text: '' };\n if (step.kind === 'call') {\n await step.fn();\n return { completed: true, text: '' };\n }\n let child;\n if (step.kind === 'type') child = engine.type(targetFor(step), step.text, step.config);\n else if (step.kind === 'erase') child = engine.erase(targetFor(step), step.config);\n else if (step.kind === 'parallel')\n child = parallel(step.steps, {\n ...step.options,\n target: step.options?.target ?? options.target,\n });\n else\n throw new TypeError(`TypeFlow parallel: unsupported step kind \\`${String(step.kind)}\\`.`);\n activeChildren.add(child);\n try {\n return await child.promise;\n } finally {\n activeChildren.delete(child);\n }\n };\n const worker = async () => {\n while (!halted) {\n const index = nextIndex++;\n if (index >= input.length) return;\n try {\n const value = await runStep(input[index]);\n results[index] = { status: value.completed ? 'fulfilled' : 'interrupted', value };\n } catch (error) {\n results[index] = { status: 'rejected', reason: error };\n }\n if (results[index].status !== 'fulfilled' && settlement === 'fail-fast') {\n halted = true;\n stopActive();\n }\n }\n };\n controller.promise = Promise.all(Array.from({ length: concurrency }, worker)).then(() => {\n for (let index = 0; index < input.length; index += 1) {\n results[index] ??= { status: 'interrupted', value: { completed: false, text: '' } };\n }\n return {\n completed: !interrupted && results.every(({ status }) => status === 'fulfilled'),\n text: '',\n results,\n };\n });\n return controller;\n };\n return parallel;\n}\n\n/** Explicitly installs the experimental methods onto caller-provided core objects. */\nexport function installParallel(engine, sequenceHelpers) {\n const parallel = createParallel(engine);\n Object.defineProperty(engine, 'parallel', { configurable: true, value: parallel });\n if (sequenceHelpers)\n Object.defineProperty(sequenceHelpers, 'parallel', { configurable: true, value: parallelStep });\n return engine;\n}\n"],"names":["parallelStep","steps","options","kind","createParallel","engine","type","erase","TypeError","parallel","input","Array","isArray","length","stop","promise","Promise","resolve","completed","text","results","requested","Number","concurrency","isFinite","Math","max","min","floor","settlement","activeChildren","Set","cancelWaits","nextIndex","interrupted","halted","stopActive","forEach","child","cancel","clear","controller","targetFor","step","_a","target","Error","visible","IntersectionObserver","done","observer","entries","some","entry","isIntersecting","threshold","finish","disconnect","delete","add","document","querySelector","observe","runStep","__async","_b","duration","clearTimeout","id","setTimeout","fn","config","String","__spreadValues","all","from","index","value","status","error","reason","then","every","installParallel","sequenceHelpers","Object","defineProperty","configurable"],"mappings":"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"}
|