diff --git a/app/src/__tests__/command-palette.test.ts b/app/src/__tests__/command-palette.test.ts new file mode 100644 index 00000000..da238eba --- /dev/null +++ b/app/src/__tests__/command-palette.test.ts @@ -0,0 +1,163 @@ +import { Component, signal } from '@angular/core'; +import { TestBed, type ComponentFixture } from '@angular/core/testing'; +import { afterEach, describe, expect, it } from 'vitest'; +import { CommandPalette } from '../ui/command-palette'; +import { filterCommands, fuzzyScore, type PaletteCommand } from '../palette-filter'; + +const COMMANDS: PaletteCommand[] = [ + { id: 'tab:dashboard', title: 'Go to Dashboard', group: 'Go to' }, + { id: 'tab:signals', title: 'Go to Signals', group: 'Go to' }, + { id: 'tab:network', title: 'Go to SSR & HTTP', group: 'Go to' }, + { id: 'pick-component', title: 'Pick component on page', group: 'Actions', keywords: 'select' }, + { id: 'theme:dark', title: 'Theme: dark', group: 'Theme' }, +]; + +describe('palette filter', () => { + it('matches letters in order and ranks word starts and runs higher', () => { + expect(fuzzyScore('Go to Signals', 'gtsig')).toBeGreaterThan(0); + expect(fuzzyScore('Go to Signals', 'xyz')).toBe(-1); + expect(fuzzyScore('Go to Signals', 'sig')).toBeGreaterThan(fuzzyScore('Design', 'sig')); + }); + + it('keeps the order for an empty query and puts the best match first', () => { + expect(filterCommands(COMMANDS, ' ')).toEqual(COMMANDS); + expect(filterCommands(COMMANDS, 'sig').map((c) => c.id)[0]).toBe('tab:signals'); + expect(filterCommands(COMMANDS, 'http').map((c) => c.id)).toEqual(['tab:network']); + expect(filterCommands(COMMANDS, 'dark').map((c) => c.id)).toEqual(['theme:dark']); + }); + + it('also matches the group and keywords, below a title match', () => { + expect(filterCommands(COMMANDS, 'select').map((c) => c.id)).toEqual(['pick-component']); + expect(filterCommands(COMMANDS, 'theme').map((c) => c.id)[0]).toBe('theme:dark'); + }); +}); + +@Component({ + imports: [CommandPalette], + template: ` + + + `, +}) +class Host { + readonly commands = COMMANDS; + readonly open = signal(false); + readonly picked: string[] = []; +} + +async function settle(fixture: ComponentFixture) { + for (let i = 0; i < 3; i++) { + await new Promise((resolve) => setTimeout(resolve)); + await fixture.whenStable(); + } +} + +function key(target: Element, name: string) { + target.dispatchEvent( + new KeyboardEvent('keydown', { key: name, bubbles: true, cancelable: true }), + ); +} + +async function openPalette() { + const fixture = TestBed.createComponent(Host); + document.body.appendChild(fixture.nativeElement); + await settle(fixture); + const opener = fixture.nativeElement.querySelector('#opener') as HTMLButtonElement; + opener.focus(); + opener.click(); + await settle(fixture); + const root = fixture.nativeElement as HTMLElement; + const input = root.querySelector('input[role="combobox"]') as HTMLInputElement; + return { fixture, root, input, opener }; +} + +afterEach(() => { + document.body.innerHTML = ''; + TestBed.resetTestingModule(); +}); + +describe('CommandPalette', () => { + it('is a modal dialog with a combobox that controls a listbox', async () => { + const { root, input } = await openPalette(); + const dialog = root.querySelector('[role="dialog"]')!; + expect(dialog.getAttribute('aria-modal')).toBe('true'); + const title = root.querySelector(`#${dialog.getAttribute('aria-labelledby')}`); + expect(title?.textContent?.trim()).toBe('Command palette'); + expect(document.activeElement).toBe(input); + expect(input.getAttribute('aria-expanded')).toBe('true'); + const list = root.querySelector(`#${input.getAttribute('aria-controls')}`)!; + expect(list.getAttribute('role')).toBe('listbox'); + const options = list.querySelectorAll('[role="option"]'); + expect(options).toHaveLength(COMMANDS.length); + expect(input.getAttribute('aria-activedescendant')).toBe(options[0].id); + expect(options[0].getAttribute('aria-selected')).toBe('true'); + expect(options[1].getAttribute('aria-selected')).toBe('false'); + }); + + it('filters as you type and says when nothing matches', async () => { + const { fixture, root, input } = await openPalette(); + input.value = 'sig'; + input.dispatchEvent(new Event('input')); + await settle(fixture); + const options = [...root.querySelectorAll('[role="option"]')]; + expect(options[0].textContent).toContain('Go to Signals'); + expect(root.querySelector('[role="status"]')?.textContent).toMatch(/command/); + + input.value = 'zzzz'; + input.dispatchEvent(new Event('input')); + await settle(fixture); + expect(root.querySelectorAll('[role="option"]')).toHaveLength(0); + expect(root.querySelector('.empty')?.textContent).toContain('No commands match “zzzz”'); + expect(input.getAttribute('aria-activedescendant')).toBeNull(); + }); + + it('moves with the arrow keys, wraps, and runs the active command on Enter', async () => { + const { fixture, root, input, opener } = await openPalette(); + key(input, 'ArrowDown'); + key(input, 'ArrowDown'); + await settle(fixture); + const options = root.querySelectorAll('[role="option"]'); + expect(input.getAttribute('aria-activedescendant')).toBe(options[2].id); + key(input, 'ArrowUp'); + key(input, 'ArrowUp'); + key(input, 'ArrowUp'); + await settle(fixture); + expect(input.getAttribute('aria-activedescendant')).toBe(options[COMMANDS.length - 1].id); + + key(input, 'Enter'); + await settle(fixture); + expect(root.querySelector('[role="dialog"]')).toBeNull(); + expect(fixture.componentInstance.picked).toEqual(['theme:dark']); + // Focus went back to what opened it before the command ran. + expect(document.activeElement).toBe(opener); + }); + + it('closes on Escape without running anything, and keeps Tab inside', async () => { + const { fixture, root, input, opener } = await openPalette(); + const tab = new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, cancelable: true }); + input.dispatchEvent(tab); + expect(tab.defaultPrevented).toBe(true); + const escape = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true }); + input.dispatchEvent(escape); + expect(escape.defaultPrevented).toBe(true); + await settle(fixture); + expect(root.querySelector('[role="dialog"]')).toBeNull(); + expect(fixture.componentInstance.picked).toEqual([]); + expect(fixture.componentInstance.open()).toBe(false); + expect(document.activeElement).toBe(opener); + }); + + it('runs a command on click and starts empty the next time', async () => { + const { fixture, root, input } = await openPalette(); + input.value = 'pick'; + input.dispatchEvent(new Event('input')); + await settle(fixture); + (root.querySelector('[role="option"]') as HTMLElement).click(); + await settle(fixture); + expect(fixture.componentInstance.picked).toEqual(['pick-component']); + fixture.componentInstance.open.set(true); + await settle(fixture); + expect((root.querySelector('input[role="combobox"]') as HTMLInputElement).value).toBe(''); + expect(root.querySelectorAll('[role="option"]')).toHaveLength(COMMANDS.length); + }); +}); diff --git a/app/src/__tests__/component-tree-commands.test.ts b/app/src/__tests__/component-tree-commands.test.ts new file mode 100644 index 00000000..e46a1e51 --- /dev/null +++ b/app/src/__tests__/component-tree-commands.test.ts @@ -0,0 +1,109 @@ +import { TestBed, type ComponentFixture } from '@angular/core/testing'; +import type { DevframeRpcClient } from 'devframe/client'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { ComponentTree } from '../pages/component-tree'; + +const roots = [{ id: 'app', name: 'App', tag: 'app-root', children: [] }]; + +function client(options: { live?: boolean; recording?: boolean } = {}) { + const calls: { name: string; args: unknown[] }[] = []; + const page = { + pageId: 'a', + title: 'a', + url: '/', + roots: options.live === false ? [] : roots, + count: 1, + detail: null, + reportedAt: 1, + }; + const state: Record = { + 'component-tree': { pages: { a: page } }, + 'change-detection': { + pages: { + a: { + pageId: 'a', + supported: true, + recording: options.recording === true, + startedAt: null, + cycles: [], + dropped: 0, + components: [], + hosts: {}, + }, + }, + }, + }; + const rpc = { + call: (name: string, ...args: unknown[]) => { + calls.push({ name, args }); + // A pick waits for a click in the app; the test only checks it started. + return name === 'request-component-pick' ? new Promise(() => {}) : Promise.resolve([]); + }, + callEvent: () => Promise.resolve(), + sharedState: (name: string) => + Promise.resolve({ value: () => state[name] ?? null, on: () => () => {} }), + }; + const fake = { connectionMeta: {}, scope: () => ({ rpc }) } as unknown as DevframeRpcClient; + return { fake, calls }; +} + +async function settle(fixture: ComponentFixture) { + for (let i = 0; i < 3; i++) { + await new Promise((resolve) => setTimeout(resolve)); + await fixture.whenStable(); + } +} + +async function setup(options: { live?: boolean; recording?: boolean } = {}) { + const { fake, calls } = client(options); + const fixture = TestBed.createComponent(ComponentTree); + fixture.componentRef.setInput('rpc', fake); + const handled = vi.fn(); + fixture.componentInstance.commandHandled.subscribe(handled); + document.body.appendChild(fixture.nativeElement); + await settle(fixture); + return { fixture, calls, handled }; +} + +afterEach(() => { + document.body.innerHTML = ''; + TestBed.resetTestingModule(); +}); + +describe('Components tab palette commands', () => { + it('starts picking a component on the page', async () => { + const { fixture, calls, handled } = await setup(); + fixture.componentRef.setInput('command', { kind: 'pick' }); + await settle(fixture); + expect(calls.some((call) => call.name === 'request-component-pick')).toBe(true); + expect(fixture.componentInstance.picking()).toBe(true); + expect(handled).toHaveBeenCalledTimes(1); + }); + + it('starts, stops and clears the change detection recording', async () => { + const records = async (kind: 'cd-start' | 'cd-stop' | 'cd-clear', recording: boolean) => { + const { fixture, calls } = await setup({ recording }); + fixture.componentRef.setInput('command', { kind }); + await settle(fixture); + const sent = calls + .filter((call) => call.name === 'request-change-detection-record') + .map((call) => call.args[0]); + fixture.destroy(); + TestBed.resetTestingModule(); + return sent; + }; + expect(await records('cd-start', false)).toEqual([{ pageId: 'a', on: true }]); + expect(await records('cd-start', true)).toEqual([]); + expect(await records('cd-stop', true)).toEqual([{ pageId: 'a', on: false }]); + expect(await records('cd-clear', false)).toEqual([{ pageId: 'a', clear: true }]); + }); + + it('drops a command when no live page is connected', async () => { + const { fixture, calls, handled } = await setup({ live: false }); + fixture.componentRef.setInput('command', { kind: 'pick' }); + await settle(fixture); + expect(calls.some((call) => call.name === 'request-component-pick')).toBe(false); + expect(handled).toHaveBeenCalledTimes(1); + expect(fixture.nativeElement.textContent).toContain('The page reported no component instances'); + }); +}); diff --git a/app/src/__tests__/errors-view.test.ts b/app/src/__tests__/errors-view.test.ts new file mode 100644 index 00000000..565e17fe --- /dev/null +++ b/app/src/__tests__/errors-view.test.ts @@ -0,0 +1,263 @@ +import { TestBed, type ComponentFixture } from '@angular/core/testing'; +import type { DevframeRpcClient } from 'devframe/client'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import type { ConsoleEntry, ErrorGroup } from '../pages/errors-types'; + +const connection = vi.hoisted(() => ({ resolve: (_client: unknown) => {} })); + +vi.mock('devframe/client', () => ({ + connectDevframe: () => + new Promise((resolve) => { + connection.resolve = resolve; + }), +})); + +const { App } = await import('../app'); +const { ErrorsInspector } = await import('../pages/errors-inspector'); +const { errorsPages, defaultErrorsPage } = await import('../pages/errors-types'); + +const group = (extra: Partial = {}): ErrorGroup => ({ + id: 'e1', + message: 'Error: No seats left on trip 42', + name: 'Error', + count: 3, + firstAt: 1_000, + lastAt: 2_000, + sources: ['handler'], + stack: 'Error: No seats left\n at _TripCard.book (main.js:10:5)', + owner: { id: 'c1-7', name: 'TripCard' }, + ...extra, +}); + +const entry = (id: number, extra: Partial = {}): ConsoleEntry => ({ + id, + level: 'log', + text: `line ${id}`, + at: 1_000 + id, + count: 1, + ...extra, +}); + +/** The shape the server sends: groups and entries keyed by id. */ +function wirePage( + pageId: string, + errors: ErrorGroup[], + console: ConsoleEntry[], + extra: Record = {}, +) { + return { + pageId, + url: `/${pageId}`, + title: `Trips ${pageId}`, + reportedAt: 5_000, + handler: 'wrapped', + errors: Object.fromEntries(errors.map((e) => [e.id, e])), + console: Object.fromEntries(console.map((e) => [String(e.id), e])), + dropped: { errors: 0, console: 0 }, + ...extra, + }; +} + +function fakeClient(value: unknown, configs: Record = {}) { + const rpc = { + call: () => Promise.resolve([]), + callEvent: () => Promise.resolve(), + sharedState: (name: string) => + Promise.resolve({ + value: () => (name === 'errors' ? value : null), + on: () => () => {}, + }), + }; + return { + connectionMeta: { configs }, + scope: () => ({ rpc }), + events: { on: () => () => {} }, + } as unknown as DevframeRpcClient; +} + +async function settle(fixture: ComponentFixture) { + for (let i = 0; i < 4; i++) { + await new Promise((resolve) => setTimeout(resolve)); + await fixture.whenStable(); + } +} + +const host = (fixture: ComponentFixture) => fixture.nativeElement as HTMLElement; +const text = (fixture: ComponentFixture) => + (host(fixture).textContent ?? '').replace(/\s+/g, ' '); + +async function mount(value: unknown) { + const fixture = TestBed.createComponent(ErrorsInspector); + fixture.componentRef.setInput('rpc', fakeClient(value)); + document.body.append(host(fixture)); + await settle(fixture); + return fixture; +} + +function button(fixture: ComponentFixture, name: string): HTMLButtonElement { + const found = [...host(fixture).querySelectorAll('button')].find((b) => + (b.textContent ?? '').replace(/\s+/g, ' ').trim().startsWith(name), + ); + if (!found) throw new Error(`No button ${name}`); + return found; +} + +afterEach(() => { + document.body.innerHTML = ''; + location.hash = ''; + sessionStorage.clear(); +}); + +describe('the Errors tab', () => { + it('says how to get data when no page reports', async () => { + const fixture = await mount({ pages: {} }); + expect(text(fixture)).toContain('No page reports errors yet.'); + }); + + it('lists errors with count, code link, stack collapsed and a Show component link', async () => { + const fixture = await mount({ + pages: { + p1: wirePage( + 'p1', + [ + group(), + group({ + id: 'e2', + message: 'Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError', + code: 'NG0100', + docUrl: 'https://angular.dev/errors/NG0100', + lastAt: 3_000, + count: 1, + owner: undefined, + }), + group({ id: 'e3', message: 'NG0303: unknown', code: 'NG0303', lastAt: 500 }), + ], + [], + ), + }, + }); + const items = [...host(fixture).querySelectorAll('ol.errors > li')]; + expect(items.map((li) => li.querySelector('.message')?.textContent)).toEqual([ + 'Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError', + 'Error: No seats left on trip 42', + 'NG0303: unknown', + ]); + const link = items[0]!.querySelector('a.chip.code')!; + expect(link.href).toBe('https://angular.dev/errors/NG0100'); + expect(link.target).toBe('_blank'); + // An undocumented code is shown, without a link. + expect(items[2]!.querySelector('a.chip.code')).toBeNull(); + expect(items[2]!.querySelector('.chip.code')?.textContent?.trim()).toBe('NG0303'); + expect(items[1]!.querySelector('.times')?.getAttribute('aria-label')).toBe('3 times'); + const details = items[1]!.querySelector('details')!; + expect(details.open).toBe(false); + expect(details.querySelector('summary')?.textContent).toBe('Stack'); + + const shown: unknown[] = []; + fixture.componentInstance.showComponent.subscribe((focus) => shown.push(focus)); + button(fixture, 'Show component').click(); + expect(shown).toEqual([{ id: 'c1-7', pageId: 'p1' }]); + expect(text(fixture)).toContain('3 of 3 errors'); + }); + + it('filters by message and offers Clear filter when nothing matches', async () => { + const fixture = await mount({ pages: { p1: wirePage('p1', [group()], []) } }); + const search = host(fixture).querySelector('input[type="search"]')!; + search.value = 'zzz'; + search.dispatchEvent(new Event('input')); + await settle(fixture); + expect(text(fixture)).toContain('No error matches “zzz”.'); + button(fixture, 'Clear filter').click(); + await settle(fixture); + expect(host(fixture).querySelectorAll('ol.errors > li')).toHaveLength(1); + expect(document.activeElement).toBe(search); + }); + + it('shows the empty state and the unwrapped handler notice', async () => { + const fixture = await mount({ pages: { p1: wirePage('p1', [], [], { handler: 'none' }) } }); + expect(text(fixture)).toContain('No errors since the page loaded.'); + expect(text(fixture)).toContain("Angular's ErrorHandler isn't wrapped"); + }); + + it('shows the console log newest first, with a level filter and repeat counts', async () => { + const fixture = await mount({ + pages: { + p1: wirePage( + 'p1', + [], + [ + entry(1, { text: 'Loaded trips', count: 4 }), + entry(2, { + level: 'warn', + text: 'NG0913: image too big', + code: 'NG0913', + docUrl: 'https://angular.dev/errors/NG0913', + }), + entry(3, { level: 'error', text: 'Failed to save' }), + ], + ), + }, + }); + button(fixture, 'Console').click(); + await settle(fixture); + const rows = () => + [...host(fixture).querySelectorAll('ol.console > li .text')].map((t) => t.textContent); + expect(rows()).toEqual(['Failed to save', 'NG0913: image too big', 'Loaded trips']); + expect(host(fixture).querySelector('ol.console a.chip.code')?.getAttribute('href')).toBe( + 'https://angular.dev/errors/NG0913', + ); + expect(text(fixture)).toContain('4×'); + fixture.componentInstance.level.set('warn'); + await settle(fixture); + expect(rows()).toEqual(['NG0913: image too big']); + expect(text(fixture)).toContain('1 of 3 calls'); + expect(button(fixture, 'Console').getAttribute('aria-pressed')).toBe('true'); + }); + + it('merges pages under All pages and picks the panel page when it reports', () => { + const value = { + pages: { + a: wirePage('a', [group({ lastAt: 10 })], []), + b: { ...wirePage('b', [group({ id: 'e9', lastAt: 20 })], []), reportedAt: 9_000 }, + }, + }; + const pages = errorsPages(value); + expect(pages.map((p) => p.pageId)).toEqual(['b', 'a']); + expect(defaultErrorsPage(pages, 'a')).toBe('a'); + expect(defaultErrorsPage(pages, null)).toBe('all'); + expect(defaultErrorsPage(pages.slice(0, 1), null)).toBe('b'); + }); +}); + +describe('the Errors tab in the panel', () => { + it('appears in the tab bar, opens the Components tab from Show component, and goes with its inspector', async () => { + const open = async (configs: Record) => { + location.hash = '#tab=errors'; + const fixture = TestBed.createComponent(App); + document.body.append(host(fixture)); + await settle(fixture); + connection.resolve(fakeClient({ pages: { p1: wirePage('p1', [group()], []) } }, configs)); + await settle(fixture); + return fixture; + }; + const fixture = await open({}); + const names = [...host(fixture).querySelectorAll('nav button')].map((b) => + b.textContent?.trim(), + ); + expect(names).toContain('Errors'); + expect(host(fixture).querySelector('nav button.active')?.textContent?.trim()).toBe('Errors'); + button(fixture, 'Show component').click(); + await settle(fixture); + expect(host(fixture).querySelector('nav button.active')?.textContent?.trim()).toBe( + 'Components', + ); + fixture.destroy(); + document.body.innerHTML = ''; + + const off = await open({ pangular: { inspectors: { errors: false } } }); + const offNames = [...host(off).querySelectorAll('nav button')].map((b) => + b.textContent?.trim(), + ); + expect(offNames).not.toContain('Errors'); + }); +}); diff --git a/app/src/__tests__/settings.test.ts b/app/src/__tests__/settings.test.ts new file mode 100644 index 00000000..a7d0e916 --- /dev/null +++ b/app/src/__tests__/settings.test.ts @@ -0,0 +1,223 @@ +// @vitest-environment jsdom +import { TestBed, type ComponentFixture } from '@angular/core/testing'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { Settings } from '../pages/settings'; +import { + DEFAULT_TAB_LAYOUT, + arrangeTabs, + moveTab, + setTabHidden, + setTabPinned, + storePassive, + storeTabLayout, + storeThemePreference, + storedPassive, + storedTabLayout, + storedThemePreference, + type TabLayout, +} from '../shell-prefs'; +import { ThemeService } from '../theme.service'; + +const TABS = [ + { id: 'dashboard', label: 'Dashboard' }, + { id: 'components', label: 'Components' }, + { id: 'signals', label: 'Signals' }, + { id: 'forms', label: 'Forms' }, +]; +const IDS = TABS.map((tab) => tab.id); + +beforeEach(() => localStorage.clear()); +afterEach(() => { + document.body.innerHTML = ''; + delete document.documentElement.dataset['theme']; + TestBed.resetTestingModule(); +}); + +describe('settings storage', () => { + it('keeps the tab layout, theme and passive mode across reloads', () => { + expect(storedTabLayout()).toEqual(DEFAULT_TAB_LAYOUT); + const layout: TabLayout = { order: ['forms', 'dashboard'], hidden: ['signals'], pinned: [] }; + storeTabLayout(layout); + expect(storedTabLayout()).toEqual(layout); + storeTabLayout(DEFAULT_TAB_LAYOUT); + expect(localStorage.getItem('pangular-pref:tabs')).toBeNull(); + + expect(storedThemePreference()).toBe('system'); + storeThemePreference('light'); + expect(storedThemePreference()).toBe('light'); + storeThemePreference('system'); + expect(localStorage.getItem('pangular-pref:theme')).toBeNull(); + + expect(storedPassive()).toBe(false); + storePassive(true); + expect(storedPassive()).toBe(true); + }); + + it('ignores a stored layout it cannot use', () => { + for (const raw of ['{nope', '[]', 'null', '{"order":"x","hidden":[1,"forms"]}']) { + localStorage.setItem('pangular-pref:tabs', raw); + const layout = storedTabLayout(); + expect(Array.isArray(layout.order)).toBe(true); + expect(layout.hidden.every((id) => typeof id === 'string')).toBe(true); + } + }); +}); + +describe('tab layout', () => { + it('orders pinned tabs first and leaves hidden ones out, except the open one', () => { + const layout: TabLayout = { order: [], hidden: ['signals'], pinned: ['forms'] }; + expect(arrangeTabs(TABS, layout).map((tab) => tab.id)).toEqual([ + 'forms', + 'dashboard', + 'components', + ]); + expect(arrangeTabs(TABS, layout, 'signals').map((tab) => tab.id)).toContain('signals'); + }); + + it('moves a tab within its section and not past the ends', () => { + let layout = moveTab(IDS, DEFAULT_TAB_LAYOUT, 'signals', -1); + expect(arrangeTabs(TABS, layout).map((tab) => tab.id)).toEqual([ + 'dashboard', + 'signals', + 'components', + 'forms', + ]); + expect(moveTab(IDS, layout, 'dashboard', -1)).toBe(layout); + layout = setTabPinned(IDS, layout, 'forms', true); + // The first unpinned tab can't move above a pinned one. + expect(moveTab(IDS, layout, 'dashboard', -1)).toBe(layout); + }); + + it('unpins a tab it hides, and shows a tab it pins', () => { + let layout = setTabPinned(IDS, DEFAULT_TAB_LAYOUT, 'forms', true); + layout = setTabHidden(layout, 'forms', true); + expect(layout.pinned).toEqual([]); + expect(layout.hidden).toEqual(['forms']); + layout = setTabPinned(IDS, layout, 'forms', true); + expect(layout.hidden).toEqual([]); + }); +}); + +async function settle(fixture: ComponentFixture) { + for (let i = 0; i < 3; i++) { + await new Promise((resolve) => setTimeout(resolve)); + await fixture.whenStable(); + } +} + +async function render() { + const fixture = TestBed.createComponent(Settings); + fixture.componentRef.setInput('tabs', TABS); + fixture.componentRef.setInput('hotkey', 'Alt+Shift+P'); + document.body.appendChild(fixture.nativeElement); + await settle(fixture); + const root = fixture.nativeElement as HTMLElement; + const rows = () => + [...root.querySelectorAll('.tab-row')].map((row) => row.dataset['tab']); + const button = (label: string) => + root.querySelector(`[aria-label="${label}"]`)!; + return { fixture, root, rows, button }; +} + +describe('Settings page', () => { + it('starts with h2 sections and lists the tabs in order', async () => { + const { root, rows } = await render(); + expect([...root.querySelectorAll('h2')].map((h) => h.textContent?.trim())).toEqual([ + 'Theme', + 'Tabs', + 'Popup on the page', + 'Keyboard shortcuts', + ]); + expect(root.querySelector('h1, h3')).toBeNull(); + expect(rows()).toEqual(IDS); + }); + + it('reorders with the buttons, keeps focus on the moved row and says where it went', async () => { + const { fixture, root, rows, button } = await render(); + button('Move Signals up').focus(); + button('Move Signals up').click(); + await settle(fixture); + expect(rows()).toEqual(['dashboard', 'signals', 'components', 'forms']); + expect(fixture.componentInstance.layout().order).toEqual([ + 'dashboard', + 'signals', + 'components', + 'forms', + ]); + expect(document.activeElement).toBe(button('Move Signals up')); + expect(root.querySelector('[role="status"]')?.textContent).toContain( + 'Signals moved to position 2 of 4.', + ); + // At the top, focus moves to the other arrow instead of a disabled one. + button('Move Signals up').click(); + await settle(fixture); + expect(rows()[0]).toBe('signals'); + expect(button('Move Signals up').disabled).toBe(true); + expect(document.activeElement).toBe(button('Move Signals down')); + }); + + it('reorders with Alt and the arrow keys on a row', async () => { + const { fixture, rows, button } = await render(); + const pin = button('Pin Dashboard'); + pin.focus(); + pin.dispatchEvent( + new KeyboardEvent('keydown', { key: 'ArrowDown', altKey: true, bubbles: true }), + ); + await settle(fixture); + expect(rows()).toEqual(['components', 'dashboard', 'signals', 'forms']); + }); + + it('hides, pins and resets tabs', async () => { + const { fixture, root, rows, button } = await render(); + const shown = root.querySelector( + '[aria-label="Forms shown in the tab bar"]', + )!; + shown.click(); + await settle(fixture); + expect(fixture.componentInstance.layout().hidden).toEqual(['forms']); + + button('Pin Signals').click(); + await settle(fixture); + expect(rows()[0]).toBe('signals'); + expect(button('Pin Signals').getAttribute('aria-pressed')).toBe('true'); + + const reset = [...root.querySelectorAll('button')].find( + (b) => b.textContent?.trim() === 'Reset tabs', + )!; + reset.click(); + await settle(fixture); + expect(fixture.componentInstance.layout()).toEqual(DEFAULT_TAB_LAYOUT); + expect(rows()).toEqual(IDS); + }); + + it('turns passive mode off when the popup has no shortcut', async () => { + const { fixture, root } = await render(); + const passive = () => + root.querySelector('input[aria-describedby="settings-passive-hint"]')!; + expect(passive().disabled).toBe(false); + fixture.componentRef.setInput('hotkey', false); + await settle(fixture); + expect(passive().disabled).toBe(true); + expect(root.textContent).toContain('popup.hotkey'); + }); +}); + +describe('theme preference', () => { + it('pins light or dark over the system, saves it, and follows the system again', () => { + const service = TestBed.inject(ThemeService); + expect(service.preference()).toBe('system'); + service.setPreference('light'); + expect(service.current()).toBe('light'); + expect(document.documentElement.dataset['theme']).toBe('light'); + expect(storedThemePreference()).toBe('light'); + service.setPreference('system'); + expect(document.documentElement.dataset['theme']).toBeUndefined(); + expect(storedThemePreference()).toBe('system'); + }); + + it('starts from the saved preference', () => { + storeThemePreference('light'); + const service = TestBed.inject(ThemeService); + expect(service.current()).toBe('light'); + }); +}); diff --git a/app/src/__tests__/shell-deep-link.test.ts b/app/src/__tests__/shell-deep-link.test.ts new file mode 100644 index 00000000..117cd6b3 --- /dev/null +++ b/app/src/__tests__/shell-deep-link.test.ts @@ -0,0 +1,158 @@ +import { TestBed, type ComponentFixture } from '@angular/core/testing'; +import type { DevframeRpcClient } from 'devframe/client'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { parsePanelLink } from '@pangular-inspector/devtools/config'; + +const server = vi.hoisted(() => ({ + /** Events the panel registered, by name, to call as the server would broadcast. */ + handlers: new Map void>(), +})); + +function fakeClient(): DevframeRpcClient { + const rpc = { + call: () => new Promise(() => {}), + callEvent: () => Promise.resolve(), + sharedState: () => Promise.resolve({ value: () => undefined, on: () => () => {} }), + register: (definition: { name: string; handler: (message: unknown) => void }) => + server.handlers.set(definition.name, definition.handler), + }; + return { + connectionMeta: { configs: {} }, + scope: () => ({ rpc }), + events: { on: () => () => {} }, + close: () => {}, + } as unknown as DevframeRpcClient; +} + +vi.mock('devframe/client', () => ({ + connectDevframe: () => Promise.resolve(fakeClient()), +})); + +const { App } = await import('../app'); + +async function settle(fixture: ComponentFixture) { + for (let i = 0; i < 3; i++) { + await new Promise((resolve) => setTimeout(resolve)); + await fixture.whenStable(); + } +} + +async function boot(hash = '') { + history.replaceState(null, '', `/${hash}`); + const fixture = TestBed.createComponent(App); + document.body.appendChild(fixture.nativeElement); + await settle(fixture); + return { fixture, app: fixture.componentInstance, root: fixture.nativeElement as HTMLElement }; +} + +beforeEach(() => { + localStorage.clear(); + sessionStorage.clear(); + server.handlers.clear(); +}); + +afterEach(() => { + document.body.innerHTML = ''; + history.replaceState(null, '', '/'); + TestBed.resetTestingModule(); +}); + +describe('deep links', () => { + it('opens the tab and selects the component a link names', async () => { + const { fixture, app } = await boot('#tab=components&id=12&page=p1'); + expect(app.tab()).toBe('components'); + expect(app.componentFocus()).toEqual({ id: '12', pageId: 'p1' }); + fixture.destroy(); + }); + + it('selects the injector of a component, and a form', async () => { + const booted = await boot('#tab=injectors&id=c4'); + expect(booted.app.injectorFocus()).toEqual({ componentId: 'c4', pageId: undefined }); + booted.fixture.destroy(); + TestBed.resetTestingModule(); + // The Forms tab takes the focus at once and clears it, so the hand-over is watched. + history.replaceState(null, '', '/#tab=forms&id=f1'); + const fixture = TestBed.createComponent(App); + const handed = vi.spyOn(fixture.componentInstance.formFocus, 'set'); + await settle(fixture); + expect(fixture.componentInstance.tab()).toBe('forms'); + expect(handed).toHaveBeenCalledWith({ id: 'f1' }); + fixture.destroy(); + }); + + it('opens a tab without an item, and ignores an unknown tab', async () => { + let booted = await boot('#tab=signals&id=3'); + expect(booted.app.tab()).toBe('signals'); + booted.fixture.destroy(); + TestBed.resetTestingModule(); + booted = await boot('#tab=nope&id=3'); + expect(booted.app.tab()).toBe('dashboard'); + booted.fixture.destroy(); + }); + + it('follows a link the server sends to open panels', async () => { + const { fixture, app } = await boot(); + server.handlers.get('open-in-panel')!({ tab: 'components', id: '7', page: 'p2' }); + await settle(fixture); + expect(app.tab()).toBe('components'); + expect(app.componentFocus()).toEqual({ id: '7', pageId: 'p2' }); + expect(parsePanelLink(location.hash)).toEqual({ tab: 'components', id: '7', page: 'p2' }); + fixture.destroy(); + }); + + it('runs commands from the hub palette', async () => { + const { fixture, app } = await boot(); + server.handlers.get('panel-command')!({ command: 'tab:routes' }); + await settle(fixture); + expect(app.tab()).toBe('routes'); + server.handlers.get('panel-command')!({ command: 'pick-component' }); + await settle(fixture); + expect(app.tab()).toBe('components'); + fixture.destroy(); + }); +}); + +describe('shell palette and settings', () => { + it('opens the palette with Ctrl+K and runs a tab command', async () => { + const { fixture, app, root } = await boot(); + document.dispatchEvent( + new KeyboardEvent('keydown', { key: 'k', ctrlKey: true, bubbles: true, cancelable: true }), + ); + await settle(fixture); + const input = root.querySelector('app-command-palette input')!; + expect(document.activeElement).toBe(input); + input.value = 'go to forms'; + input.dispatchEvent(new Event('input')); + await settle(fixture); + input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })); + await settle(fixture); + expect(app.tab()).toBe('forms'); + fixture.destroy(); + }); + + it('opens Settings from the header and goes back to the tab before', async () => { + const { fixture, app, root } = await boot('#tab=signals'); + const settings = root.querySelector('button[aria-label="Settings"]')!; + settings.click(); + await settle(fixture); + expect(app.tab()).toBe('settings'); + expect(settings.getAttribute('aria-pressed')).toBe('true'); + expect(root.querySelector('app-settings h2')?.textContent).toBe('Theme'); + settings.click(); + await settle(fixture); + expect(app.tab()).toBe('signals'); + fixture.destroy(); + }); + + it('orders and hides tab bar buttons as saved in Settings', async () => { + localStorage.setItem( + 'pangular-pref:tabs', + JSON.stringify({ order: [], hidden: ['pipes'], pinned: ['forms'] }), + ); + const { fixture, root } = await boot(); + const labels = [...root.querySelectorAll('nav button')].map((b) => b.textContent?.trim()); + expect(labels[0]).toBe('Forms'); + expect(labels).not.toContain('Pipes'); + fixture.destroy(); + }); +}); diff --git a/app/src/app.ts b/app/src/app.ts index 71ee816f..033d2b80 100644 --- a/app/src/app.ts +++ b/app/src/app.ts @@ -30,11 +30,12 @@ import { AnalogInspector } from './pages/analog-inspector'; import { NetworkInspector } from './pages/network-inspector'; import { ComingSoon, type ComingSoonInfo } from './pages/coming-soon'; import { CapacitorInspector } from './pages/capacitor-inspector'; +import { ErrorsInspector } from './pages/errors-inspector'; import { capacitorPages } from './pages/capacitor-types'; import { TabIcon } from './pages/tab-icon'; import { styleHubRail } from './hub-rail-style'; -import { ThemeService } from './theme.service'; -import { followHubDocks, inHub, selectHubDock } from './hub-dock-sync'; +import { ThemeService, themeTargets } from './theme.service'; +import { followHubDocks, inHub, openHubPalette, selectHubDock } from './hub-dock-sync'; import { fullPanelHref, isPlainClick } from './full-panel'; import { INSPECTORS_DOCS_URL, panelConfig, tabEnabled, tabInspector } from './devtools-config'; import { hostPageId, scopeToPage } from './page-id'; @@ -47,9 +48,32 @@ import { viewAccent } from './view-accents'; import { HUB_ALL_TOOLS, HUB_VIEWS, + PANEL_LINK_ITEMS, + PANEL_TABS, + hotkeyLabel, hubDockId, + matchesHotkey, + panelCommands, + panelLinkHash, + parsePanelLink, type HubView, + type PanelLink, } from '@pangular-inspector/devtools/config'; +import { Settings } from './pages/settings'; +import { CommandPalette } from './ui/command-palette'; +import type { PaletteCommand } from './palette-filter'; +import type { ComponentCommand } from './types/component-command.types'; +import { + arrangeTabs, + inPopup, + isMacPlatform, + storePassive, + storeTabLayout, + storedPassive, + storedTabLayout, + type TabLayout, + type ThemePreference, +} from './shell-prefs'; type View = HubView; @@ -169,6 +193,7 @@ function readView(): View | null { '[style.--accent]': 'viewAccent()?.accent ?? null', '[style.--accent-text]': 'viewAccent()?.text ?? null', '(window:message)': 'inspectFromPanel($event)', + '(document:keydown)': 'onGlobalKey($event)', }, imports: [ Dashboard, @@ -182,8 +207,11 @@ function readView(): View | null { AnalogInspector, NetworkInspector, CapacitorInspector, + ErrorsInspector, ComingSoon, TabIcon, + Settings, + CommandPalette, ], template: `
@@ -392,6 +420,33 @@ function readView(): View | null { Open full panel } + + + +

{{ backgroundNote() }}

- @if (connectionFailed()) { + @if (tab() === 'settings') { + + } @else if (connectionFailed()) {
+ `, styles: ` @use 'mixins' as m; @@ -718,7 +799,50 @@ function readView(): View | null { @include m.focus-ring(2px); } } - .full-panel + .status { + .shell-actions { + display: inline-flex; + flex-shrink: 0; + gap: 4px; + margin-left: auto; + } + .full-panel + .shell-actions { + margin-left: 0; + } + .shell-btn { + display: grid; + place-items: center; + width: 30px; + height: 30px; + padding: 0; + border: 1px solid var(--border); + border-radius: 8px; + background: var(--surface); + color: var(--text-2); + cursor: pointer; + transition: + background-color 0.16s var(--ease), + color 0.16s var(--ease); + svg { + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; + } + &:hover { + background: var(--surface-2); + color: var(--text-strong); + } + &.active { + border-color: var(--accent-line); + background: var(--accent-soft); + color: var(--text-strong); + } + &:focus-visible { + @include m.focus-ring(2px); + } + } + .shell-actions + .status { margin-left: 0; } .dot { @@ -883,27 +1007,17 @@ function readView(): View | null { }) export class App implements OnInit, OnDestroy { readonly analog = signal(false); - private readonly allTabs: Tabs[] = [ - { id: 'dashboard', label: 'Dashboard' }, - { id: 'analog', label: 'Analog' }, - { id: 'components', label: 'Components' }, - { id: 'routes', label: 'Routes' }, - { id: 'signals', label: 'Signals' }, - { id: 'injectors', label: 'Injectors' }, - { id: 'store', label: 'Store' }, - { id: 'forms', label: 'Forms' }, - { id: 'pipes', label: 'Pipes' }, - { id: 'network', label: 'SSR & HTTP' }, - { id: 'capacitor', label: 'Capacitor' }, - ]; + private readonly allTabs: Tabs[] = PANEL_TABS.map(({ id, label }) => ({ id, label })); readonly view = signal(readView()); readonly viewAccent = computed(() => viewAccent(this.view(), this.themeService.current())); readonly title = computed(() => { const view = this.view(); return view ? VIEW_TITLE[view] : 'Pangular Inspector'; }); - protected readonly mainLabel = computed( - () => this.availableTabs().find((t) => t.id === this.tab())?.label ?? this.title(), + protected readonly mainLabel = computed(() => + this.tab() === 'settings' + ? 'Settings' + : (this.availableTabs().find((t) => t.id === this.tab())?.label ?? this.title()), ); readonly analogKnown = signal(false); /** Whether a Capacitor app reports, so the Capacitor tab has something to show. */ @@ -954,12 +1068,16 @@ export class App implements OnInit, OnDestroy { !(view === 'angular' && TAB_VIEW[t.id]), ); }); + /** How the viewer arranged the tab bar in Settings. */ + readonly tabLayout = signal(storedTabLayout()); readonly tabs = computed(() => { - const tabs = this.availableTabs(); - if (this.rpc()) return tabs; const tab = this.tab(); + const tabs = arrangeTabs(this.availableTabs(), this.tabLayout(), tab); + if (this.rpc()) return tabs; return tabs.filter((t) => t.id === 'dashboard' || t.id === tab); }); + /** The tabs Settings arranges: every tab this panel can show, in the default order. */ + protected readonly settingsTabs = computed(() => this.availableTabs()); /** The one tab button in the Tab order; the arrow keys reach the others. */ protected readonly rovingTab = computed(() => { @@ -1095,13 +1213,14 @@ export class App implements OnInit, OnDestroy { if (dock === ALL_TOOLS) this.showFullPanel(); else this.showView(dock); }); - const restored = initialTab( - location.hash, - storedTab(this.tabScope()), - this.availableTabs().map((t) => t.id), - ); - if (restored) this.tab.set(restored); - else if ( + const restored = initialTab(location.hash, storedTab(this.tabScope()), [ + ...this.availableTabs().map((t) => t.id), + 'settings' as const, + ]); + if (restored) { + this.tab.set(restored); + this.restoreLinkItem(); + } else if ( !this.view() && initialTab(location.hash, storedTab(this.tabScope()), ['capacitor']) === 'capacitor' ) { @@ -1142,6 +1261,7 @@ export class App implements OnInit, OnDestroy { this.refocusOnConnect = false; this.rpc.set(client); this.connected.set(true); + this.listenForServer(client); void this.watchVisibility(client); void this.watchAngularNative(client); void this.watchCapacitor(client); @@ -1252,6 +1372,199 @@ export class App implements OnInit, OnDestroy { void selectHubDock(ALL_TOOLS); } + // Command palette, settings and deep links. + readonly paletteOpen = signal(false); + protected readonly paletteShortcut = isMacPlatform() ? '⌘K' : 'Ctrl+K'; + readonly themePreference = computed(() => this.themeService.preference()); + readonly passive = signal(storedPassive()); + /** The popup shortcut from the config, as the platform writes it. */ + readonly popupHotkey = computed(() => { + const hotkey = this.config().popup.hotkey; + return hotkey === false ? false : hotkeyLabel(hotkey, isMacPlatform()); + }); + private readonly popup = inPopup(); + /** The tab to go back to when Settings closes. */ + private tabBeforeSettings: Tab | null = null; + /** A command for the Components tab, handed over once it shows. */ + readonly componentCommand = linkedSignal({ + source: this.tab, + computation: () => null, + }); + + readonly paletteCommands = computed(() => { + const available = new Set(this.availableTabs().map((t) => t.id)); + const components = available.has('components') && !!this.rpc(); + return panelCommands(this.config()).filter((command) => { + if (command.id.startsWith('tab:')) return available.has(command.id.slice(4)); + if (command.popupOnly) return this.popup; + if (command.id === 'pick-component' || command.id.startsWith('cd-')) return components; + return true; + }); + }); + + /** Cmd+K on macOS, Ctrl+K elsewhere, opens the palette from anywhere in the panel. */ + onGlobalKey(event: KeyboardEvent) { + if (event.defaultPrevented) return; + const mac = isMacPlatform(); + const hotkey = this.config().popup.hotkey; + if (this.popup && hotkey && !event.repeat && matchesHotkey(event, hotkey, mac)) { + // The popup can't hear keys inside a hub dock, so the panel asks it to close. + event.preventDefault(); + this.postToPopup({ type: 'pangular:popup-close' }); + return; + } + const mod = mac ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey; + if (!mod || event.altKey || event.shiftKey || event.key.toLowerCase() !== 'k') return; + if (event.repeat) return; + event.preventDefault(); + if (this.paletteOpen()) return; + this.openPalette(); + } + + /** The hub's palette lists the same commands; outside the hub the panel has its own. */ + openPalette() { + if (inHub() && openHubPalette()) return; + this.paletteOpen.set(true); + } + + /** Runs a palette command, from this panel's palette or the hub's. */ + runCommand(id: string) { + if (id.startsWith('tab:')) { + const tab = id.slice(4) as Tab; + if (this.availableTabs().some((t) => t.id === tab)) this.switchTab(tab); + return; + } + if (id.startsWith('theme:')) { + const theme = id.slice(6); + if (theme === 'system' || theme === 'light' || theme === 'dark') this.setTheme(theme); + return; + } + if (id.startsWith('dock:')) { + this.postToPopup({ type: 'pangular:popup-dock', mode: id.slice(5) }); + return; + } + const kinds: Record = { + 'pick-component': 'pick', + 'cd-record-start': 'cd-start', + 'cd-record-stop': 'cd-stop', + 'cd-clear': 'cd-clear', + }; + if (id === 'settings') { + if (this.tab() !== 'settings') this.toggleSettings(); + } else if (kinds[id] && this.availableTabs().some((t) => t.id === 'components')) { + // Switch first: the command belongs to the tab, so the switch would clear it. + if (this.tab() !== 'components') this.switchTab('components'); + this.componentCommand.set({ kind: kinds[id] }); + } + } + + toggleSettings() { + if (this.tab() === 'settings') { + const back = this.tabBeforeSettings; + const available = this.availableTabs().map((t) => t.id); + this.switchTab(back && available.includes(back) ? back : (available[0] ?? 'dashboard')); + return; + } + this.tabBeforeSettings = this.tab(); + this.switchTab('settings'); + } + + setTabLayout(layout: TabLayout) { + this.tabLayout.set(layout); + storeTabLayout(layout); + } + + setTheme(theme: ThemePreference) { + this.themeService.setPreference(theme); + } + + setPassive(passive: boolean) { + this.passive.set(passive); + storePassive(passive); + this.postToPopup({ type: 'pangular:popup-passive', passive }); + } + + /** Sends a message to the popup on the app's page, which checks it came from its panel. */ + private postToPopup(message: Record) { + for (const { win, origin } of themeTargets()) { + try { + win.postMessage(message, origin); + } catch { + // a window that went away + } + } + } + + /** + * Opens a deep link: its tab, and the item it names on the tabs that can + * select one (`PANEL_LINK_ITEMS`). Returns whether the tab exists here. + */ + openLink(link: PanelLink): boolean { + const tab = link.tab as Tab; + if (!this.availableTabs().some((t) => t.id === tab)) return false; + if (this.tab() !== tab) this.switchTab(tab); + if (link.id && Object.hasOwn(PANEL_LINK_ITEMS, tab)) { + const pageId = link.page; + if (tab === 'components') this.componentFocus.set({ id: link.id, pageId }); + else if (tab === 'injectors') this.injectorFocus.set({ componentId: link.id, pageId }); + else if (tab === 'forms') this.formFocus.set({ id: link.id }); + } + history.replaceState(history.state, '', panelLinkHash(link)); + return true; + } + + /** Listens for the commands and links the server sends to every open panel. */ + private listenForServer(client: DevframeRpcClient) { + const rpc = client.scope('pangular').rpc as unknown as { + register: (definition: { + name: string; + type: 'event'; + jsonSerializable: boolean; + handler: (message: unknown) => void; + }) => void; + }; + // Only a panel someone can see acts, so a tab in the background stays put. + const visible = () => typeof document === 'undefined' || document.visibilityState !== 'hidden'; + try { + rpc.register({ + name: 'panel-command', + type: 'event', + jsonSerializable: true, + handler: (message) => { + const command = (message as { command?: unknown } | null)?.command; + if (typeof command === 'string' && visible()) this.runCommand(command); + }, + }); + rpc.register({ + name: 'open-in-panel', + type: 'event', + jsonSerializable: true, + handler: (message) => { + const link = message as Partial | null; + if (!visible() || typeof link?.tab !== 'string') return; + this.openLink({ + tab: link.tab, + ...(typeof link.id === 'string' ? { id: link.id } : {}), + ...(typeof link.page === 'string' ? { page: link.page } : {}), + }); + }, + }); + } catch { + // a client that cannot take server events; the palette still works locally + } + } + + /** The item a deep link on load names, applied once its tab is open. */ + private restoreLinkItem() { + const link = parsePanelLink(location.hash); + if (!link?.id || link.tab !== this.tab()) return; + const tab = link.tab as Tab; + if (tab === 'components') this.componentFocus.set({ id: link.id, pageId: link.page }); + else if (tab === 'injectors') { + this.injectorFocus.set({ componentId: link.id, pageId: link.page }); + } else if (tab === 'forms') this.formFocus.set({ id: link.id }); + } + formFocus = signal<{ id: string } | null>(null); // Belongs to the Components tab that received it, so leaving the tab drops it. readonly componentFocus = linkedSignal({ diff --git a/app/src/devtools-config.ts b/app/src/devtools-config.ts index f6f11572..4a373875 100644 --- a/app/src/devtools-config.ts +++ b/app/src/devtools-config.ts @@ -30,6 +30,7 @@ const TAB_INSPECTOR: Partial> = { network: 'http', analog: 'analog', capacitor: 'capacitor', + errors: 'errors', }; /** The `inspectors` key that turns a tab on or off, if any. */ diff --git a/app/src/hub-dock-sync.ts b/app/src/hub-dock-sync.ts index 1461ca93..280fb3f0 100644 --- a/app/src/hub-dock-sync.ts +++ b/app/src/hub-dock-sync.ts @@ -7,6 +7,7 @@ interface DockState { } interface HubClientContext { + commands?: { openPalette?: (scopeId?: string | null) => void }; docks: { selectedId: string | null; getStateById: (id: string) => DockState | undefined; @@ -65,3 +66,18 @@ export async function selectHubDock(view: string): Promise { return false; } } + +/** + * Opens the hub's command palette, which lists the panel's commands through + * `ctx.commands`. `false` outside the hub or when the hub has no palette. + */ +export function openHubPalette(): boolean { + const open = hubContext()?.commands?.openPalette; + if (typeof open !== 'function') return false; + try { + open(); + return true; + } catch { + return false; + } +} diff --git a/app/src/pages/component-tree.ts b/app/src/pages/component-tree.ts index b1233d7c..4abab9f9 100644 --- a/app/src/pages/component-tree.ts +++ b/app/src/pages/component-tree.ts @@ -36,6 +36,7 @@ import { import { HydrationSection, type HydrationReport } from './hydration-section'; import { CdRecording, type CdPage } from './cd-recording'; import type { ComponentFocus } from '../types/component-focus.types'; +import type { ComponentCommand } from '../types/component-command.types'; import type { InjectorFocus } from '../types/injector-focus.types'; import { SourceLink } from '../ui/source-link'; import { actionAllowed } from '../devtools-config'; @@ -1641,6 +1642,9 @@ export class ComponentTree { readonly focus = input(null); readonly showForm = output(); readonly focusHandled = output(); + /** A palette command to run once the tree shows a live page. */ + readonly command = input(null); + readonly commandHandled = output(); /** Whether the Injectors tab is on, so "Show in Injectors" can open it. */ readonly canShowInjector = input(false); readonly showInjector = output(); @@ -1675,6 +1679,9 @@ export class ComponentTree { private readonly injector = inject(Injector); private readonly host = inject>(ElementRef); private readonly filterInput = viewChild>('filterInput'); + private readonly cdRecording = viewChild(CdRecording); + /** Whether the server sent the component tree state yet, so an empty one means no page. */ + private readonly pagesKnown = signal(false); private readonly cleanups: (() => void)[] = []; private selection = { pageId: null as string | null, detailId: null as string | null }; @@ -1963,6 +1970,38 @@ export class ComponentTree { this.focusHandled.emit(); }); }); + effect(() => { + const command = this.command(); + if (!command) return; + if (!this.live()) { + // The tab already explains that no live page is connected. + if (this.pagesKnown()) untracked(() => this.commandHandled.emit()); + return; + } + if (command.kind === 'pick') { + untracked(() => { + if (this.native()) this.say('Picking needs a page in a browser.'); + else if (!this.picking()) void this.pick(); + this.commandHandled.emit(); + }); + return; + } + const recording = this.cdRecording(); + if (!recording) { + if (this.native() || this.staticReport()) { + untracked(() => { + this.say('This page cannot record change detection.'); + this.commandHandled.emit(); + }); + } + return; + } + untracked(() => { + if (command.kind === 'cd-clear') void recording.clear(); + else if ((command.kind === 'cd-start') !== recording.recording()) void recording.toggle(); + this.commandHandled.emit(); + }); + }); this.destroyRef.onDestroy(() => { this.highlight(null); for (const cleanup of this.cleanups.splice(0)) cleanup(); @@ -1978,11 +2017,14 @@ export class ComponentTree { const applyTree = (value: unknown) => { const pages = (value as { pages?: Record } | null)?.pages; this.applyPages(pages && typeof pages === 'object' ? pages : {}); + // A state the client hasn't loaded from the server yet says nothing. + if (value !== undefined) this.pagesKnown.set(true); }; applyTree(tree.value()); this.cleanups.push(tree.on('updated', applyTree)); } catch { this.applyPages({}); + this.pagesKnown.set(true); } try { const cd = await my.rpc.sharedState('change-detection'); diff --git a/app/src/pages/errors-inspector.ts b/app/src/pages/errors-inspector.ts new file mode 100644 index 00000000..81245867 --- /dev/null +++ b/app/src/pages/errors-inspector.ts @@ -0,0 +1,660 @@ +import { + Component, + DestroyRef, + computed, + effect, + inject, + input, + linkedSignal, + output, + signal, +} from '@angular/core'; +import type { DevframeRpcClient } from 'devframe/client'; +import { time } from '../format'; +import { hostPageId } from '../page-id'; +import { Select, type SelectOption } from '../ui/select'; +import type { ComponentFocus } from '../types/component-focus.types'; +import { + ALL_PAGES, + CONSOLE_LEVELS, + SOURCE_LABELS, + codeLink, + consoleOf, + defaultErrorsPage, + errorsOf, + errorsPages, + type ConsoleLevel, + type ErrorsPage, +} from './errors-types'; + +type View = 'errors' | 'console'; + +const LEVEL_TONE: Record = { + error: 'danger', + warn: 'warn', + info: 'accent', + log: 'plain', + debug: 'plain', +}; + +@Component({ + selector: 'app-errors-inspector', + imports: [Select], + template: ` + @if (!loaded()) { +

Loading errors…

+ } @else if (failed()) { + + } @else if (!pages().length) { +
+

No page reports errors yet.

+

+ Open the app with the overlay loaded. Errors and console calls show up here as they + happen. +

+
+ } @else { +

+ Errors from Angular's ErrorHandler, uncaught errors and unhandled promise rejections on the + live page, grouped by message, and the page's console calls. Messages and values are masked + like other live data. +

+ +
+
+ + +
+ + @if (view() === 'console') { + + } + @if (pageOptions().length > 2) { + + } + {{ countText() }} +
+ + @if (view() === 'errors') { +
+

Errors

+ @if (unwrapped()) { +

+ Angular's ErrorHandler isn't wrapped on this page yet, so errors Angular catches show + up only when the default handler logs them. +

+ } + @if (droppedErrors()) { +

+ {{ droppedErrors() }} older error + {{ droppedErrors() === 1 ? 'group was' : 'groups were' }} + dropped. Each page keeps its last 100. +

+ } + @if (!errors().length) { +

+ No errors since the page loaded. Errors show up here as the app hits them. +

+ } @else if (!shownErrors().length) { +
+

No error matches “{{ filter() }}”.

+ +
+ } @else { +
    + @for (error of shownErrors(); track error.pageId + error.id) { +
  1. +
    + + {{ error.count }}× + + {{ error.message }} +
    +
    + @if (error.code; as ngCode) { + @if (codeLink(ngCode, error.docUrl).href; as href) { + {{ ngCode + }} reference (opens in a new tab) + } @else { + {{ ngCode }} + } + } + @for (source of error.sources; track source) { + {{ sourceLabels[source] }} + } + Last at {{ time(error.lastAt) }} + @if (showPage()) { + {{ pageLabel(error.pageId) }} + } + @if (error.owner; as owner) { + @if (canShowComponent()) { + + } @else { + In {{ owner.name }} + } + } +
    + @if (error.stack) { +
    + Stack +
    {{ error.stack }}
    +
    + } +
  2. + } +
+ } +
+ } @else { +
+

Console

+ @if (droppedConsole()) { +

+ {{ droppedConsole() }} older {{ droppedConsole() === 1 ? 'call was' : 'calls were' }} + dropped. Each page keeps its last 200. +

+ } + @if (!entries().length) { +

+ No console calls since the overlay connected. They show up here as the app logs. +

+ } @else if (!shownEntries().length) { +
+

No console call matches the filters.

+ +
+ } @else { +
    + @for (entry of shownEntries(); track entry.pageId + entry.id) { +
  1. + {{ + entry.level + }} + {{ entry.text }} + @if (entry.count > 1) { + {{ entry.count }}× + } + @if (entry.code; as ngCode) { + @if (codeLink(ngCode, entry.docUrl).href; as href) { + {{ ngCode }} reference (opens in a new tab) + } @else { + {{ ngCode }} + } + } + +
  2. + } +
+ } +
+ } + } + `, + styles: ` + @use 'mixins' as m; + :host { + display: block; + font-size: 13px; + } + .intro { + margin: 0 0 12px; + color: var(--text-2); + line-height: 1.5; + } + code, + pre { + font-family: var(--font-mono); + font-size: 12px; + } + .muted { + color: var(--text-2); + } + .toolbar { + position: sticky; + top: 0; + z-index: 2; + display: flex; + flex-wrap: wrap; + gap: 8px 12px; + align-items: center; + margin: 0 0 12px; + padding: 8px; + background: color-mix(in srgb, var(--surface) 85%, transparent); + backdrop-filter: blur(10px); + border: 1px solid var(--border); + border-radius: var(--radius); + } + .views { + display: inline-flex; + gap: 4px; + } + .view { + display: inline-flex; + gap: 6px; + align-items: center; + height: var(--control-h); + padding: 0 12px; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + background: var(--surface); + color: var(--text); + font: inherit; + cursor: pointer; + transition: background-color 150ms var(--ease); + } + .view:hover { + background: var(--surface-2); + } + .view[aria-pressed='true'] { + border-color: var(--accent-line); + background: var(--accent-soft); + color: var(--text-strong); + } + .view:focus-visible { + @include m.focus-ring; + } + .badge { + color: var(--text-2); + font-variant-numeric: tabular-nums; + } + .search { + position: relative; + flex: 1 1 200px; + min-width: 0; + } + .search-icon { + position: absolute; + top: 50%; + left: 12px; + width: 14px; + height: 14px; + transform: translateY(-50%); + fill: none; + stroke: var(--text-3); + stroke-width: 2.2; + stroke-linecap: round; + pointer-events: none; + } + input[type='search'] { + width: 100%; + height: var(--control-h); + padding: 0 12px 0 34px; + background: var(--bg); + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + color: var(--text); + font-size: 13px; + } + input[type='search']:focus { + @include m.field-focus; + } + .level-select, + .page-select { + flex: 0 1 180px; + min-width: 0; + } + .count { + margin-left: auto; + color: var(--text-2); + font-size: 12px; + } + .notice { + margin: 0 0 12px; + padding: 8px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + background: var(--surface); + color: var(--text-2); + line-height: 1.5; + } + .errors, + .console { + display: grid; + gap: 6px; + margin: 0; + padding: 0; + list-style: none; + } + .error { + @include m.panel; + display: grid; + gap: 6px; + min-width: 0; + padding: 8px 12px; + } + .head { + display: flex; + gap: 8px; + align-items: baseline; + min-width: 0; + } + .message { + min-width: 0; + color: var(--text-strong); + overflow-wrap: anywhere; + white-space: pre-wrap; + } + .times { + flex-shrink: 0; + color: var(--danger-text); + font-weight: 600; + font-variant-numeric: tabular-nums; + } + .meta { + display: flex; + flex-wrap: wrap; + gap: 6px 10px; + align-items: center; + font-size: 12px; + } + .chip { + display: inline-flex; + align-items: center; + padding: 1px 8px; + border: 1px solid transparent; + border-radius: 99px; + font-size: 11px; + font-weight: 600; + @include m.tint(accent); + } + .chip.source, + .chip.plain, + .chip[data-tone='plain'] { + border-color: var(--border); + background: var(--surface-2); + color: var(--text-2); + } + .chip[data-tone='danger'] { + @include m.tint(danger); + } + .chip[data-tone='warn'] { + @include m.tint(warn); + } + a.chip { + text-decoration: underline; + text-underline-offset: 2px; + } + a.chip:focus-visible { + @include m.focus-ring; + } + .link { + display: inline-flex; + gap: 4px; + align-items: baseline; + padding: 0; + border: 0; + border-radius: 2px; + background: none; + color: var(--accent-text); + font: inherit; + text-decoration: underline; + text-underline-offset: 2px; + cursor: pointer; + } + .link:focus-visible { + @include m.focus-ring; + } + details summary { + width: fit-content; + border-radius: 2px; + color: var(--text-2); + font-size: 12px; + cursor: pointer; + } + details summary:focus-visible { + @include m.focus-ring; + } + pre { + max-height: 240px; + margin: 6px 0 0; + padding: 8px; + overflow: auto; + border-radius: var(--radius-sm); + background: var(--bg); + color: var(--text); + white-space: pre; + } + pre:focus-visible { + @include m.focus-ring(-2px); + } + .entry { + display: flex; + flex-wrap: wrap; + gap: 4px 8px; + align-items: baseline; + min-width: 0; + padding: 6px 10px; + border-bottom: 1px solid var(--border); + } + .entry .level { + min-width: 44px; + justify-content: center; + } + .entry .times { + color: var(--text-2); + } + .text { + flex: 1 1 240px; + min-width: 0; + color: var(--text); + overflow-wrap: anywhere; + white-space: pre-wrap; + } + .when { + margin-left: auto; + color: var(--text-2); + font-size: 12px; + font-variant-numeric: tabular-nums; + } + .small { + height: var(--control-h); + padding: 0 12px; + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + background: var(--surface-2); + color: var(--text); + } + .small:focus-visible { + @include m.focus-ring; + } + .empty, + .state { + margin: 0 0 12px; + color: var(--text-2); + } + .empty p, + .state p { + margin: 0 0 8px; + } + `, +}) +export class ErrorsInspector { + readonly rpc = input(null); + /** Whether the Components tab is on, so "Show component" has somewhere to go. */ + readonly canShowComponent = input(true); + readonly showComponent = output(); + + private readonly destroyRef = inject(DestroyRef); + private readonly hostPageId = hostPageId(); + private unsubscribe?: () => void; + + protected readonly time = time; + protected readonly codeLink = codeLink; + protected readonly sourceLabels = SOURCE_LABELS; + protected readonly levelTone = LEVEL_TONE; + protected readonly allPages = ALL_PAGES; + protected readonly levelOptions: SelectOption[] = [ + { value: 'all', label: 'All levels' }, + ...CONSOLE_LEVELS.map((level) => ({ value: level, label: level })), + ]; + + readonly pages = signal([]); + readonly loaded = signal(false); + readonly failed = signal(false); + readonly view = signal('errors'); + readonly filter = signal(''); + readonly level = signal('all'); + /** Keeps the picked page while it reports, and falls back once it is gone. */ + readonly pageId = linkedSignal({ + source: () => this.pages(), + computation: (pages, previous) => + previous?.value && + (previous.value === ALL_PAGES || pages.some((page) => page.pageId === previous.value)) + ? previous.value + : defaultErrorsPage(pages, this.hostPageId), + }); + + readonly pageOptions = computed(() => [ + { value: ALL_PAGES, label: 'All pages' }, + ...this.pages().map((page) => ({ + value: page.pageId, + label: page.title || page.url || page.pageId, + hint: page.url, + })), + ]); + readonly showPage = computed(() => this.pageId() === ALL_PAGES && this.pages().length > 1); + private readonly picked = computed(() => + this.pages().filter((page) => this.pageId() === ALL_PAGES || page.pageId === this.pageId()), + ); + readonly unwrapped = computed(() => this.picked().some((page) => page.handler !== 'wrapped')); + readonly droppedErrors = computed(() => + this.picked().reduce((sum, page) => sum + page.dropped.errors, 0), + ); + readonly droppedConsole = computed(() => + this.picked().reduce((sum, page) => sum + page.dropped.console, 0), + ); + readonly errors = computed(() => errorsOf(this.pages(), this.pageId())); + readonly entries = computed(() => consoleOf(this.pages(), this.pageId())); + readonly shownErrors = computed(() => { + const text = this.filter().trim().toLowerCase(); + if (!text) return this.errors(); + return this.errors().filter( + (error) => + error.message.toLowerCase().includes(text) || + (error.code ?? '').toLowerCase().includes(text) || + (error.owner?.name ?? '').toLowerCase().includes(text), + ); + }); + readonly shownEntries = computed(() => { + const text = this.filter().trim().toLowerCase(); + const level = this.level(); + return this.entries().filter( + (entry) => + (level === 'all' || entry.level === level) && + (!text || entry.text.toLowerCase().includes(text)), + ); + }); + readonly countText = computed(() => + this.view() === 'errors' + ? `${this.shownErrors().length} of ${this.errors().length} errors` + : `${this.shownEntries().length} of ${this.entries().length} calls`, + ); + + constructor() { + effect(() => { + const client = this.rpc(); + if (client) void this.load(client); + }); + this.destroyRef.onDestroy(() => this.unsubscribe?.()); + } + + retry() { + const client = this.rpc(); + if (client) void this.load(client); + } + + clearFilters() { + this.filter.set(''); + this.level.set('all'); + } + + timesLabel(count: number): string { + return count === 1 ? 'Once' : `${count} times`; + } + + pageLabel(pageId: string): string { + const page = this.pages().find((p) => p.pageId === pageId); + return page?.title || page?.url || pageId; + } + + private async load(client: DevframeRpcClient) { + this.failed.set(false); + try { + const state = await client.scope('pangular').rpc.sharedState('errors'); + if (this.destroyRef.destroyed) return; + const apply = (value: unknown) => this.pages.set(errorsPages(value)); + apply(state.value()); + this.unsubscribe?.(); + this.unsubscribe = state.on('updated', apply); + } catch { + this.failed.set(true); + } finally { + this.loaded.set(true); + } + } +} diff --git a/app/src/pages/errors-types.ts b/app/src/pages/errors-types.ts new file mode 100644 index 00000000..52268ca6 --- /dev/null +++ b/app/src/pages/errors-types.ts @@ -0,0 +1,127 @@ +/** The Errors inspector data as the `errors` shared state holds it. */ + +export type ConsoleLevel = 'log' | 'info' | 'warn' | 'error' | 'debug'; + +export const CONSOLE_LEVELS: readonly ConsoleLevel[] = ['log', 'info', 'warn', 'error', 'debug']; + +export interface ErrorOwner { + /** The host element id the Components tab selects. */ + id: string; + name: string; +} + +export interface ErrorGroup { + id: string; + message: string; + name?: string; + code?: string; + docUrl?: string; + count: number; + firstAt: number; + lastAt: number; + sources: ('handler' | 'window' | 'promise')[]; + stack?: string; + owner?: ErrorOwner; +} + +export interface ConsoleEntry { + id: number; + level: ConsoleLevel; + text: string; + at: number; + count: number; + code?: string; + docUrl?: string; +} + +export interface ErrorsPage { + pageId: string; + url: string; + title: string; + reportedAt: number; + handler: 'wrapped' | 'none'; + errors: ErrorGroup[]; + console: ConsoleEntry[]; + dropped: { errors: number; console: number }; +} + +/** An error group with the page it comes from, for the list across pages. */ +export interface PageError extends ErrorGroup { + pageId: string; +} + +export interface PageConsoleEntry extends ConsoleEntry { + pageId: string; +} + +export const ALL_PAGES = 'all'; + +export const SOURCE_LABELS: Record = { + handler: 'ErrorHandler', + window: 'Uncaught', + promise: 'Unhandled rejection', +}; + +function isRecord(value: unknown): value is Record { + return !!value && typeof value === 'object'; +} + +/** + * The pages in the shared state, newest report first. The server keys groups + * and console entries by id, so one push patches one entry; the panel reads + * them as lists. + */ +export function errorsPages(value: unknown): ErrorsPage[] { + const pages = isRecord(value) ? value['pages'] : undefined; + if (!isRecord(pages)) return []; + return Object.values(pages) + .filter( + (page): page is Record => + isRecord(page) && typeof page['pageId'] === 'string', + ) + .map((page) => ({ + pageId: page['pageId'] as string, + url: typeof page['url'] === 'string' ? page['url'] : '', + title: typeof page['title'] === 'string' ? page['title'] : '', + reportedAt: typeof page['reportedAt'] === 'number' ? page['reportedAt'] : 0, + handler: page['handler'] === 'wrapped' ? ('wrapped' as const) : ('none' as const), + errors: isRecord(page['errors']) ? (Object.values(page['errors']) as ErrorGroup[]) : [], + console: isRecord(page['console']) + ? (Object.values(page['console']) as ConsoleEntry[]).sort((a, b) => a.id - b.id) + : [], + dropped: isRecord(page['dropped']) + ? { + errors: Number(page['dropped']['errors']) || 0, + console: Number(page['dropped']['console']) || 0, + } + : { errors: 0, console: 0 }, + })) + .sort((a, b) => b.reportedAt - a.reportedAt); +} + +/** The page to show first: the panel's own page, else the newest. */ +export function defaultErrorsPage(pages: ErrorsPage[], hostPageId: string | null): string { + if (hostPageId && pages.some((page) => page.pageId === hostPageId)) return hostPageId; + return pages.length > 1 ? ALL_PAGES : (pages[0]?.pageId ?? ALL_PAGES); +} + +/** The error groups of one page or of every page, most recent first. */ +export function errorsOf(pages: ErrorsPage[], pageId: string): PageError[] { + return pages + .filter((page) => pageId === ALL_PAGES || page.pageId === pageId) + .flatMap((page) => page.errors.map((group) => ({ ...group, pageId: page.pageId }))) + .sort((a, b) => b.lastAt - a.lastAt); +} + +/** The console entries of one page or of every page, newest first. */ +export function consoleOf(pages: ErrorsPage[], pageId: string): PageConsoleEntry[] { + return pages + .filter((page) => pageId === ALL_PAGES || page.pageId === pageId) + .flatMap((page) => page.console.map((entry) => ({ ...entry, pageId: page.pageId }))) + .sort((a, b) => b.at - a.at || b.id - a.id); +} + +/** `NG0100` and its reference page, or just the code when the reference has none. */ +export function codeLink(code: string, docUrl?: string): { code: string; href?: string } { + return docUrl?.startsWith('https://angular.dev/errors/') ? { code, href: docUrl } : { code }; +} diff --git a/app/src/pages/settings.ts b/app/src/pages/settings.ts new file mode 100644 index 00000000..42f9388d --- /dev/null +++ b/app/src/pages/settings.ts @@ -0,0 +1,520 @@ +import { + Component, + ElementRef, + Injector, + afterNextRender, + computed, + inject, + input, + model, + signal, +} from '@angular/core'; +import { + moveTab, + orderedTabIds, + setTabHidden, + setTabPinned, + DEFAULT_TAB_LAYOUT, + type TabLayout, + type ThemePreference, +} from '../shell-prefs'; +import { TabIcon } from './tab-icon'; + +export interface SettingsTab { + id: string; + label: string; +} + +const THEMES: { value: ThemePreference; label: string; hint: string }[] = [ + { value: 'system', label: 'System', hint: 'Follows the hub, or your system without it' }, + { value: 'light', label: 'Light', hint: 'Always light' }, + { value: 'dark', label: 'Dark', hint: 'Always dark' }, +]; + +/** Per-viewer settings: theme, tab bar layout and the popup's passive mode. */ +@Component({ + selector: 'app-settings', + imports: [TabIcon], + template: ` +

+ Settings for this panel in this browser. They are saved in the browser's local storage, so + every panel on this address uses them. +

+ +
+

Theme

+
+ @for (option of themes; track option.value) { + + } +
+
+ +
+
+

Tabs

+ +
+

+ Pinned tabs come first in the tab bar. Hidden tabs stay reachable from the command palette + and from links. Use the arrow buttons, or Alt with ↑ and + ↓ on a row, to change the order. +

+
    + @for (tab of orderedTabs(); track tab.id; let first = $first, last = $last) { +
  1. + + + {{ tab.label }} + @if (isPinned(tab.id)) { + Pinned + } + + + + + + + +
  2. + } +
+
+ +
+

Popup on the page

+ +

+ @if (hotkey(); as shortcut) { + Press {{ shortcut }} on your app's page to open or close the panel. The button + shows while the panel is open. The popup on the page saves this setting. + } @else { + The popup shortcut is turned off in the devtools config (popup.hotkey), so + the button always shows. + } +

+
+ +
+

Keyboard shortcuts

+ + + + + + + + + + + + + + + + + + +
+ Keyboard shortcuts +
ShortcutAction
+ {{ paletteShortcut() }} + Open the command palette in the panel
+ @if (hotkey(); as shortcut) { + {{ shortcut }} + } @else { + Off + } + Open or close the popup on your app's page
+
+

{{ announcement() }}

+ `, + styles: ` + @use 'mixins' as m; + + :host { + display: block; + max-width: 760px; + } + .intro { + max-width: 720px; + margin: 0 0 16px; + color: var(--text-2); + line-height: 1.5; + } + .card { + margin: 0 0 16px; + padding: 16px; + @include m.panel(1); + } + .card-head { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 8px; + } + h2 { + margin: 0 0 10px; + color: var(--text-strong); + font-size: 15px; + font-weight: 650; + } + .card-head h2 { + margin: 0; + } + .hint { + margin: 8px 0 12px; + color: var(--text-2); + font-size: 12px; + line-height: 1.5; + } + .themes { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 8px; + } + .theme { + position: relative; + display: grid; + grid-template-columns: auto 1fr; + gap: 2px 8px; + align-items: center; + padding: 10px 12px; + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + background: var(--bg); + cursor: pointer; + .hint { + grid-column: 2; + margin: 0; + } + &.checked { + border-color: var(--accent-line); + background: var(--accent-soft); + } + &:has(input:focus-visible) { + @include m.focus-ring(2px); + } + } + .theme input { + margin: 0; + accent-color: var(--accent); + } + .theme-label { + color: var(--text-strong); + font-weight: 600; + } + .tab-list { + margin: 0; + padding: 0; + list-style: none; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + } + .tab-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px 12px; + min-height: 44px; + padding: 4px 8px 4px 12px; + color: var(--text); + & + & { + border-top: 1px solid var(--border); + } + app-tab-icon { + color: var(--text-3); + } + } + .tab-row.hidden-tab .tab-label { + color: var(--text-2); + } + .tab-label { + display: inline-flex; + flex: 1 1 120px; + align-items: center; + gap: 8px; + min-width: 0; + } + .tag { + padding: 1px 8px; + border: 1px solid; + border-radius: 999px; + font-size: 11px; + font-weight: 600; + @include m.tint(accent); + } + .action { + display: inline-flex; + align-items: center; + height: var(--control-h); + padding: 0 12px; + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + background: var(--surface-2); + color: var(--text); + font: inherit; + font-weight: 500; + cursor: pointer; + &.small { + height: 28px; + padding: 0 10px; + font-size: 12px; + } + &[aria-pressed='true'] { + border-color: var(--accent-line); + background: var(--accent-soft); + color: var(--text-strong); + } + &:hover:not(:disabled) { + background: var(--surface-3); + } + &:disabled { + color: var(--text-3); + cursor: default; + } + &:focus-visible { + @include m.focus-ring; + } + } + .check { + display: inline-flex; + align-items: center; + gap: 6px; + color: var(--text-2); + font-size: 12px; + cursor: pointer; + input { + margin: 0; + accent-color: var(--accent); + } + input:focus-visible { + @include m.focus-ring; + } + &.wide { + color: var(--text); + font-size: 13px; + } + } + .moves { + display: inline-flex; + gap: 4px; + margin-left: auto; + } + .icon { + display: grid; + place-items: center; + width: 28px; + height: 28px; + padding: 0; + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + background: var(--surface-2); + color: var(--text); + cursor: pointer; + svg { + width: 16px; + height: 16px; + fill: none; + stroke: currentColor; + stroke-width: 2; + } + &:hover:not(:disabled) { + background: var(--surface-3); + } + &:disabled { + color: var(--text-3); + opacity: 0.6; + cursor: default; + } + &:focus-visible { + @include m.focus-ring; + } + } + kbd { + padding: 1px 6px; + border: 1px solid var(--border-strong); + border-radius: 4px; + background: var(--surface-2); + color: var(--text); + font-family: var(--font-mono); + font-size: 11px; + } + code { + font-family: var(--font-mono); + } + .keys { + width: 100%; + border-collapse: collapse; + font-size: 13px; + th { + padding: 6px 8px; + text-align: left; + @include m.label; + } + td { + padding: 8px; + border-top: 1px solid var(--border); + color: var(--text); + } + } + `, +}) +export class Settings { + /** Every tab the panel can show here, in the default order. */ + readonly tabs = input([]); + readonly layout = model(DEFAULT_TAB_LAYOUT); + readonly theme = model('system'); + readonly passive = model(false); + /** The popup shortcut as the platform writes it, or `false` when it is off. */ + readonly hotkey = input(false); + readonly paletteShortcut = input('Ctrl+K'); + + protected readonly themes = THEMES; + protected readonly announcement = signal(''); + private readonly host = inject>(ElementRef); + private readonly injector = inject(Injector); + + private readonly ids = computed(() => this.tabs().map((tab) => tab.id)); + readonly orderedTabs = computed(() => { + const byId = new Map(this.tabs().map((tab) => [tab.id, tab])); + return orderedTabIds(this.ids(), this.layout()).map((id) => byId.get(id)!); + }); + protected readonly isDefaultLayout = computed(() => { + const { order, hidden, pinned } = this.layout(); + const shown = orderedTabIds(this.ids(), this.layout()); + return ( + !hidden.length && + !pinned.length && + (!order.length || shown.every((id, index) => id === this.ids()[index])) + ); + }); + + isPinned(id: string) { + return this.layout().pinned.includes(id); + } + + isHidden(id: string) { + return this.layout().hidden.includes(id) && !this.isPinned(id); + } + + canMove(id: string, delta: -1 | 1) { + return moveTab(this.ids(), this.layout(), id, delta) !== this.layout(); + } + + move(id: string, delta: -1 | 1) { + const next = moveTab(this.ids(), this.layout(), id, delta); + if (next === this.layout()) return; + this.layout.set(next); + const order = orderedTabIds(this.ids(), next); + const label = this.label(id); + this.say(`${label} moved to position ${order.indexOf(id) + 1} of ${order.length}.`); + // Keep focus on the moved row, on the same button, or the other one at an end. + afterNextRender( + () => { + const row = [...this.host.nativeElement.querySelectorAll('.tab-row')].find( + (candidate) => candidate.dataset['tab'] === id, + ); + const wanted = row?.querySelector( + `[data-move="${delta < 0 ? 'up' : 'down'}"]`, + ); + const other = row?.querySelector( + `[data-move="${delta < 0 ? 'down' : 'up'}"]`, + ); + (wanted && !wanted.disabled ? wanted : other)?.focus(); + }, + { injector: this.injector }, + ); + } + + onRowKey(event: KeyboardEvent, id: string) { + if (!event.altKey || (event.key !== 'ArrowUp' && event.key !== 'ArrowDown')) return; + event.preventDefault(); + this.move(id, event.key === 'ArrowUp' ? -1 : 1); + } + + togglePinned(id: string) { + const pinned = !this.isPinned(id); + this.layout.set(setTabPinned(this.ids(), this.layout(), id, pinned)); + this.say(pinned ? `${this.label(id)} pinned.` : `${this.label(id)} unpinned.`); + } + + setShown(id: string, shown: boolean) { + this.layout.set(setTabHidden(this.layout(), id, !shown)); + this.say(shown ? `${this.label(id)} shown.` : `${this.label(id)} hidden.`); + } + + resetTabs() { + this.layout.set(DEFAULT_TAB_LAYOUT); + this.say('Tabs reset to the default order.'); + } + + private label(id: string) { + return this.tabs().find((tab) => tab.id === id)?.label ?? id; + } + + private say(message: string) { + this.announcement.update((current) => (current === message ? `${message} ` : message)); + } +} diff --git a/app/src/pages/tab-icon.ts b/app/src/pages/tab-icon.ts index 53fdba4b..50079c0d 100644 --- a/app/src/pages/tab-icon.ts +++ b/app/src/pages/tab-icon.ts @@ -63,6 +63,17 @@ import { Component, input } from '@angular/core'; } + @case ('settings') { + + + } + @case ('errors') { + + + + } @case ('analog') { } diff --git a/app/src/palette-filter.ts b/app/src/palette-filter.ts new file mode 100644 index 00000000..67e252f0 --- /dev/null +++ b/app/src/palette-filter.ts @@ -0,0 +1,57 @@ +/** A command as the palette lists it. */ +export interface PaletteCommand { + id: string; + title: string; + group: string; + keywords?: string; + /** A shortcut that also runs it, shown beside the title. */ + shortcut?: string; +} + +/** + * How well `query` matches `text` as a subsequence, or `-1` when it doesn't. + * Consecutive letters and letters at the start of a word score higher, so + * `gtsig` finds "Go to Signals" and `sig` puts it before "Design". + */ +export function fuzzyScore(text: string, query: string): number { + const haystack = text.toLowerCase(); + const needle = query.toLowerCase().replace(/\s+/g, ''); + if (!needle) return 0; + let score = 0; + let from = 0; + let previous = -2; + for (const char of needle) { + const index = haystack.indexOf(char, from); + if (index < 0) return -1; + const wordStart = index === 0 || /[\s:&/-]/.test(haystack[index - 1]); + score += 1; + if (index === previous + 1) score += 3; + if (wordStart) score += 4; + previous = index; + from = index + 1; + } + // Shorter texts with the same letters read as the closer match. + return score - haystack.length / 100; +} + +/** + * The commands that match `query`, best first. A title match beats one in + * the group or keywords. An empty query keeps the given order. + */ +export function filterCommands( + commands: readonly T[], + query: string, +): T[] { + const trimmed = query.trim(); + if (!trimmed) return [...commands]; + return commands + .map((command, index) => { + const title = fuzzyScore(command.title, trimmed); + const extra = fuzzyScore(`${command.group} ${command.keywords ?? ''}`, trimmed); + const score = Math.max(title >= 0 ? title + 10 : -1, extra); + return { command, index, score }; + }) + .filter((entry) => entry.score >= 0) + .sort((a, b) => b.score - a.score || a.index - b.index) + .map((entry) => entry.command); +} diff --git a/app/src/shell-prefs.ts b/app/src/shell-prefs.ts new file mode 100644 index 00000000..c0c274a5 --- /dev/null +++ b/app/src/shell-prefs.ts @@ -0,0 +1,187 @@ +const PREF_KEY = 'pangular-pref'; + +/** The theme the viewer picked in Settings; `system` follows the hub or the system. */ +export type ThemePreference = 'system' | 'light' | 'dark'; + +/** + * How the viewer arranged the tab bar in Settings. `order` lists tab ids in + * the order they chose; tabs it doesn't name keep their default place after + * the ones it does. Pinned tabs come first, and a pinned tab is never hidden. + */ +export interface TabLayout { + order: string[]; + hidden: string[]; + pinned: string[]; +} + +export const DEFAULT_TAB_LAYOUT: TabLayout = { order: [], hidden: [], pinned: [] }; + +function read(name: string): string | null { + try { + return localStorage.getItem(`${PREF_KEY}:${name}`); + } catch { + return null; + } +} + +function write(name: string, value: string | null) { + try { + if (value === null) localStorage.removeItem(`${PREF_KEY}:${name}`); + else localStorage.setItem(`${PREF_KEY}:${name}`, value); + } catch { + // Blocked storage only forgets the preference on the next reload. + } +} + +export function storedThemePreference(): ThemePreference { + const value = read('theme'); + return value === 'light' || value === 'dark' ? value : 'system'; +} + +export function storeThemePreference(value: ThemePreference) { + write('theme', value === 'system' ? null : value); +} + +function ids(value: unknown): string[] { + if (!Array.isArray(value)) return []; + const valid = value.filter( + (id): id is string => typeof id === 'string' && id.length > 0 && id.length <= 40, + ); + return [...new Set(valid)].slice(0, 50); +} + +export function storedTabLayout(): TabLayout { + const raw = read('tabs'); + if (!raw) return DEFAULT_TAB_LAYOUT; + try { + const parsed: unknown = JSON.parse(raw); + if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return DEFAULT_TAB_LAYOUT; + // Anything in storage may be stale or hand edited, so each list is checked. + const saved = parsed as Record; + return { + order: ids(saved['order']), + hidden: ids(saved['hidden']), + pinned: ids(saved['pinned']), + }; + } catch { + return DEFAULT_TAB_LAYOUT; + } +} + +export function storeTabLayout(layout: TabLayout) { + const empty = !layout.order.length && !layout.hidden.length && !layout.pinned.length; + write('tabs', empty ? null : JSON.stringify(layout)); +} + +/** Passive mode, as the panel last set it. The popup on the page keeps its own copy. */ +export function storedPassive(): boolean { + return read('passive') === 'true'; +} + +export function storePassive(value: boolean) { + write('passive', value ? 'true' : null); +} + +/** `ids` in the viewer's order: pinned first, then the rest, each in `layout.order`. */ +export function orderedTabIds(all: readonly string[], layout: TabLayout): string[] { + const rank = (id: string) => { + const index = layout.order.indexOf(id); + return index < 0 ? layout.order.length + all.indexOf(id) : index; + }; + const sorted = [...all].sort((a, b) => rank(a) - rank(b)); + const pinned = sorted.filter((id) => layout.pinned.includes(id)); + return [...pinned, ...sorted.filter((id) => !layout.pinned.includes(id))]; +} + +/** + * The tabs of the bar in the viewer's order, without the hidden ones. `keep` + * stays even when hidden, so the open tab is always in the bar. + */ +export function arrangeTabs( + tabs: readonly T[], + layout: TabLayout, + keep?: string, +): T[] { + const byId = new Map(tabs.map((tab) => [tab.id, tab])); + return orderedTabIds( + tabs.map((tab) => tab.id), + layout, + ) + .filter((id) => id === keep || layout.pinned.includes(id) || !layout.hidden.includes(id)) + .map((id) => byId.get(id)!); +} + +/** + * Moves a tab one place up (`-1`) or down (`1`) among `all`, as Settings + * shows them. A tab stays inside its section: pinned tabs move among the + * pinned ones, the others among the others. + */ +export function moveTab( + all: readonly string[], + layout: TabLayout, + id: string, + delta: -1 | 1, +): TabLayout { + const order = orderedTabIds(all, layout); + const index = order.indexOf(id); + const target = index + delta; + if (index < 0 || target < 0 || target >= order.length) return layout; + const pinned = layout.pinned.includes(id); + if (layout.pinned.includes(order[target]) !== pinned) return layout; + const next = [...order]; + [next[index], next[target]] = [next[target], next[index]]; + return { ...layout, order: next }; +} + +export function setTabHidden(layout: TabLayout, id: string, hidden: boolean): TabLayout { + const rest = layout.hidden.filter((other) => other !== id); + return { + ...layout, + hidden: hidden ? [...rest, id] : rest, + pinned: hidden ? layout.pinned.filter((other) => other !== id) : layout.pinned, + }; +} + +export function setTabPinned( + all: readonly string[], + layout: TabLayout, + id: string, + pinned: boolean, +): TabLayout { + const rest = layout.pinned.filter((other) => other !== id); + // Keep today's visible order, so pinning moves only the pinned tab. + const order = orderedTabIds(all, layout); + return { + order, + pinned: pinned ? [...rest, id] : rest, + hidden: pinned ? layout.hidden.filter((other) => other !== id) : layout.hidden, + }; +} + +/** Whether the viewer is on macOS or iOS, where `Mod` shortcuts use Cmd. */ +export function isMacPlatform(): boolean { + try { + const nav = navigator as Navigator & { userAgentData?: { platform?: string } }; + return /mac|iphone|ipad|ipod/i.test(nav.userAgentData?.platform ?? nav.platform ?? ''); + } catch { + return false; + } +} + +/** + * Whether the panel runs in the popup on the app's page, which has dock + * modes and passive mode. Only frames on the same origin can tell. + */ +export function inPopup(win: Window = window): boolean { + try { + for (let current = win; current !== current.parent; current = current.parent) { + const root = current.frameElement?.getRootNode(); + if (root && 'host' in root && (root.host as Element | null)?.id === 'pangular-popup-root') { + return true; + } + } + } catch { + // a frame on another origin; the popup can't be named + } + return false; +} diff --git a/app/src/theme.service.ts b/app/src/theme.service.ts index a2aca7af..87d3e0a7 100644 --- a/app/src/theme.service.ts +++ b/app/src/theme.service.ts @@ -1,10 +1,17 @@ import { DestroyRef, Service, effect, inject, signal } from '@angular/core'; +import { storeThemePreference, storedThemePreference, type ThemePreference } from './shell-prefs'; export type Theme = 'dark' | 'light'; @Service() export class ThemeService { readonly current = signal('dark'); + /** What the viewer picked in Settings. `system` follows the hub, the extension or the system. */ + readonly preference = signal(storedThemePreference()); + /** The theme the hub, the extension, a `data-theme` attribute or the system asks for. */ + private source: Theme = 'dark'; + /** Whether the source set `data-theme`, which the system preference never does. */ + private sourceAttr = false; constructor() { const destroyRef = inject(DestroyRef); @@ -13,19 +20,21 @@ export class ThemeService { let pinned = attr === 'light' || attr === 'dark'; if (attr === 'light' || attr === 'dark') { - this.current.set(attr); + this.fromSource(attr, true); } else if (colorRoot) { pinned = true; - this.apply(hubTheme(colorRoot)); + this.fromSource(hubTheme(colorRoot), true); } else { const query = prefersLight(); if (query) { - this.current.set(query.matches ? 'light' : 'dark'); + this.fromSource(query.matches ? 'light' : 'dark', false); const onChange = (e: MediaQueryListEvent) => { - if (!pinned) this.current.set(e.matches ? 'light' : 'dark'); + if (!pinned) this.fromSource(e.matches ? 'light' : 'dark', false); }; query.addEventListener('change', onChange); destroyRef.onDestroy(() => query.removeEventListener('change', onChange)); + } else { + this.resolve(); } } @@ -50,13 +59,13 @@ export class ThemeService { const msg = e.data as { type?: unknown; theme?: unknown } | null; if (msg?.type !== 'pangular:theme-change') return; pinned = true; - this.apply(msg.theme === 'dark' ? 'dark' : 'light'); + this.fromSource(msg.theme === 'dark' ? 'dark' : 'light', true); }; window.addEventListener('message', onMessage); let observer: MutationObserver | undefined; if (colorRoot) { - observer = new MutationObserver(() => this.apply(hubTheme(colorRoot))); + observer = new MutationObserver(() => this.fromSource(hubTheme(colorRoot), true)); observer.observe(colorRoot, { attributes: true, attributeFilter: ['class'] }); } @@ -67,9 +76,28 @@ export class ThemeService { }); } - private apply(theme: Theme) { + /** Picks light, dark or the source's theme, and keeps the choice for the next visit. */ + setPreference(preference: ThemePreference) { + this.preference.set(preference); + storeThemePreference(preference); + this.resolve(); + } + + private fromSource(theme: Theme, attr: boolean) { + this.source = theme; + this.sourceAttr = attr; + this.resolve(); + } + + private resolve() { + const preference = this.preference(); + const theme = preference === 'system' ? this.source : preference; this.current.set(theme); - document.documentElement.dataset['theme'] = theme; + const root = document.documentElement; + // The system preference reaches the styles through the media query, so + // `data-theme` is only set when something picked a theme. + if (preference !== 'system' || this.sourceAttr) root.dataset['theme'] = theme; + else delete root.dataset['theme']; } } diff --git a/app/src/types/component-command.types.ts b/app/src/types/component-command.types.ts new file mode 100644 index 00000000..1c201a06 --- /dev/null +++ b/app/src/types/component-command.types.ts @@ -0,0 +1,7 @@ +/** + * An action for the Components tab to run, from the command palette or the + * hub's. A new object each time, so running the same command again counts. + */ +export interface ComponentCommand { + kind: 'pick' | 'cd-start' | 'cd-stop' | 'cd-clear'; +} diff --git a/app/src/types/tab.types.ts b/app/src/types/tab.types.ts index bf2c8b01..340cad06 100644 --- a/app/src/types/tab.types.ts +++ b/app/src/types/tab.types.ts @@ -9,7 +9,9 @@ export type Tab = | 'forms' | 'network' | 'analog' - | 'capacitor'; + | 'capacitor' + | 'settings' + | 'errors'; export type Tabs = { id: Tab; diff --git a/app/src/ui/command-palette.ts b/app/src/ui/command-palette.ts new file mode 100644 index 00000000..3bc421a3 --- /dev/null +++ b/app/src/ui/command-palette.ts @@ -0,0 +1,324 @@ +import { + Component, + ElementRef, + Injector, + afterNextRender, + computed, + effect, + inject, + input, + linkedSignal, + model, + output, + signal, + untracked, + viewChild, +} from '@angular/core'; +import { filterCommands, type PaletteCommand } from '../palette-filter'; + +let nextId = 0; + +/** + * The panel's own command palette: a modal dialog with a combobox that + * filters a listbox of commands. Arrow keys move, Enter runs, Escape closes, + * and focus goes back to where it was when the palette opened. + */ +@Component({ + selector: 'app-command-palette', + template: ` + @if (open()) { + + + } + `, + styles: ` + @use 'mixins' as m; + + .backdrop { + position: fixed; + inset: 0; + z-index: 100; + background: color-mix(in srgb, var(--bg) 55%, transparent); + backdrop-filter: blur(2px); + } + .palette { + position: fixed; + top: min(12vh, 96px); + right: 0; + left: 0; + z-index: 101; + display: flex; + flex-direction: column; + width: min(560px, calc(100vw - 32px)); + max-height: min(70vh, 520px); + margin-inline: auto; + @include m.panel(1); + box-shadow: 0 24px 64px -24px rgba(0, 0, 0, 0.6); + overflow: hidden; + @include m.enter(0.18s); + } + .field { + position: relative; + flex-shrink: 0; + padding: 10px; + border-bottom: 1px solid var(--border); + } + .search-icon { + position: absolute; + top: 50%; + left: 22px; + width: 16px; + height: 16px; + transform: translateY(-50%); + fill: none; + stroke: var(--text-3); + stroke-width: 2; + pointer-events: none; + } + input { + box-sizing: border-box; + width: 100%; + height: var(--control-h); + padding: 0 12px 0 36px; + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + background: var(--bg); + color: var(--text-strong); + font: inherit; + font-size: 14px; + &::placeholder { + color: var(--text-3); + } + &:focus { + @include m.field-focus; + } + } + .list { + flex: 1; + min-height: 0; + margin: 0; + padding: 6px; + overflow-y: auto; + list-style: none; + &[hidden] { + display: none; + } + } + li { + display: flex; + align-items: center; + gap: 10px; + min-height: var(--control-h); + padding: 0 10px; + border-radius: var(--radius-sm); + color: var(--text); + cursor: pointer; + } + li.active { + background: var(--accent-soft); + color: var(--text-strong); + box-shadow: inset 2px 0 0 var(--accent); + } + .title { + flex: 1; + @include m.truncate; + } + .group { + flex-shrink: 0; + color: var(--text-2); + font-size: 12px; + } + kbd { + padding: 1px 6px; + border: 1px solid var(--border-strong); + border-radius: 4px; + background: var(--surface-2); + color: var(--text); + font-family: var(--font-mono); + font-size: 11px; + } + .empty { + margin: 0; + padding: 16px; + color: var(--text-2); + } + .help { + flex-shrink: 0; + margin: 0; + padding: 8px 12px; + border-top: 1px solid var(--border); + color: var(--text-2); + font-size: 12px; + } + @media (max-width: 480px) { + .group, + .help { + display: none; + } + } + `, +}) +export class CommandPalette { + readonly commands = input([]); + readonly open = model(false); + /** The id of the command picked, sent after the palette closed and gave focus back. */ + readonly picked = output(); + + protected readonly uid = `cp${nextId++}`; + readonly query = signal(''); + readonly results = computed(() => filterCommands(this.commands(), this.query())); + readonly active = linkedSignal(() => (this.results().length ? 0 : -1)); + protected readonly activeId = computed(() => + this.active() >= 0 ? `${this.uid}-opt-${this.active()}` : null, + ); + protected readonly status = computed(() => { + const count = this.results().length; + if (!count) return 'No commands match.'; + return `${count} ${count === 1 ? 'command' : 'commands'}.`; + }); + + private readonly input = viewChild>('input'); + private readonly injector = inject(Injector); + private returnFocus: HTMLElement | null = null; + + constructor() { + effect(() => { + if (!this.open()) return; + untracked(() => { + const active = document.activeElement; + this.returnFocus = + active instanceof HTMLElement && active !== document.body ? active : null; + this.query.set(''); + afterNextRender(() => this.input()?.nativeElement.focus(), { injector: this.injector }); + }); + }); + } + + close(then?: () => void) { + if (!this.open()) return; + this.open.set(false); + const back = this.returnFocus; + this.returnFocus = null; + afterNextRender( + () => { + if (back?.isConnected) back.focus(); + then?.(); + }, + { injector: this.injector }, + ); + } + + run(command: PaletteCommand) { + this.close(() => this.picked.emit(command.id)); + } + + onKey(event: KeyboardEvent) { + const count = this.results().length; + switch (event.key) { + case 'ArrowDown': + case 'ArrowUp': { + event.preventDefault(); + if (!count) return; + const step = event.key === 'ArrowDown' ? 1 : -1; + this.active.set((this.active() + step + count) % count); + this.reveal(); + return; + } + case 'PageDown': + case 'PageUp': + event.preventDefault(); + if (!count) return; + this.active.set(event.key === 'PageDown' ? count - 1 : 0); + this.reveal(); + return; + case 'Enter': { + event.preventDefault(); + const command = this.results()[this.active()]; + if (command) this.run(command); + return; + } + case 'Escape': + event.preventDefault(); + // The popup closes on Escape too; this one belongs to the palette. + event.stopPropagation(); + this.close(); + return; + case 'Tab': + // The input is the only stop in the dialog, so focus stays in it. + event.preventDefault(); + return; + } + } + + private reveal() { + afterNextRender( + () => { + const id = this.activeId(); + if (id) document.getElementById(id)?.scrollIntoView?.({ block: 'nearest' }); + }, + { injector: this.injector }, + ); + } +} diff --git a/apps/docs/src/content/agents/resources.md b/apps/docs/src/content/agents/resources.md index b9ef96ee..a68346db 100644 --- a/apps/docs/src/content/agents/resources.md +++ b/apps/docs/src/content/agents/resources.md @@ -94,6 +94,7 @@ This table covers the data that has no resource of its own. | `pangular:http-payloads` | The TransferState payload of each page, by page id | | `pangular:change-detection` | Change detection recordings, by page id | | `pangular:pipe-usage` | Live pipe instances and recorded calls | +| `pangular:errors` | Error groups and console calls, by page id | | `pangular:analog` | Analog page data and the server call log | | `pangular:routes` | Declared but not filled. Use `get-routes` or `list-routes` instead. | diff --git a/apps/docs/src/content/agents/tools.md b/apps/docs/src/content/agents/tools.md index 01fd217a..fc37c233 100644 --- a/apps/docs/src/content/agents/tools.md +++ b/apps/docs/src/content/agents/tools.md @@ -4,7 +4,7 @@ description: Every agent tool the devtools expose, grouped by inspector, with wh --- - Sixty-seven tools, grouped by inspector. Each one answers a question you would otherwise answer by clicking through the panel. + Seventy-one tools, grouped by inspector. Each one answers a question you would otherwise answer by clicking through the panel. # Tools @@ -45,6 +45,18 @@ Lists the tabs, [Angular Native](../getting-started/angular-native.md) apps, [Na The URL comes from the HTTP or router report. A page that sends neither (no router, and no [HTTP setup](../getting-started/express.md)) still shows the URL its component tree reports, which also stands in when the other reports are more than 15 seconds older. A tab in the background stops reporting until it is shown again, so its last report is marked `(background)`: an old time there means the data is the last known state, not that the page is gone. +### open-in-panel + +Gives the user a link that opens the panel on one tab with one item selected, and switches the panels that are open to it. Reads: page. Use it to point the user at what you found. + +| Argument | Required | What it is | +| -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `tab` | Yes | The tab: `dashboard`, `components`, `routes`, `signals`, `injectors`, `store`, `forms`, `pipes`, `network` (SSR & HTTP), `errors`, `analog` or `capacitor`. Only tabs that are on count. | +| `id` | No | The item to select: a component id on `components`, the id of the component whose element injector to show on `injectors`, a form id on `forms`. Other tabs ignore it. | +| `page` | No | The page the item belongs to, from `list-pages`. | + +The answer is a full URL, such as `http://localhost:4200/__devframes/pangular/#tab=components&id=12&page=k3x9`, when the hub serves the panel and a page has reported its address. Otherwise it is the hash to add to the panel's address. Each panel that is open and not in a background tab opens the link at once. The tool is `read`: it changes what the panel shows, not the app. See [Deep links](../getting-started/popup-and-hub.md#deep-links). + ### Action tools Every tool has one of three safety tiers. The server sends the tier to your client as the tool's read-only and destructive hints. @@ -535,6 +547,18 @@ These tools read what a Capacitor app reported: its platform, its plugins and th `plugin` keeps calls to one plugin, ignoring case. `failed` keeps calls that failed. `slowMs` keeps calls that took at least that many milliseconds, counting a pending call's time so far. `limit` defaults to 30 (at most 200). Without `page`, both tools answer for the most recent page with a native bridge, so a desktop tab of the same app doesn't hide the device, and they name the other pages that report. A long answer is cut at about 20,000 characters with a note on how to narrow it, and a plugin lists its first 20 methods. Native calls are logged on iOS and Android. Calls a web implementation answers are logged only when the app loads `@pangular-inspector/devtools/capacitor-hook` before `@capacitor/core`, and the answer says so when it doesn't. Arguments, results and errors are masked with the server's redaction too. +## Errors + +These tools read what a page captured: errors from Angular's `ErrorHandler`, uncaught errors, unhandled promise rejections and console calls. See [Errors](../inspectors/errors.md). Reads: page. + +| Tool | What it answers | Arguments | +| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | +| `list-errors` | Error groups, most recent first: id, count, when last seen, the Angular error code linked to its reference page, the message, the owning component with its instance id, and the source (`handler`, `window` or `promise`). | `code`, `limit` | +| `explain-error` | One error by `id`: message, count, sources, the owning component, the stack of the first occurrence, and for an Angular code its reference page and a short known cause. With `code` instead, the reference entry and the errors that carry it. | `id`, `code` | +| `list-console` | Console calls, newest first: when, level, the text of the arguments and the Angular code it mentions. Calls repeated in a row show once with a count. | `level`, `search`, `limit` | + +`code` accepts `NG0100`, `ng100` or `NG01203`. `explain-error` says so when Angular's error reference has no page for a code, and gives no known cause then. Pass the owner's instance id to `inspect-component` for its inputs and state. `list-errors` takes `limit` up to 100 (default 30), and `list-console` up to 200 (default 50). Messages, stacks and console text are masked like other live values. + ## Analog These tools cover *Analog apps. Most read your source. Some also read what the Vite plugin recorded. diff --git a/apps/docs/src/content/getting-started/command-palette.md b/apps/docs/src/content/getting-started/command-palette.md new file mode 100644 index 00000000..191b402d --- /dev/null +++ b/apps/docs/src/content/getting-started/command-palette.md @@ -0,0 +1,63 @@ +--- +title: Command palette +description: Open any tab and run the main panel actions from the keyboard with the command palette. +--- + + + Press Cmd+K or Ctrl+K in the panel to jump to a tab or run an action without the mouse. + + +# Command palette + +The command palette lists a command for every tab and for the main actions of the panel. Type a few letters to filter it, then press Enter. + +## Open it + +| Where you are | What Cmd+K or Ctrl+K opens | +| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | +| The panel in the [hub](./popup-and-hub.md#the-hub), in the popup or at `/__devframes/` | The hub's palette, which lists the Pangular commands next to the commands of other tools | +| The panel without the hub: the standalone CLI, `initDevframe()` or the [Chrome extension](./chrome-extension.md) | The panel's own palette | + +Use Cmd on macOS and Ctrl elsewhere. The palette button in the panel header opens it too. + +## Commands + +| Command | What it does | +| ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +| **Go to** a tab | Opens the tab. Hidden tabs are listed too. Tabs that are turned off or have nothing to show are not. | +| **Open settings** | Opens [Settings](./settings.md). | +| **Pick component on page** | Opens **Components** and starts **Pick component on page**. | +| **Start recording change detection** | Opens **Components** and starts the change detection recording. | +| **Stop recording change detection** | Opens **Components** and stops the recording. | +| **Clear change detection recording** | Opens **Components** and clears the recorded cycles. | +| **Theme: follow the system**, **Theme: light**, **Theme: dark** | Sets the panel theme, like the [Settings](./settings.md#theme) page. | +| **Popup: float**, **Popup: dock to the bottom**, **Popup: dock to the right** | Changes the [dock mode](./popup-and-hub.md#dock-modes). Only in the popup's own palette. | + +The **Components** commands need the Components inspector on and a page connected. Without a live page the tab shows why, and the command does nothing. + +## Filter and run + +The filter matches the letters you type in order, anywhere in the title, so `gtsig` finds **Go to Signals**. Letters at the start of a word and letters next to each other rank higher. It also matches the group (**Go to**, **Actions**, **Theme**, **Popup**) and a few extra words, such as `profiler` for the recording commands. + +| Key | Action | +| ------------------------------------------- | --------------------------------------------- | +| ↑ and ↓ | Move through the list. It wraps at both ends. | +| Page Up and Page Down | Jump to the first or the last command. | +| Enter | Run the highlighted command. | +| Escape | Close the palette without running anything. | + +The palette is a modal dialog. The filter box is a combobox that controls the list, and screen readers hear the highlighted command and how many commands match. When the palette closes, focus goes back to where it was, then the command runs. + +## In the hub + +In the hub, the Pangular commands are in the hub's command palette, in the **Pangular Inspector** category. **Pangular: open a tab** groups the tab commands. A **Go to** or **Components** command first opens the **All tools** dock, so the panel is on screen. + +The server registers the commands through Devframe's command registry when the hub starts, and each one asks the open panels to run it. A panel in a background browser tab ignores it. If you have the hub open in two windows, both run the command. The dock mode commands stay out of the hub's palette, because the hub has its own. + +## Where to next + + + + + + diff --git a/apps/docs/src/content/getting-started/configuration.md b/apps/docs/src/content/getting-started/configuration.md index e7e1c7d0..cec10c52 100644 --- a/apps/docs/src/content/getting-started/configuration.md +++ b/apps/docs/src/content/getting-started/configuration.md @@ -99,7 +99,8 @@ type PangularInspector = | 'pipes' | 'http' | 'analog' - | 'capacitor'; + | 'capacitor' + | 'errors'; type PangularAction = 'forms' | 'router' | 'ngrx' | 'http' | 'analog' | 'components'; @@ -117,6 +118,7 @@ interface PangularConfig { cdCycles?: number; capacitorCalls?: number; }; + popup?: {hotkey?: string | false}; } ``` @@ -179,6 +181,33 @@ When a timeline reaches its limit, the oldest entries are dropped. The timeline On Angular 20 and later, the page reports about 250 ms after Angular runs change detection, plus a heartbeat every 4 seconds. `refreshMs` doesn't change that. The page polls every `refreshMs` instead when it can't follow change detection, such as until the app bootstraps. The Analog inspector also reads the page every `refreshMs`. At any value, the page sends its data at least every 8 seconds, even when nothing changed, so the server never drops a page that is still open. +### Popup + +| Option | Default | What it does | +| -------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `popup.hotkey` | `Alt+Shift+P` | The shortcut that opens and closes the [popup](./popup-and-hub.md#keyboard-and-mouse) on your app's page. `false` turns it off. | + +Write the shortcut as modifiers and one key joined with `+`, such as `Mod+Shift+K` or `Ctrl+Alt+D`: + +| Part | Values | +| --------- | --------------------------------------------------------------------------------------------------------------- | +| Modifiers | `Mod` (Cmd on macOS, Ctrl elsewhere), `Ctrl`, `Meta` or `Cmd`, `Alt` or `Option`, `Shift` | +| Key | One letter, one digit, or `F1` to `F12` | + +It needs at least one modifier other than `Shift`, so typing in your app never sets it off. Letters and digits match by key position, so an Option combination that types another character on macOS still works. A value that is not a shortcut prints a warning and keeps `Alt+Shift+P`. + +```ts {6} +// src/server.ts +import {initPangularHub} from '@pangular-inspector/devtools/hub'; + +const devtools = initPangularHub({ + ws: false, + popup: {hotkey: 'Mod+Shift+K'}, +}); +``` + +The overlay reads the option from the server when it connects, so the default works until then. With `false`, [passive mode](./settings.md#passive-mode) has no effect and the floating button always shows. + ## Check the active configuration The server checks the options when it starts. An unknown key, a value of the wrong type or a limit outside its bounds prints one `[pangular]` warning in the terminal that lists each problem and the value used instead. An unknown key names the closest known key: @@ -202,6 +231,7 @@ The [Dashboard](../inspectors/dashboard.md#configuration-block) has a **Configur | **Extra secret names** | `redaction.secretNames`. | | **Unmasked names** | `redaction.unmask`. | | **Limits** | Limits that differ from the defaults. | +| **Popup shortcut** | `popup.hotkey`, or **Off** when it is `false`. | ## Where to next diff --git a/apps/docs/src/content/getting-started/popup-and-hub.md b/apps/docs/src/content/getting-started/popup-and-hub.md index de6a3f10..dcce8708 100644 --- a/apps/docs/src/content/getting-started/popup-and-hub.md +++ b/apps/docs/src/content/getting-started/popup-and-hub.md @@ -90,6 +90,8 @@ The button and the panel sit in the browser top layer, like a ``, a popo | Action | How | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Open the panel | Click the button, or focus it and press Enter or Space; from the keyboard, focus moves into the panel | +| Open or close the panel | Press Alt+Shift+P anywhere on the page, or the shortcut in [`popup.hotkey`](./configuration.md#popup). Closing gives focus back to where it was | +| Run a command | Cmd+K or Ctrl+K in the panel opens the [command palette](./command-palette.md) | | Move between tabs | Arrow keys, Home and End in the tab bar, then Enter to open a tab | | Move through a long list | ↑, ↓, Home and End in the SSR & HTTP timeline, the Store changes and events, and the Signals list. Each list is one Tab stop | | Close the panel | Escape, outside a search box with text | @@ -103,11 +105,15 @@ In a search box that has text, Escape clears the box and leaves the p ### Saved layout -The panel saves its position, size and dock mode in `localStorage` under `pangular-popup`, so it keeps its layout across reloads. Clear that key to reset it. +The panel saves its position, size, dock mode and [passive mode](./settings.md#passive-mode) in `localStorage` under `pangular-popup`, so it keeps its layout across reloads. Clear that key to reset it. + +### Passive mode + +In passive mode the floating button stays hidden until you press the popup shortcut. Turn it on in [Settings](./settings.md#passive-mode). ### Theme -The panel follows the color scheme of the hub, which follows your system unless you pick light or dark in the hub. Without the hub, the panel follows your system. The popup frame around the panel switches with it and saves the last theme with the layout. It takes the theme only from the panel's own frame, so other frames on your page cannot change it. +The panel follows the color scheme of the hub, which follows your system unless you pick light or dark in the hub. Without the hub, the panel follows your system. To keep the panel light or dark whatever the hub does, pick it in [Settings](./settings.md#theme). The popup frame around the panel switches with it and saves the last theme with the layout. It takes the theme only from the panel's own frame, so other frames on your page cannot change it. ## The hub @@ -186,8 +192,22 @@ The URL hash selects a tab. Open `/__devframes/pangular/#tab=signals` to land on | Forms | `#tab=forms` | | Pipes | `#tab=pipes` | | SSR & HTTP | `#tab=network` | +| Errors | `#tab=errors` | | Analog | `#tab=analog` | | Capacitor | `#tab=capacitor` | +| Settings | `#tab=settings` | + +### Link to an item + +A link can also select an item on its tab, on one page: `#tab=&id=&page=`. Open `/__devframes/pangular/#tab=components&id=12&page=k3x9` to land on Components with that component instance selected. + +| Tab | `id` selects | +| ---------- | ---------------------------------------------------------- | +| Components | A component instance, by its id in the component tree | +| Injectors | The element injector of a component, by the component's id | +| Forms | A form, by its id | + +On other tabs, `id` is ignored and the link opens the tab. `page` is the page id from `list-pages`. Without it, the tab looks on the page it shows. If the item is not on the page, the tab says so. The [`open-in-panel`](../agents/tools.md#open-in-panel) agent tool builds these links and switches the panels that are open to them. ### Last tab diff --git a/apps/docs/src/content/getting-started/settings.md b/apps/docs/src/content/getting-started/settings.md new file mode 100644 index 00000000..260797dd --- /dev/null +++ b/apps/docs/src/content/getting-started/settings.md @@ -0,0 +1,65 @@ +--- +title: Settings +description: Pick the panel theme, hide, pin and reorder tabs, and hide the popup button until you press its shortcut. +--- + + + Your own preferences for the panel: theme, tab bar and the popup on your app's page. + + +# Settings + +Open **Settings** with the gear button in the panel header, or with **Open settings** in the [command palette](./command-palette.md). Press the gear button again to go back to the tab you had open. The page is also at `#tab=settings`. + +## Where settings are saved + +Settings belong to you, not to the project. The panel saves them in the browser's `localStorage`, so every panel on the same address uses them, and they survive reloads. The Chrome extension and the panel on your dev server have different addresses, so each keeps its own. + +| Key | Holds | +| ----------------------- | -------------------------------------------- | +| `pangular-pref:theme` | `light` or `dark`. Missing means **System**. | +| `pangular-pref:tabs` | The order, hidden tabs and pinned tabs. | +| `pangular-pref:passive` | `true` when passive mode is on. | + +If the browser blocks storage, the settings apply until the panel reloads. Remove the keys to go back to the defaults. + +## Theme + +| Choice | The panel | +| ---------- | -------------------------------------------------------------------------------------------------------------- | +| **System** | Follows the hub, the Chrome DevTools theme in the extension, or your system color scheme. This is the default. | +| **Light** | Stays light. | +| **Dark** | Stays dark. | + +The popup frame on your app's page follows the panel's theme. The command palette has the same three choices. + +## Tabs + +The **Tabs** list shows every tab the panel can show, in tab bar order. + +| Control | What it does | +| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | +| **Pin** | Moves the tab to the start of the tab bar, with the other pinned tabs. A pinned tab is always shown. | +| **Shown** | Clear it to hide the tab from the tab bar. A hidden tab stays reachable from the command palette and from links. Hiding unpins it. | +| Up and down arrows | Move the tab one place. Pinned tabs move among the pinned ones, the others among the others. | +| **Reset tabs** | Back to the default order, with every tab shown and none pinned. | + +Each row works with the keyboard: Tab reaches its buttons, and Alt+↑ or Alt+↓ on any control in the row moves the tab. After a move, focus stays on the row and a screen reader hears the new position, such as **Signals moved to position 2 of 11.** Dragging is not needed. + +The tab you have open stays in the tab bar while it is open, even when it is hidden. Turning an inspector off in the [configuration](./configuration.md) removes its tab whatever the settings say. + +## Passive mode + +Passive mode hides the floating button on your app's page until you press the popup shortcut, `Alt+Shift+P` unless [`popup.hotkey`](./configuration.md#popup) sets another one. The button shows while the panel is open and hides again when it closes. + +The popup saves passive mode with its layout, under `pangular-popup` in your app's `localStorage`, so it stays on after a reload. Turn it on or off from the panel in the popup: the panel sends the change to the popup around it, and the button hides as soon as you close the panel. A panel opened elsewhere, such as the Chrome extension, saves the setting but has no popup to change. + +With `popup.hotkey: false` there is no shortcut to bring the button back, so passive mode is off and the checkbox is disabled. + +## Where to next + + + + + + diff --git a/apps/docs/src/content/inspectors/errors.md b/apps/docs/src/content/inspectors/errors.md new file mode 100644 index 00000000..6a6e44e2 --- /dev/null +++ b/apps/docs/src/content/inspectors/errors.md @@ -0,0 +1,132 @@ +--- +title: Errors +description: Errors from Angular's ErrorHandler, uncaught errors, unhandled promise rejections and the console log of the running page. +--- + + + The errors your page hit, grouped by message, with their Angular error code, the component they came from and the page's console log. + + +# Errors + +The Errors tab collects what goes wrong on the running page: errors that reach Angular's `ErrorHandler`, uncaught errors and unhandled promise rejections. It groups them by message, links Angular error codes to their reference page, and points at the component that threw when it can find it. A second view shows the page's console calls. + +## What it shows + +### Errors + +Each row is one message with: + +| Part | What it shows | +| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| Count | How many times the page hit this message, as **3×**. | +| Message | The error name and message, masked and cut to 500 characters. | +| Code chip | The Angular error code, such as **NG0100**. It links to the code's page in [Angular's error reference](https://angular.dev/errors) when it has one. | +| Source | **ErrorHandler**, **Uncaught** (a `window` error) or **Unhandled rejection**. | +| Time | When the page last hit it. | +| **Show component** | Opens the [Components](./components.md) tab with the owning component selected. | +| **Stack** | The stack of the first occurrence, collapsed until you open it. | + +The list is newest first. Search by message, code or component name, and press `Escape` to clear the search. + +### Console + +Click **Console** to see the page's `console.log`, `info`, `warn`, `error` and `debug` calls, newest first. Pick a level in **Console level**, or search the text. A call repeated in a row shows once with a count. A call that mentions an Angular code gets a code chip too. + +### Pages + +When several tabs report, **Page** picks one, or **All pages** to see them together. The panel of a tab starts on that tab. + +## Where the data comes from + + + + The overlay wraps the handleError method of the app's ErrorHandler, your own or Angular's. Your handler still runs, with the same arguments, after the overlay records the error. + + + Listeners for error and unhandledrejection on window. They only listen, so the browser and Angular handle the event as before. + + + One shared tap on console, the same one the Forms, Analog and SSR & HTTP inspectors read their messages from. Every call still prints. + + + +Angular forwards `window` errors to its `ErrorHandler` when the app uses `provideBrowserGlobalErrorListeners()`. The overlay counts that error once. + +### The owning component + +The tab looks for the component in this order: + +1. The element whose event listener threw, through `ng.getOwningComponent`. This covers template listeners such as `(click)`. +2. A component Angular names in the message, as in `used in the 'TripCard' component template`. +3. A component class in the stack, such as `_TripCard.book` or a compiled template function such as `TripList_Template`. + +A name from the message or the stack counts only when a component with that class name is on the page. The tab uses the same component ids as the Components tab, so **Show component** selects that instance. + +### Angular error codes + +A `RuntimeError` carries its code, and other errors carry it in the message. The tab reads `NG0` codes (runtime, such as `NG0100` and `NG01203`) and compiler codes (such as `NG8001`). + +## Agent tools + +| Tool | What it does | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------- | +| `pangular:list-errors` | The error groups, with count, code link, owning component and source. | +| `pangular:explain-error` | One error by `id`, or an Angular `code`: the message, the owning component, the stack, the reference page and cause. | +| `pangular:list-console` | The console calls, by `level` or `search`. | + +The known causes come from Angular's error reference, in a sentence or two. For a code without a reference page, `explain-error` says so. See [Tools](../agents/tools.md#errors). + +## Limits and gotchas + + + Messages, stacks and console text are masked like other live values: secret field names, JWTs, bearer tokens and secret key=value pairs. See Access and redaction. + + +### Caps + +| What | Kept per page | +| --------------------- | ------------------------------------- | +| Error groups | 100. The least recent one goes first. | +| Console calls | 200. The oldest one goes first. | +| Message, console text | 500 characters. | +| Stack | 40 lines and 4,000 characters. | + +The tab says how many groups or calls a page dropped. + +### Capture starts with the overlay + +The overlay starts after the page claims its page id, so errors and console calls from before it connects are not in the list. The `ErrorHandler` is wrapped as soon as the app has bootstrapped. Until then, the tab counts the `ERROR` lines Angular's default handler logs, and says the handler isn't wrapped yet. + +### It needs a development build + +Finding the `ErrorHandler` and the owning component uses Angular's debug APIs, which only development builds have. + +### Turn it off + +Set `inspectors: {errors: false}` to drop the tab, the collector and the agent tools. See [Inspectors and agent tools](../getting-started/configuration.md#inspectors-and-agent-tools). + +## FAQ + + + + It did not come from a template listener, and no component on the page matches a class name in its message or stack. Errors from services, timers and promises often have none. + + + Angular's error reference has no page for that code. + + + No. Your handler gets every error, with the same arguments, and its return value is passed back. Stopping the overlay puts the method back. + + + +## Where to next + + + + The component an error points at. + + + Every tool a coding agent can call. + + diff --git a/apps/docs/src/ngmd.config.ts b/apps/docs/src/ngmd.config.ts index 0dae9dd7..5779cdac 100644 --- a/apps/docs/src/ngmd.config.ts +++ b/apps/docs/src/ngmd.config.ts @@ -183,6 +183,8 @@ const config: NgmdConfig = { {label: 'Standalone CLI', href: '/getting-started/cli'}, {label: 'Configuration', href: '/getting-started/configuration', status: 'new'}, {label: 'Popup and hub', href: '/getting-started/popup-and-hub', status: 'new'}, + {label: 'Command palette', href: '/getting-started/command-palette', status: 'new'}, + {label: 'Settings', href: '/getting-started/settings', status: 'new'}, {label: 'Browser overlay', href: '/getting-started/overlay', status: 'updated'}, {label: 'Chrome extension', href: '/getting-started/chrome-extension'}, {label: 'Angular Native', href: '/getting-started/angular-native', status: 'new'}, @@ -203,6 +205,7 @@ const config: NgmdConfig = { {label: 'SSR & HTTP', href: '/inspectors/ssr-http', status: 'new'}, {label: 'Analog', href: '/inspectors/analog', status: 'new'}, {label: 'Capacitor', href: '/inspectors/capacitor', status: 'new'}, + {label: 'Errors', href: '/inspectors/errors', status: 'new'}, ], }, { diff --git a/extension/ui/assets/browser-agent-rpc-BXhoSh1z-CQE1-tGR.js b/extension/ui/assets/browser-agent-rpc-BXhoSh1z-DTULcebV.js similarity index 93% rename from extension/ui/assets/browser-agent-rpc-BXhoSh1z-CQE1-tGR.js rename to extension/ui/assets/browser-agent-rpc-BXhoSh1z-DTULcebV.js index 45b55a01..9377ec72 100644 --- a/extension/ui/assets/browser-agent-rpc-BXhoSh1z-CQE1-tGR.js +++ b/extension/ui/assets/browser-agent-rpc-BXhoSh1z-DTULcebV.js @@ -1 +1 @@ -import{t as e}from"./index-BwYb2ll8.js";var t=Symbol.for(`devframe:browser-agent-registry`),{tools:n,listeners:r}=globalThis[t]??={tools:new Map,listeners:new Set};function i(){return[...n.values()]}function a(e){return r.add(e),()=>r.delete(e)}var o=`devframe:client-id`,s;function c(t=globalThis.window){try{let n=t?.sessionStorage;if(n){let t=n.getItem(o);return t||(t=e(),n.setItem(o,t)),t}}catch{}return s??=e(),s}function l(e){e.client.register({name:`devframe:agent:invoke-client-tool`,type:`action`,jsonSerializable:!0,handler:async(e,t)=>{let n=i().find(t=>t.id===e);if(!n)throw Error(`[devframe/agent] browser tool "${e}" not found`);return await n.invoke(t)}});let t=!1,n=!1,r=0,o=()=>{t||n||(t=!0,queueMicrotask(async()=>{if(t=!1,n)return;let a=i().map(({invoke:e,...t})=>t);(a.length!==0||r!==0)&&(r=a.length,await e.callOptional(`devframe:agent:sync-client-tools`,c(),a).catch(()=>{}))}))},s=a(o),l=e.events.on(`connection:status`,e=>{e===`connected`&&o()});return o(),()=>{n=!0,s(),l()}}export{l as setupBrowserAgentRpcBridge}; \ No newline at end of file +import{t as e}from"./index-qtNa3SVJ.js";var t=Symbol.for(`devframe:browser-agent-registry`),{tools:n,listeners:r}=globalThis[t]??={tools:new Map,listeners:new Set};function i(){return[...n.values()]}function a(e){return r.add(e),()=>r.delete(e)}var o=`devframe:client-id`,s;function c(t=globalThis.window){try{let n=t?.sessionStorage;if(n){let t=n.getItem(o);return t||(t=e(),n.setItem(o,t)),t}}catch{}return s??=e(),s}function l(e){e.client.register({name:`devframe:agent:invoke-client-tool`,type:`action`,jsonSerializable:!0,handler:async(e,t)=>{let n=i().find(t=>t.id===e);if(!n)throw Error(`[devframe/agent] browser tool "${e}" not found`);return await n.invoke(t)}});let t=!1,n=!1,r=0,o=()=>{t||n||(t=!0,queueMicrotask(async()=>{if(t=!1,n)return;let a=i().map(({invoke:e,...t})=>t);(a.length!==0||r!==0)&&(r=a.length,await e.callOptional(`devframe:agent:sync-client-tools`,c(),a).catch(()=>{}))}))},s=a(o),l=e.events.on(`connection:status`,e=>{e===`connected`&&o()});return o(),()=>{n=!0,s(),l()}}export{l as setupBrowserAgentRpcBridge}; \ No newline at end of file diff --git a/extension/ui/assets/index-BwYb2ll8.js b/extension/ui/assets/index-qtNa3SVJ.js similarity index 79% rename from extension/ui/assets/index-BwYb2ll8.js rename to extension/ui/assets/index-qtNa3SVJ.js index 5463128f..3ff4646b 100644 --- a/extension/ui/assets/index-BwYb2ll8.js +++ b/extension/ui/assets/index-qtNa3SVJ.js @@ -5,10 +5,10 @@ `):``,this.name=`UnsubscriptionError`,this.errors=t}});function hr(e,t){if(e){var n=e.indexOf(t);0<=n&&e.splice(n,1)}}var gr=function(){function e(e){this.initialTeardown=e,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var e,t,n,r,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a){if(this._parentage=null,Array.isArray(a))try{for(var o=lr(a),s=o.next();!s.done;s=o.next())s.value.remove(this)}catch(t){e={error:t}}finally{try{s&&!s.done&&(t=o.return)&&t.call(o)}finally{if(e)throw e.error}}else a.remove(this)}var c=this.initialTeardown;if(fr(c))try{c()}catch(e){i=e instanceof mr?e.errors:[e]}var l=this._finalizers;if(l){this._finalizers=null;try{for(var u=lr(l),d=u.next();!d.done;d=u.next()){var f=d.value;try{yr(f)}catch(e){i??=[],e instanceof mr?i=dr(dr([],ur(i)),ur(e.errors)):i.push(e)}}}catch(e){n={error:e}}finally{try{d&&!d.done&&(r=u.return)&&r.call(u)}finally{if(n)throw n.error}}}if(i)throw new mr(i)}},e.prototype.add=function(t){if(t&&t!==this){if(this.closed)yr(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=this._finalizers??[]).push(t)}}},e.prototype._hasParent=function(e){var t=this._parentage;return t===e||Array.isArray(t)&&t.includes(e)},e.prototype._addParent=function(e){var t=this._parentage;this._parentage=Array.isArray(t)?(t.push(e),t):t?[t,e]:e},e.prototype._removeParent=function(e){var t=this._parentage;t===e?this._parentage=null:Array.isArray(t)&&hr(t,e)},e.prototype.remove=function(t){var n=this._finalizers;n&&hr(n,t),t instanceof e&&t._removeParent(this)},e.EMPTY=(function(){var t=new e;return t.closed=!0,t})(),e}(),_r=gr.EMPTY;function vr(e){return e instanceof gr||e&&`closed`in e&&fr(e.remove)&&fr(e.add)&&fr(e.unsubscribe)}function yr(e){fr(e)?e():e.unsubscribe()}var br={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1},xr={setTimeout:function(e,t){var n=[...arguments].slice(2),r=xr.delegate;return r?.setTimeout?r.setTimeout.apply(r,dr([e,t],ur(n))):setTimeout.apply(void 0,dr([e,t],ur(n)))},clearTimeout:function(e){return(xr.delegate?.clearTimeout||clearTimeout)(e)},delegate:void 0};function Sr(e){xr.setTimeout(function(){var t=br.onUnhandledError;if(t)t(e);else throw e})}function Cr(){}var wr=(function(){return Dr(`C`,void 0,void 0)})();function Tr(e){return Dr(`E`,void 0,e)}function Er(e){return Dr(`N`,e,void 0)}function Dr(e,t,n){return{kind:e,value:t,error:n}}var Or=null;function kr(e){if(br.useDeprecatedSynchronousErrorHandling){var t=!Or;if(t&&(Or={errorThrown:!1,error:null}),e(),t){var n=Or,r=n.errorThrown,i=n.error;if(Or=null,r)throw i}}else e()}function Ar(e){br.useDeprecatedSynchronousErrorHandling&&Or&&(Or.errorThrown=!0,Or.error=e)}var jr=function(e){cr(t,e);function t(t){var n=e.call(this)||this;return n.isStopped=!1,t?(n.destination=t,vr(t)&&t.add(n)):n.destination=zr,n}return t.create=function(e,t,n){return new Fr(e,t,n)},t.prototype.next=function(e){this.isStopped?Rr(Er(e),this):this._next(e)},t.prototype.error=function(e){this.isStopped?Rr(Tr(e),this):(this.isStopped=!0,this._error(e))},t.prototype.complete=function(){this.isStopped?Rr(wr,this):(this.isStopped=!0,this._complete())},t.prototype.unsubscribe=function(){this.closed||(this.isStopped=!0,e.prototype.unsubscribe.call(this),this.destination=null)},t.prototype._next=function(e){this.destination.next(e)},t.prototype._error=function(e){try{this.destination.error(e)}finally{this.unsubscribe()}},t.prototype._complete=function(){try{this.destination.complete()}finally{this.unsubscribe()}},t}(gr),Mr=Function.prototype.bind;function Nr(e,t){return Mr.call(e,t)}var Pr=function(){function e(e){this.partialObserver=e}return e.prototype.next=function(e){var t=this.partialObserver;if(t.next)try{t.next(e)}catch(e){Ir(e)}},e.prototype.error=function(e){var t=this.partialObserver;if(t.error)try{t.error(e)}catch(e){Ir(e)}else Ir(e)},e.prototype.complete=function(){var e=this.partialObserver;if(e.complete)try{e.complete()}catch(e){Ir(e)}},e}(),Fr=function(e){cr(t,e);function t(t,n,r){var i=e.call(this)||this,a;if(fr(t)||!t)a={next:t??void 0,error:n??void 0,complete:r??void 0};else{var o;i&&br.useDeprecatedNextContext?(o=Object.create(t),o.unsubscribe=function(){return i.unsubscribe()},a={next:t.next&&Nr(t.next,o),error:t.error&&Nr(t.error,o),complete:t.complete&&Nr(t.complete,o)}):a=t}return i.destination=new Pr(a),i}return t}(jr);function Ir(e){br.useDeprecatedSynchronousErrorHandling?Ar(e):Sr(e)}function Lr(e){throw e}function Rr(e,t){var n=br.onStoppedNotification;n&&xr.setTimeout(function(){return n(e,t)})}var zr={closed:!0,next:Cr,error:Lr,complete:Cr},Br=(function(){return typeof Symbol==`function`&&Symbol.observable||`@@observable`})();function Vr(e){return e}function Hr(e){return e.length===0?Vr:e.length===1?e[0]:function(t){return e.reduce(function(e,t){return t(e)},t)}}var Ur=function(){function e(e){e&&(this._subscribe=e)}return e.prototype.lift=function(t){var n=new e;return n.source=this,n.operator=t,n},e.prototype.subscribe=function(e,t,n){var r=this,i=Kr(e)?e:new Fr(e,t,n);return kr(function(){var e=r,t=e.operator,n=e.source;i.add(t?t.call(i,n):n?r._subscribe(i):r._trySubscribe(i))}),i},e.prototype._trySubscribe=function(e){try{return this._subscribe(e)}catch(t){e.error(t)}},e.prototype.forEach=function(e,t){var n=this;return t=Wr(t),new t(function(t,r){var i=new Fr({next:function(t){try{e(t)}catch(e){r(e),i.unsubscribe()}},error:r,complete:t});n.subscribe(i)})},e.prototype._subscribe=function(e){return this.source?.subscribe(e)},e.prototype[Br]=function(){return this},e.prototype.pipe=function(){return Hr([...arguments])(this)},e.prototype.toPromise=function(e){var t=this;return e=Wr(e),new e(function(e,n){var r;t.subscribe(function(e){return r=e},function(e){return n(e)},function(){return e(r)})})},e.create=function(t){return new e(t)},e}();function Wr(e){return e??br.Promise??Promise}function Gr(e){return e&&fr(e.next)&&fr(e.error)&&fr(e.complete)}function Kr(e){return e&&e instanceof jr||Gr(e)&&vr(e)}function qr(e){return fr(e?.lift)}function Jr(e){return function(t){if(qr(t))return t.lift(function(t){try{return e(t,this)}catch(e){this.error(e)}});throw TypeError(`Unable to lift unknown Observable type`)}}function Yr(e,t,n,r,i){return new Xr(e,t,n,r,i)}var Xr=function(e){cr(t,e);function t(t,n,r,i,a,o){var s=e.call(this,t)||this;return s.onFinalize=a,s.shouldUnsubscribe=o,s._next=n?function(e){try{n(e)}catch(e){t.error(e)}}:e.prototype._next,s._error=i?function(e){try{i(e)}catch(e){t.error(e)}finally{this.unsubscribe()}}:e.prototype._error,s._complete=r?function(){try{r()}catch(e){t.error(e)}finally{this.unsubscribe()}}:e.prototype._complete,s}return t.prototype.unsubscribe=function(){var t;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){var n=this.closed;e.prototype.unsubscribe.call(this),!n&&((t=this.onFinalize)==null||t.call(this))}},t}(jr),Zr=pr(function(e){return function(){e(this),this.name=`ObjectUnsubscribedError`,this.message=`object unsubscribed`}}),Qr=function(e){cr(t,e);function t(){var t=e.call(this)||this;return t.closed=!1,t.currentObservers=null,t.observers=[],t.isStopped=!1,t.hasError=!1,t.thrownError=null,t}return t.prototype.lift=function(e){var t=new $r(this,this);return t.operator=e,t},t.prototype._throwIfClosed=function(){if(this.closed)throw new Zr},t.prototype.next=function(e){var t=this;kr(function(){var n,r;if(t._throwIfClosed(),!t.isStopped){t.currentObservers||=Array.from(t.observers);try{for(var i=lr(t.currentObservers),a=i.next();!a.done;a=i.next())a.value.next(e)}catch(e){n={error:e}}finally{try{a&&!a.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}}})},t.prototype.error=function(e){var t=this;kr(function(){if(t._throwIfClosed(),!t.isStopped){t.hasError=t.isStopped=!0,t.thrownError=e;for(var n=t.observers;n.length;)n.shift().error(e)}})},t.prototype.complete=function(){var e=this;kr(function(){if(e._throwIfClosed(),!e.isStopped){e.isStopped=!0;for(var t=e.observers;t.length;)t.shift().complete()}})},t.prototype.unsubscribe=function(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null},Object.defineProperty(t.prototype,"observed",{get:function(){return this.observers?.length>0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(t){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,t)},t.prototype._subscribe=function(e){return this._throwIfClosed(),this._checkFinalizedStatuses(e),this._innerSubscribe(e)},t.prototype._innerSubscribe=function(e){var t=this,n=this,r=n.hasError,i=n.isStopped,a=n.observers;return r||i?_r:(this.currentObservers=null,a.push(e),new gr(function(){t.currentObservers=null,hr(a,e)}))},t.prototype._checkFinalizedStatuses=function(e){var t=this,n=t.hasError,r=t.thrownError,i=t.isStopped;n?e.error(r):i&&e.complete()},t.prototype.asObservable=function(){var e=new Ur;return e.source=this,e},t.create=function(e,t){return new $r(e,t)},t}(Ur),$r=function(e){cr(t,e);function t(t,n){var r=e.call(this)||this;return r.destination=t,r.source=n,r}return t.prototype.next=function(e){var t,n;(n=(t=this.destination)?.next)==null||n.call(t,e)},t.prototype.error=function(e){var t,n;(n=(t=this.destination)?.error)==null||n.call(t,e)},t.prototype.complete=function(){var e,t;(t=(e=this.destination)?.complete)==null||t.call(e)},t.prototype._subscribe=function(e){return this.source?.subscribe(e)??_r},t}(Qr),ei=function(e){cr(t,e);function t(t){var n=e.call(this)||this;return n._value=t,n}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(t){var n=e.prototype._subscribe.call(this,t);return!n.closed&&t.next(this._value),n},t.prototype.getValue=function(){var e=this,t=e.hasError,n=e.thrownError,r=e._value;if(t)throw n;return this._throwIfClosed(),r},t.prototype.next=function(t){e.prototype.next.call(this,this._value=t)},t}(Qr);function ti(e,t){return Jr(function(n,r){var i=0;n.subscribe(Yr(r,function(n){r.next(e.call(t,n,i++))}))})}var ni=`https://angular.dev/best-practices/security#preventing-cross-site-scripting-xss`,ri=class extends Error{code;constructor(e,t){super(ai(e,t)),this.code=e}};function ii(e){return`NG0${Math.abs(e)}`}function ai(e,t){return`${ii(e)}${t?`: `+t:``}`}function oi(e){for(let t in e)if(e[t]===oi)return t;throw Error(``)}function si(e){if(typeof e==`string`)return e;if(Array.isArray(e))return`[${e.map(si).join(`, `)}]`;if(e==null)return``+e;let t=e.overriddenName||e.name;if(t)return`${t}`;let n=e.toString();if(n==null)return``+n;let r=n.indexOf(` `);return r>=0?n.slice(0,r):n}function ci(e,t){return e?t?`${e} ${t}`:e:t||``}var li=oi({__forward_ref__:oi});function ui(e){return e.__forward_ref__=ui,e}function di(e){return fi(e)?e():e}function fi(e){return typeof e==`function`&&Object.hasOwn(e,li)&&e.__forward_ref__===ui}function pi(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function mi(e){return hi(e,vi)}function hi(e,t){return Object.hasOwn(e,t)&&e[t]||null}function gi(e){return(e?.[vi]??null)||null}function _i(e){return e&&Object.hasOwn(e,yi)?e[yi]:null}var vi=oi({ɵprov:oi}),yi=oi({ɵinj:oi}),bi=class{_desc;ngMetadataName=`InjectionToken`;ɵprov;constructor(e,t){this._desc=e,this.ɵprov=void 0,typeof t==`number`?this.__NG_ELEMENT_ID__=t:t!==void 0&&(this.ɵprov=pi({token:this,providedIn:t.providedIn||`root`,factory:t.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}};function xi(e){return e&&!!e.ɵproviders}var Si=oi({ɵcmp:oi}),Ci=oi({ɵdir:oi}),wi=oi({ɵpipe:oi}),Ti=oi({ɵfac:oi}),Ei=oi({__NG_ELEMENT_ID__:oi}),Di=oi({__NG_ENV_ID__:oi});function Oi(e){return ji(e,`@Component`),e[Si]||null}function ki(e){return ji(e,`@Directive`),e[Ci]||null}function Ai(e){return ji(e,`@Pipe`),e[wi]||null}function ji(e,t){if(e==null)throw new ri(-919,!1)}function Mi(e){return typeof e==`string`?e:e==null?``:String(e)}var Ni=oi({ngErrorCode:oi}),Pi=oi({ngErrorMessage:oi}),Fi=oi({ngTokenPath:oi});function Ii(e,t){return Ri(``,-200,t)}function Li(e,t){throw new ri(-201,!1)}function Ri(e,t,n){let r=new ri(t,e);return r[Ni]=t,r[Pi]=e,n&&(r[Fi]=n),r}function zi(e){return e[Ni]}var Bi;function Vi(){return Bi}function Hi(e){let t=Bi;return Bi=e,t}function Ui(e,t,n){let r=mi(e);if(r&&r.providedIn==`root`)return r.value===void 0?r.value=r.factory():r.value;if(n&8)return null;if(t!==void 0)return t;Li(e,``)}var Wi=globalThis,Gi={},Ki=`__NG_DI_FLAG__`,qi=class{injector;constructor(e){this.injector=e}retrieve(e,t){let n=Xi(t)||0;try{return this.injector.get(e,n&8?null:Gi,n)}catch(e){if(tr(e))return e;throw e}}};function Ji(e,t=0){let n=Qn();if(n===void 0)throw new ri(-203,!1);if(n===null)return Ui(e,void 0,t);{let r=Zi(t),i=n.retrieve(e,r);if(tr(i)){if(r.optional)return null;throw i}return i}}function Yi(e,t=0){return(Vi()||Ji)(di(e),t)}function w(e,t){return Yi(e,Xi(t))}function Xi(e){return e===void 0||typeof e==`number`?e:0|(e.optional&&8)|(e.host&&1)|(e.self&&2)|(e.skipSelf&&4)}function Zi(e){return{optional:!!(e&8),host:!!(e&1),self:!!(e&2),skipSelf:!!(e&4)}}function Qi(e){let t=[];for(let n=0;nArray.isArray(e)?ra(e,t):t(e))}function ia(e,t,n){t>=e.length?e.push(n):e.splice(t,0,n)}function aa(e,t){return t>=e.length-1?e.pop():e.splice(t,1)[0]}function oa(e,t){let n=[];for(let r=0;rt;){let t=i-2;e[i]=e[t],i--}e[t]=n,e[t+1]=r}}function ca(e,t,n){let r=ua(e,t);return r>=0?e[r|1]=n:(r=~r,sa(e,r,t,n)),r}function la(e,t){let n=ua(e,t);if(n>=0)return e[n|1]}function ua(e,t){return da(e,t,1)}function da(e,t,n){let r=0,i=e.length>>n;for(;i!==r;){let a=r+(i-r>>1),o=e[a<t?i=a:r=a+1}return~(i<{n.push(e)};return ra(t,e=>{let t=e;xa(t,a,[],r)&&(i||=[],i.push(t))}),i!==void 0&&ba(i,a),n}function ba(e,t){for(let n=0;n{t(e,r)})}}function xa(e,t,n,r){if(e=di(e),!e)return!1;let i=null,a=_i(e),o=!a&&Oi(e);if(!a&&!o){let t=e.ngModule;if(a=_i(t),a)i=t;else return!1}else if(o&&!o.standalone)return!1;else i=e;let s=r.has(i);if(o){if(s)return!1;if(r.add(i),o.dependencies){let e=typeof o.dependencies==`function`?o.dependencies():o.dependencies;for(let i of e)xa(i,t,n,r)}}else if(a){if(a.imports!=null&&!s){r.add(i);let e;try{ra(a.imports,i=>{xa(i,t,n,r)&&(e||=[],e.push(i))})}finally{}e!==void 0&&ba(e,t)}if(!s){let e=ea(i)||(()=>new i);t({provide:i,useFactory:e,deps:pa},i),t({provide:ga,useValue:i,multi:!0},i),t({provide:ma,useValue:()=>Yi(i),multi:!0},i)}let o=a.providers;if(o!=null&&!s){let n=e;Sa(o,e=>{t(e,n)})}}else return!1;return i!==e&&e.providers!==void 0}function Sa(e,t){for(let n of e)xi(n)&&(n=n.ɵproviders),Array.isArray(n)?Sa(n,t):t(n)}var Ca=oi({provide:String,useValue:oi});function wa(e){return typeof e==`object`&&!!e&&Ca in e}function Ta(e){return!!(e&&e.useExisting)}function Ea(e){return!!(e&&e.useFactory)}function Da(e){return typeof e==`function`}var Oa=new bi(``),ka={},Aa={},ja=void 0;function Ma(){return ja===void 0&&(ja=new _a),ja}var Na=class{},Pa=class extends Na{parent;source;scopes;records=new Map;_ngOnDestroyHooks=new Set;_onDestroyHooks=[];get destroyed(){return this._destroyed}_destroyed=!1;injectorDefTypes;constructor(e,t,n,r){super(),this.parent=t,this.source=n,this.scopes=r,Wa(e,e=>this.processProvider(e)),this.records.set(ha,Ba(void 0,this)),r.has(`environment`)&&this.records.set(Na,Ba(void 0,this));let i=this.records.get(Oa);i!=null&&typeof i.value==`string`&&this.scopes.add(i.value),this.injectorDefTypes=new Set(this.get(ga,pa,{self:!0}))}retrieve(e,t){let n=Xi(t)||0;try{return this.get(e,Gi,n)}catch(e){if(tr(e))return e;throw e}}destroy(){za(this),this._destroyed=!0;let e=C(null);try{for(let e of this._ngOnDestroyHooks)e.ngOnDestroy();let e=this._onDestroyHooks;this._onDestroyHooks=[];for(let t of e)t()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),C(e)}}onDestroy(e){return za(this),this._onDestroyHooks.push(e),()=>this.removeOnDestroy(e)}runInContext(e){za(this);let t=$n(this),n=Hi(void 0);try{return e()}finally{$n(t),Hi(n)}}get(e,t=Gi,n){if(za(this),Object.hasOwn(e,Di))return e[Di](this);let r=Xi(n),i=$n(this),a=Hi(void 0);try{if(!(r&4)){let t=this.records.get(e);if(t===void 0){let n=Ua(e)&&mi(e);t=n&&this.injectableDefInScope(n)?Ba(Fa(e),ka):null,this.records.set(e,t)}if(t!=null)return this.hydrate(e,t,r)}let n=r&2?Ma():this.parent;return t=r&8&&t===Gi?null:t,n.get(e,t)}catch(e){let t=zi(e);throw t===-200||t===-201?new ri(t,null):e}finally{Hi(a),$n(i)}}resolveInjectorInitializers(){let e=C(null),t=$n(this),n=Hi(void 0);try{let e=this.get(ma,pa,{self:!0});for(let t of e)t()}finally{$n(t),Hi(n),C(e)}}toString(){return`R3Injector[...]`}processProvider(e){e=di(e);let t=Da(e)?e:di(e&&e.provide),n=La(e);if(!Da(e)&&e.multi===!0){let n=this.records.get(t);n||(n=Ba(void 0,ka,!0),n.factory=()=>Qi(n.multi),this.records.set(t,n)),t=e,n.multi.push(e)}this.records.set(t,n)}hydrate(e,t,n){let r=C(null);try{if(t.value===Aa)throw Ii(``);return t.value===ka&&(t.value=Aa,t.value=t.factory(void 0,n)),typeof t.value==`object`&&t.value&&Ha(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}finally{C(r)}}injectableDefInScope(e){if(!e.providedIn)return!1;let t=di(e.providedIn);return typeof t==`string`?t===`any`||this.scopes.has(t):this.injectorDefTypes.has(t)}removeOnDestroy(e){let t=this._onDestroyHooks.indexOf(e);t!==-1&&this._onDestroyHooks.splice(t,1)}};function Fa(e){let t=mi(e),n=t===null?ea(e):t.factory;if(n!==null)return n;if(e instanceof bi)throw new ri(-204,!1);if(e instanceof Function)return Ia(e);throw new ri(-204,!1)}function Ia(e){if(e.length>0)throw new ri(-204,!1);let t=gi(e);return t===null?()=>new e:()=>t.factory(e)}function La(e){return wa(e)?Ba(void 0,e.useValue):Ba(Ra(e),ka)}function Ra(e,t,n){let r;if(Da(e)){let t=di(e);return ea(t)||Fa(t)}if(wa(e))r=()=>di(e.useValue);else if(Ea(e))r=()=>e.useFactory(...Qi(e.deps||[]));else if(Ta(e))r=(t,n)=>Yi(di(e.useExisting),n!==void 0&&n&8?8:void 0);else{let t=di(e&&(e.useClass||e.provide));if(Va(e))r=()=>new t(...Qi(e.deps));else return ea(t)||Fa(t)}return r}function za(e){if(e.destroyed)throw new ri(-205,!1)}function Ba(e,t,n=!1){return{factory:e,value:t,multi:n?[]:void 0}}function Va(e){return!!e.deps}function Ha(e){return typeof e==`object`&&!!e&&typeof e.ngOnDestroy==`function`}function Ua(e){return typeof e==`function`||typeof e==`object`&&e.ngMetadataName===`InjectionToken`}function Wa(e,t){for(let n of e)Array.isArray(n)?Wa(n,t):n&&xi(n)?Wa(n.ɵproviders,t):t(n)}function Ga(e,t){let n;e instanceof Pa?(za(e),n=e):n=new qi(e);let r=$n(n),i=Hi(void 0);try{return t()}finally{$n(r),Hi(i)}}function Ka(){return Vi()!==void 0||Qn()!=null}var qa=1;function Ja(e){return Array.isArray(e)&&typeof e[qa]==`object`}function Ya(e){return Array.isArray(e)&&e[qa]===!0}function Xa(e){return!!(e.flags&4)}function Za(e){return e.componentOffset>-1}function Qa(e){return(e.flags&1)==1}function $a(e){return!!e.template}function eo(e){return!!(e[2]&512)}function to(e){return(e[2]&256)==256}var no=(function(e){return e[e.NONE=0]=`NONE`,e[e.HTML=1]=`HTML`,e[e.STYLE=2]=`STYLE`,e[e.SCRIPT=3]=`SCRIPT`,e[e.URL=4]=`URL`,e[e.RESOURCE_URL=5]=`RESOURCE_URL`,e[e.ATTRIBUTE_NO_BINDING=6]=`ATTRIBUTE_NO_BINDING`,e})(no||{}),ro=`math`;function io(e){for(;Array.isArray(e);)e=e[0];return e}function ao(e,t){return io(t[e])}function oo(e,t){return io(t[e.index])}function so(e,t){return e.data[t]}function co(e,t){return e[t]}function lo(e,t,n,r){n>=e.data.length&&(e.data[n]=null,e.blueprint[n]=null),t[n]=r}function uo(e,t){let n=t[e];return Ja(n)?n:n[0]}function fo(e){return(e[2]&128)==128}function po(e){return Ya(e[3])}function mo(e,t){return t==null?null:e[t]}function ho(e){e[17]=0}function go(e){e[2]&1024||(e[2]|=1024,fo(e)&&bo(e))}function _o(e,t){for(;e>0;)t=t[14],e--;return t}function vo(e){return!!(e[2]&9216||e[24]?.dirty)}function yo(e){e[10].changeDetectionScheduler?.notify(8),e[2]&64&&(e[2]|=1024),vo(e)&&bo(e)}function bo(e){e[10].changeDetectionScheduler?.notify(0);let t=Co(e);for(;t!==null&&!(t[2]&8192||(t[2]|=8192,!fo(t)));)t=Co(t)}function xo(e,t){if(to(e))throw new ri(911,!1);e[21]===null&&(e[21]=[]),e[21].push(t)}function So(e,t){if(e[21]===null)return;let n=e[21].indexOf(t);n!==-1&&e[21].splice(n,1)}function Co(e){let t=e[3];return Ya(t)?t[3]:t}function wo(e){return e[7]??=[]}function To(e){return e.cleanup??=[]}function Eo(e,t,n,r){let i=wo(t);i.push(n),e.firstCreatePass&&To(e).push(r,i.length-1)}var Do={lFrame:cs(null),bindingsEnabled:!0,skipHydrationRootTNode:null},Oo=!1;function ko(){return Do.lFrame.elementDepthCount}function Ao(){Do.lFrame.elementDepthCount++}function jo(){Do.lFrame.elementDepthCount--}function Mo(){return Do.bindingsEnabled}function No(){return Do.skipHydrationRootTNode!==null}function Po(e){return Do.skipHydrationRootTNode===e}function Fo(){Do.skipHydrationRootTNode=null}function T(){return Do.lFrame.lView}function Io(){return Do.lFrame.tView}function E(e){return Do.lFrame.contextLView=e,e[8]}function D(e){return Do.lFrame.contextLView=null,e}function Lo(){let e=Ro();for(;e!==null&&e.type===64;)e=e.parent;return e}function Ro(){return Do.lFrame.currentTNode}function zo(){let e=Do.lFrame,t=e.currentTNode;return e.isParent?t:t.parent}function Bo(e,t){let n=Do.lFrame;n.currentTNode=e,n.isParent=t}function Vo(){return Do.lFrame.isParent}function Ho(){Do.lFrame.isParent=!1}function Uo(){return Do.lFrame.contextLView}function Wo(){return Oo}function Go(e){let t=Oo;return Oo=e,t}function Ko(){let e=Do.lFrame,t=e.bindingRootIndex;return t===-1&&(t=e.bindingRootIndex=e.tView.bindingStartIndex),t}function qo(){return Do.lFrame.bindingIndex}function Jo(e){return Do.lFrame.bindingIndex=e}function Yo(){return Do.lFrame.bindingIndex++}function Xo(e){let t=Do.lFrame,n=t.bindingIndex;return t.bindingIndex+=e,n}function Zo(){return Do.lFrame.inI18n}function Qo(e,t){let n=Do.lFrame;n.bindingIndex=n.bindingRootIndex=e,es(t)}function $o(){return Do.lFrame.currentDirectiveIndex}function es(e){Do.lFrame.currentDirectiveIndex=e}function ts(e){let t=Do.lFrame.currentDirectiveIndex;return t===-1?null:e[t]}function ns(){return Do.lFrame.currentQueryIndex}function rs(e){Do.lFrame.currentQueryIndex=e}function is(e){let t=e[1];return t.type===2?t.declTNode:t.type===1?e[5]:null}function as(e,t,n){if(n&4){let r=t,i=e;for(;r=r.parent,r===null&&!(n&1)&&(r=is(i),!(r===null||(i=i[14],r.type&10))););if(r===null)return!1;t=r,e=i}let r=Do.lFrame=ss();return r.currentTNode=t,r.lView=e,!0}function os(e){let t=ss(),n=e[1];Do.lFrame=t,t.currentTNode=n.firstChild,t.lView=e,t.tView=n,t.contextLView=e,t.bindingIndex=n.bindingStartIndex,t.inI18n=!1}function ss(){let e=Do.lFrame,t=e===null?null:e.child;return t===null?cs(e):t}function cs(e){let t={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return e!==null&&(e.child=t),t}function ls(){let e=Do.lFrame;return Do.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}var us=ls;function ds(){let e=ls();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function fs(e){return(Do.lFrame.contextLView=_o(e,Do.lFrame.contextLView))[8]}function ps(){return Do.lFrame.selectedIndex}function ms(e){Do.lFrame.selectedIndex=e}function hs(){let e=Do.lFrame;return so(e.tView,e.selectedIndex)}function O(){Do.lFrame.currentNamespace=`svg`}function gs(){_s()}function _s(){Do.lFrame.currentNamespace=null}function vs(){return Do.lFrame.currentNamespace}var ys=!0;function bs(){return ys}function xs(e){ys=e}function Ss(e,t=null,n=null,r){let i=Cs(e,t,n,r);return i.resolveInjectorInitializers(),i}function Cs(e,t=null,n=null,r,i=new Set){return new Pa([n||pa,va(e)],t||Ma(),null,i)}var ws=class e{static THROW_IF_NOT_FOUND=Gi;static NULL=new _a;static create(e,t){if(Array.isArray(e))return Ss({name:``},t,e,``);{let t=e.name??``;return Ss({name:t},e.parent,e.providers,t)}}static ɵprov=pi({token:e,providedIn:`any`,factory:()=>Yi(ha)});static __NG_ELEMENT_ID__=-1},Ts=new bi(``),Es=class{static __NG_ELEMENT_ID__=Os;static __NG_ENV_ID__=e=>e},Ds=class extends Es{_lView;constructor(e){super(),this._lView=e}get destroyed(){return to(this._lView)}onDestroy(e){let t=this._lView;return xo(t,e),()=>So(t,e)}};function Os(){return new Ds(T())}var ks=new bi(``),As=(()=>{class e{taskId=0;pendingTasks=new Set;destroyed=!1;pendingTask=new ei(!1);debugTaskTracker=w(ks,{optional:!0});get hasPendingTasks(){return!this.destroyed&&this.pendingTask.value}get hasPendingTasksObservable(){return this.destroyed?new Ur(e=>{e.next(!1),e.complete()}):this.pendingTask}add(){!this.hasPendingTasks&&!this.destroyed&&this.pendingTask.next(!0);let e=this.taskId++;return this.pendingTasks.add(e),this.debugTaskTracker?.add(e),e}has(e){return this.pendingTasks.has(e)}remove(e){this.pendingTasks.delete(e),this.debugTaskTracker?.remove(e),this.pendingTasks.size===0&&this.hasPendingTasks&&this.pendingTask.next(!1)}ngOnDestroy(){this.pendingTasks.clear(),this.hasPendingTasks&&this.pendingTask.next(!1),this.destroyed=!0,this.pendingTask.unsubscribe()}static ɵprov=pi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),js=class extends Qr{__isAsync;destroyRef=void 0;pendingTasks=void 0;constructor(e=!1){super(),this.__isAsync=e,Ka()&&(this.destroyRef=w(Es,{optional:!0})??void 0,this.pendingTasks=w(As,{optional:!0})??void 0)}emit(e){let t=C(null);try{super.next(e)}finally{C(t)}}subscribe(e,t,n){let r=e,i=t||(()=>null),a=n;if(e&&typeof e==`object`){let t=e;r=t.next?.bind(t),i=t.error?.bind(t),a=t.complete?.bind(t)}this.__isAsync&&(i=this.wrapInTimeout(i),r&&=this.wrapInTimeout(r),a&&=this.wrapInTimeout(a));let o=super.subscribe({next:r,error:i,complete:a});return e instanceof gr&&e.add(o),o}wrapInTimeout(e){return t=>{let n=this.pendingTasks?.add();setTimeout(()=>{try{e(t)}finally{n!==void 0&&this.pendingTasks?.remove(n)}})}}};function Ms(...e){}function Ns(e){let t,n;function r(){e=Ms;try{n!==void 0&&typeof cancelAnimationFrame==`function`&&cancelAnimationFrame(n),t!==void 0&&clearTimeout(t)}catch{}}return t=setTimeout(()=>{e(),r()}),typeof requestAnimationFrame==`function`&&(n=requestAnimationFrame(()=>{e(),r()})),()=>r()}function Ps(e){return queueMicrotask(()=>e()),()=>{e=Ms}}var Fs=`isAngularZone`,Is=`isAngularZone_ID`,Ls=0,Rs=class e{hasPendingMacrotasks=!1;hasPendingMicrotasks=!1;isStable=!0;onUnstable=new js(!1);onMicrotaskEmpty=new js(!1);onStable=new js(!1);onError=new js(!1);constructor(e){let{enableLongStackTrace:t=!1,shouldCoalesceEventChangeDetection:n=!1,shouldCoalesceRunChangeDetection:r=!1,scheduleInRootZone:i=!1}=e;if(typeof Zone>`u`)throw new ri(908,!1);Zone.assertZonePatched();let a=this;a._nesting=0,a._outer=a._inner=Zone.current,Zone.TaskTrackingZoneSpec&&(a._inner=a._inner.fork(new Zone.TaskTrackingZoneSpec)),t&&Zone.longStackTraceZoneSpec&&(a._inner=a._inner.fork(Zone.longStackTraceZoneSpec)),a.shouldCoalesceEventChangeDetection=!r&&n,a.shouldCoalesceRunChangeDetection=r,a.callbackScheduled=!1,a.scheduleInRootZone=i,Hs(a)}static isInAngularZone(){return typeof Zone<`u`&&Zone.current.get(Fs)===!0}static assertInAngularZone(){if(!e.isInAngularZone())throw new ri(909,!1)}static assertNotInAngularZone(){if(e.isInAngularZone())throw new ri(909,!1)}run(e,t,n){return this._inner.run(e,t,n)}runTask(e,t,n,r){let i=this._inner,a=i.scheduleEventTask(`NgZoneEvent: `+r,e,zs,Ms,Ms);try{return i.runTask(a,t,n)}finally{i.cancelTask(a)}}runGuarded(e,t,n){return this._inner.runGuarded(e,t,n)}runOutsideAngular(e){return this._outer.run(e)}},zs={};function Bs(e){if(e._nesting==0&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function Vs(e){if(e.isCheckStableRunning||e.callbackScheduled)return;e.callbackScheduled=!0;function t(){Ns(()=>{e.callbackScheduled=!1,Us(e),e.isCheckStableRunning=!0,Bs(e),e.isCheckStableRunning=!1})}e.scheduleInRootZone?Zone.root.run(()=>{t()}):e._outer.run(()=>{t()}),Us(e)}function Hs(e){let t=()=>{Vs(e)},n=Ls++;e._inner=e._inner.fork({name:`angular`,properties:{[Fs]:!0,[Is]:n,[Is+n]:!0},onInvokeTask:(n,r,i,a,o,s)=>{if(qs(s))return n.invokeTask(i,a,o,s);try{return Ws(e),n.invokeTask(i,a,o,s)}finally{(e.shouldCoalesceEventChangeDetection&&a.type===`eventTask`||e.shouldCoalesceRunChangeDetection)&&t(),Gs(e)}},onInvoke:(n,r,i,a,o,s,c)=>{try{return Ws(e),n.invoke(i,a,o,s,c)}finally{e.shouldCoalesceRunChangeDetection&&!e.callbackScheduled&&!Js(s)&&t(),Gs(e)}},onHasTask:(t,n,r,i)=>{t.hasTask(r,i),n===r&&(i.change==`microTask`?(e._hasPendingMicrotasks=i.microTask,Us(e),Bs(e)):i.change==`macroTask`&&(e.hasPendingMacrotasks=i.macroTask))},onHandleError:(t,n,r,i)=>(t.handleError(r,i),e.runOutsideAngular(()=>e.onError.emit(i)),!1)})}function Us(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&e.callbackScheduled===!0)}function Ws(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function Gs(e){e._nesting--,Bs(e)}var Ks=class{hasPendingMicrotasks=!1;hasPendingMacrotasks=!1;isStable=!0;onUnstable=new js;onMicrotaskEmpty=new js;onStable=new js;onError=new js;run(e,t,n){return e.apply(t,n)}runGuarded(e,t,n){return e.apply(t,n)}runOutsideAngular(e){return e()}runTask(e,t,n,r){return e.apply(t,n)}};function qs(e){return Ys(e,`__ignore_ng_zone__`)}function Js(e){return Ys(e,`__scheduler_tick__`)}function Ys(e,t){return!Array.isArray(e)||e.length!==1?!1:e[0]?.data?.[t]===!0}var Xs=class{_console=console;handleError(e){this._console.error(`ERROR`,e)}},Zs=new bi(``,{factory:()=>{let e=w(Rs),t=w(Na),n;return r=>{e.runOutsideAngular(()=>{t.destroyed&&!n?setTimeout(()=>{throw r}):(n??=t.get(Xs),n.handleError(r))})}}}),Qs={provide:ma,useValue:()=>{w(Xs,{optional:!0})},multi:!0};function k(e,t){let[n,r,i]=Un(e,t?.equal),a=n;return a[fn],a.set=r,a.update=i,a.asReadonly=$s.bind(a),a}function $s(){let e=this[fn];if(e.readonlyFn===void 0){let t=()=>this();t[fn]=e,e.readonlyFn=t}return e.readonlyFn}var ec=new bi(``,{factory:()=>tc}),tc=`ng`,nc=new bi(``),rc=new bi(``,{providedIn:`platform`,factory:()=>`unknown`}),ic=new bi(``,{factory:()=>w(Ts).body?.querySelector(`[ngCspNonce]`)?.getAttribute(`ngCspNonce`)||null}),ac=(()=>{class e{view;node;constructor(e,t){this.view=e,this.node=t}static __NG_ELEMENT_ID__=oc}return e})();function oc(){return new ac(T(),Lo())}var sc=class{},cc=new bi(``,{factory:()=>!0}),lc=new bi(``),uc=(()=>{class e{static ɵprov=pi({token:e,providedIn:`root`,factory:()=>new dc})}return e})(),dc=class{dirtyEffectCount=0;queues=new Map;add(e){this.enqueue(e),this.schedule(e)}schedule(e){e.dirty&&this.dirtyEffectCount++}remove(e){let t=e.zone,n=this.queues.get(t);n.has(e)&&(n.delete(e),e.dirty&&this.dirtyEffectCount--)}enqueue(e){let t=e.zone;this.queues.has(t)||this.queues.set(t,new Set);let n=this.queues.get(t);n.has(e)||n.add(e)}flush(){for(;this.dirtyEffectCount>0;){let e=!1;for(let[t,n]of this.queues)e||=t===null?this.flushQueue(n):t.run(()=>this.flushQueue(n));e||(this.dirtyEffectCount=0)}}flushQueue(e){let t=!1;for(let n of e)n.dirty&&(this.dirtyEffectCount--,t=!0,n.run());return t}},fc=class{[fn];constructor(e){this[fn]=e}destroy(){this[fn].destroy()}};function pc(e,t){let n=t?.injector??w(ws),r=t?.manualCleanup===!0?null:n.get(Es),i,a=n.get(ac,null,{optional:!0}),o=n.get(sc);return a===null?i=vc(e,n.get(uc),o):(i=_c(a.view,o,e),r instanceof Ds&&r._lView===a.view&&(r=null)),i.injector=n,r!==null&&(i.onDestroyFns=[r.onDestroy(()=>i.destroy())]),new fc(i)}var mc={...Yn,cleanupFns:void 0,zone:null,onDestroyFns:null,run(){let e=Go(!1);try{Xn(this)}finally{Go(e)}},cleanup(){if(!this.cleanupFns?.length)return;let e=C(null);try{for(;this.cleanupFns.length;)this.cleanupFns.pop()()}finally{this.cleanupFns=[],C(e)}}},hc={...mc,consumerMarkedDirty(){this.scheduler.schedule(this),this.notifier.notify(12)},destroy(){if(Dn(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.scheduler.remove(this)}},gc={...mc,consumerMarkedDirty(){this.view[2]|=8192,bo(this.view),this.notifier.notify(13)},destroy(){if(Dn(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.view[23]?.delete(this)}};function _c(e,t,n){let r=Object.create(gc);return r.view=e,r.zone=typeof Zone<`u`?Zone.current:null,r.notifier=t,r.fn=yc(r,n),e[23]??=new Set,e[23].add(r),r.consumerMarkedDirty(r),r}function vc(e,t,n){let r=Object.create(hc);return r.fn=yc(r,e),r.scheduler=t,r.notifier=n,r.zone=typeof Zone<`u`?Zone.current:null,r.scheduler.add(r),r.notifier.notify(12),r}function yc(e,t){return()=>{t(t=>(e.cleanupFns??=[]).push(t))}}function bc(e){return typeof e==`function`&&e[fn]!==void 0}function xc(e){return bc(e)&&typeof e.set==`function`}var Sc=Symbol(`InputSignalNode#UNSET`),Cc={...qn,transformFn:void 0,applyValueToInputSignal(e,t){Gn(e,t)}};function wc(e){return{toString:e}.toString()}var Tc=(function(e){return e[e.TemplateCreateStart=0]=`TemplateCreateStart`,e[e.TemplateCreateEnd=1]=`TemplateCreateEnd`,e[e.TemplateUpdateStart=2]=`TemplateUpdateStart`,e[e.TemplateUpdateEnd=3]=`TemplateUpdateEnd`,e[e.LifecycleHookStart=4]=`LifecycleHookStart`,e[e.LifecycleHookEnd=5]=`LifecycleHookEnd`,e[e.OutputStart=6]=`OutputStart`,e[e.OutputEnd=7]=`OutputEnd`,e[e.BootstrapApplicationStart=8]=`BootstrapApplicationStart`,e[e.BootstrapApplicationEnd=9]=`BootstrapApplicationEnd`,e[e.BootstrapComponentStart=10]=`BootstrapComponentStart`,e[e.BootstrapComponentEnd=11]=`BootstrapComponentEnd`,e[e.ChangeDetectionStart=12]=`ChangeDetectionStart`,e[e.ChangeDetectionEnd=13]=`ChangeDetectionEnd`,e[e.ChangeDetectionSyncStart=14]=`ChangeDetectionSyncStart`,e[e.ChangeDetectionSyncEnd=15]=`ChangeDetectionSyncEnd`,e[e.AfterRenderHooksStart=16]=`AfterRenderHooksStart`,e[e.AfterRenderHooksEnd=17]=`AfterRenderHooksEnd`,e[e.ComponentStart=18]=`ComponentStart`,e[e.ComponentEnd=19]=`ComponentEnd`,e[e.DeferBlockStateStart=20]=`DeferBlockStateStart`,e[e.DeferBlockStateEnd=21]=`DeferBlockStateEnd`,e[e.DynamicComponentStart=22]=`DynamicComponentStart`,e[e.DynamicComponentEnd=23]=`DynamicComponentEnd`,e[e.HostBindingsUpdateStart=24]=`HostBindingsUpdateStart`,e[e.HostBindingsUpdateEnd=25]=`HostBindingsUpdateEnd`,e})(Tc||{}),Ec=class{previousValue;currentValue;firstChange;constructor(e,t,n){this.previousValue=e,this.currentValue=t,this.firstChange=n}isFirstChange(){return this.firstChange}};function Dc(e,t,n,r){t===null?e[n]=r:t.applyValueToInputSignal(t,r)}var Oc=null,kc=(()=>{Oc=jc;let e=()=>jc;return e.ngInherit=!0,e})();function Ac(){return Oc}function jc(e){return e.type.prototype.ngOnChanges&&(e.setInput=Nc),Mc}function Mc(){let e=Fc(this),t=e?.current;if(t){let n=e.previous;if(n===fa)e.previous=t;else for(let e in t)n[e]=t[e];e.current=null,this.ngOnChanges(t)}}function Nc(e,t,n,r,i){let a=this.declaredInputs[r],o=Fc(e)||Ic(e,{previous:fa,current:null}),s=o.current||={},c=o.previous,l=c[a];s[a]=new Ec(l&&l.currentValue,n,c===fa),Dc(e,t,i,n)}var Pc=`__ngSimpleChanges__`;function Fc(e){return Object.hasOwn(e,Pc)&&e[Pc]||null}function Ic(e,t){return e[Pc]=t}var Lc=[],Rc=function(e,t=null,n){for(let r=0;r=r)break}else t[c]<0&&(e[17]+=65536),(s>14>16&&(e[2]&3)===t&&(e[2]+=16384,Gc(o,a)):Gc(o,a)}var qc=-1,Jc=class{factory;name;injectImpl;resolving=!1;canSeeViewProviders;multi;componentProviders;index;providerFactory;constructor(e,t,n,r){this.factory=e,this.name=r,this.canSeeViewProviders=t,this.injectImpl=n}};function Yc(e){return!!(e.flags&8)}function Xc(e){return!!(e.flags&16)}function Zc(e,t,n){let r=0;for(;rt){o=a-1;break}}}for(;a>16}function al(e,t){let n=il(e),r=t;for(;n>0;)r=r[14],n--;return r}var ol=!0;function sl(e){let t=ol;return ol=e,t}var cl=255,ll=5,ul=0,dl={};function fl(e,t,n){let r;typeof n==`string`?r=n.charCodeAt(0)||0:Object.hasOwn(n,Ei)&&(r=n[Ei]),r??=n[Ei]=ul++;let i=r&cl,a=1<>ll)]|=a}function pl(e,t){let n=hl(e,t);if(n!==-1)return n;let r=t[1];r.firstCreatePass&&(e.injectorIndex=t.length,ml(r.data,e),ml(t,null),ml(r.blueprint,null));let i=gl(e,t),a=e.injectorIndex;if(nl(i)){let e=rl(i),n=al(i,t),r=n[1].data;for(let i=0;i<8;i++)t[a+i]=n[e+i]|r[e+i]}return t[a+8]=i,a}function ml(e,t){e.push(0,0,0,0,0,0,0,0,t)}function hl(e,t){return e.injectorIndex===-1||e.parent&&e.parent.injectorIndex===e.injectorIndex||t[e.injectorIndex+8]===null?-1:e.injectorIndex}function gl(e,t){if(e.parent&&e.parent.injectorIndex!==-1)return e.parent.injectorIndex;let n=0,r=null,i=t;for(;i!==null;){if(r=jl(i),r===null)return qc;if(n++,i=i[14],r.injectorIndex!==-1)return r.injectorIndex|n<<16}return qc}function _l(e,t,n){fl(e,t,n)}function vl(e,t,n){if(n&8||e!==void 0)return e;Li(t,`NodeInjector`)}function yl(e,t,n,r){if(n&8&&r===void 0&&(r=null),!(n&3)){let i=e[9],a=Hi(void 0);try{return i?i.get(t,r,n&8):Ui(t,r,n&8)}finally{Hi(a)}}return vl(r,t,n)}function bl(e,t,n,r=0,i){if(e!==null){if(t[2]&2048&&!(r&2)){let i=Al(e,t,n,r,dl);if(i!==dl)return i}let i=xl(e,t,n,r,dl);if(i!==dl)return i}return yl(t,n,r,i)}function xl(e,t,n,r,i){let a=Tl(n);if(typeof a==`function`){if(!as(t,e,r))return r&1?vl(i,n,r):yl(t,n,r,i);try{let e;if(e=a(r),e==null&&!(r&8))Li(n);else return e}finally{us()}}else if(typeof a==`number`){let i=null,o=hl(e,t),s=qc,c=r&1?t[15][5]:null;for((o===-1||r&4)&&(s=o===-1?gl(e,t):t[o+8],s===qc||!Dl(r,!1)?o=-1:(i=t[1],o=rl(s),t=al(s,t)));o!==-1;){let e=t[1];if(El(a,o,e.data)){let e=Sl(o,t,n,i,r,c);if(e!==dl)return e}s=t[o+8],s!==qc&&Dl(r,t[1].data[o+8]===c)&&El(a,o,t)?(i=e,o=rl(s),t=al(s,t)):o=-1}}return i}function Sl(e,t,n,r,i,a){let o=t[1],s=o.data[e+8],c=Cl(s,o,n,r==null?Za(s)&&ol:r!=o&&!!(s.type&3),i&1&&a===s);return c===null?dl:wl(t,o,c,s,i)}function Cl(e,t,n,r,i){let a=e.providerIndexes,o=t.data,s=a&1048575,c=e.directiveStart,l=e.directiveEnd,u=a>>20,d=r?s:s+u,f=i?s+u:l;for(let e=d;e=c&&t.type===n)return e}if(i){let e=o[c];if(e&&$a(e)&&e.type===n)return c}return null}function wl(e,t,n,r,i){let a=e[n],o=t.data;if(a instanceof Jc){let s=a;if(s.resolving)throw Ii(``);let c=sl(s.canSeeViewProviders);s.resolving=!0,o[n].type||o[n];let l=s.injectImpl?Hi(s.injectImpl):null;as(e,r,0);try{a=e[n]=s.factory(void 0,i,o,e,r),t.firstCreatePass&&n>=r.directiveStart&&zc(n,o[n],t)}finally{l!==null&&Hi(l),sl(c),s.resolving=!1,us()}}return a}function Tl(e){if(typeof e==`string`)return e.charCodeAt(0)||0;let t=Object.hasOwn(e,Ei)?e[Ei]:void 0;return typeof t==`number`?t>=0?t&cl:kl:t}function El(e,t,n){let r=1<>ll)]&r)}function Dl(e,t){return!(e&2)&&!(e&1&&t)}var Ol=class{_tNode;_lView;constructor(e,t){this._tNode=e,this._lView=t}get(e,t,n){return bl(this._tNode,this._lView,e,Xi(n),t)}};function kl(){return new Ol(Lo(),T())}function Al(e,t,n,r,i){let a=e,o=t;for(;a!==null&&o!==null&&o[2]&2048&&!eo(o);){let e=xl(a,o,n,r|2,dl);if(e!==dl)return e;r&=-5;let t=a.parent;if(!t){let e=o[20];if(e){let t=e.get(n,dl,r);if(t!==dl)return t}t=jl(o),o=o[14]}a=t}return i}function jl(e){let t=e[1],n=t.type;return n===2?t.declTNode:n===1?e[5]:null}function Ml(e){return{token:e.token,providedIn:e.autoProvided===!1?null:`root`,factory:e.factory,value:void 0}}function Nl(){return Pl(Lo(),T())}function Pl(e,t){return new Fl(oo(e,t))}var Fl=(()=>{class e{nativeElement;constructor(e){this.nativeElement=e}static __NG_ELEMENT_ID__=Nl}return e})();function Il(e){return e instanceof Fl?e.nativeElement:e}function Ll(){return this._results[Symbol.iterator]()}var Rl=class{_emitDistinctChangesOnly;dirty=!0;_onDirty=void 0;_results=[];_changesDetected=!1;_changes=void 0;length=0;first=void 0;last=void 0;get changes(){return this._changes??=new Qr}constructor(e=!1){this._emitDistinctChangesOnly=e}get(e){return this._results[e]}map(e){return this._results.map(e)}filter(e){return this._results.filter(e)}find(e){return this._results.find(e)}reduce(e,t){return this._results.reduce(e,t)}forEach(e){this._results.forEach(e)}some(e){return this._results.some(e)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(e,t){this.dirty=!1;let n=na(e);(this._changesDetected=!ta(this._results,n,t))&&(this._results=n,this.length=n.length,this.last=n[this.length-1],this.first=n[0])}notifyOnChanges(){this._changes!==void 0&&(this._changesDetected||!this._emitDistinctChangesOnly)&&this._changes.next(this)}onDirty(e){this._onDirty=e}setDirty(){this.dirty=!0,this._onDirty?.()}destroy(){this._changes!==void 0&&(this._changes.complete(),this._changes.unsubscribe())}[Symbol.iterator]=Ll};function zl(e){return(e.flags&128)==128}var Bl=(function(e){return e[e.OnPush=0]=`OnPush`,e[e.Eager=1]=`Eager`,e[e.Default=1]=`Default`,e})(Bl||{}),Vl=new Map,Hl=0;function Ul(){return Hl++}function Wl(e){Vl.set(e[19],e)}function Gl(e){Vl.delete(e[19])}var Kl=`__ngContext__`;function ql(e,t){Ja(t)?(e[Kl]=t[19],Wl(t)):e[Kl]=t}function Jl(e){return Xl(e[12])}function Yl(e){return Xl(e[4])}function Xl(e){for(;e!==null&&!Ya(e);)e=e[4];return e}var Zl=void 0;function Ql(e){Zl=e}function $l(){if(Zl!==void 0)return Zl;if(typeof document<`u`)return document;throw new ri(210,!1)}var eu=!1,tu=new bi(``,{factory:()=>eu}),nu=new WeakMap;function ru(e,t){if(typeof e!=`object`||!e)return;let n=nu.get(e);n||(n=new WeakSet,nu.set(e,n)),n.add(t)}function iu(e){return(e.flags&32)==32}var au=()=>null;function ou(e,t,n=!1){return au(e,t,n)}function su(e,t){let n=e.contentQueries;if(n!==null){let r=C(null);try{for(let r=0;r|^->||--!>|)/g,yu=`​$1​`;function bu(e){return e.replace(_u,e=>e.replace(vu,yu))}function xu(e,t){return e.createText(t)}function Su(e,t,n){e.setValue(t,n)}function Cu(e,t){return e.createComment(bu(t))}function wu(e,t,n){return e.createElement(t,n)}function Tu(e,t,n,r,i){e.insertBefore(t,n,r,i)}function Eu(e,t,n){e.appendChild(t,n)}function Du(e,t,n,r,i){r===null?Eu(e,t,n):Tu(e,t,n,r,i)}function Ou(e,t,n,r){e.removeChild(null,t,n,r)}function ku(e,t,n){e.setAttribute(t,`style`,n)}function Au(e,t,n){n===``?e.removeAttribute(t,`class`):e.setAttribute(t,`class`,n)}function ju(e,t,n){let{mergedAttrs:r,classes:i,styles:a}=n;r!==null&&Zc(e,t,r),i!==null&&Au(e,t,i),a!==null&&ku(e,t,a)}function Mu(e){let t=Nu();return t?t.sanitize(no.URL,e)||``:pu(e,`URL`)?fu(e):gu(Mi(e))}function Nu(){let e=T();return e&&e[10].sanitizer}function Pu(e){return e.ownerDocument.defaultView}function Fu(e){return e.ownerDocument}function Iu(e,t,n){let r=e.length;for(;;){let i=e.indexOf(t,n);if(i===-1)return i;if(i===0||e.charCodeAt(i-1)<=32){let n=t.length;if(i+n===r||e.charCodeAt(i+n)<=32)return i}n=i+1}}var Lu=`ng-template`;function Ru(e,t,n,r){let i=0;if(r){for(;i-1){let e;for(;++ia?``:i[u+1].toLowerCase(),r&2&&l!==e){if(Hu(r))return!1;o=!0}}}}}return Hu(r)||o}function Hu(e){return!(e&1)}function Uu(e,t,n,r){if(t===null)return-1;let i=0;if(r||!n){let n=!1;for(;i-1)for(n++;n0?`="`+t+`"`:``)+`]`}else r&8?i+=`.`+o:r&4&&(i+=` `+o)}else i!==``&&!Hu(o)&&(t+=Yu(a,i),i=``),r=o,a||=!Hu(r);n++}return i!==``&&(t+=Yu(a,i)),t}function Zu(e){return e.map(Xu).join(`,`)}function Qu(e){let t=[],n=[],r=1,i=2;for(;r!1});function id(e){if(!e)return 0;let t=e.toLowerCase().indexOf(`ms`)>-1?1:1e3;return parseFloat(e)*t}function ad(e,t){return e.getPropertyValue(t).split(`,`).map(e=>e.trim())}function od(e){let t=ad(e,`transition-property`),n=ad(e,`transition-duration`),r=ad(e,`transition-delay`),i={propertyName:``,duration:0,animationName:void 0};for(let e=0;ei.duration&&(i.propertyName=t[e],i.duration=a)}return i}function sd(e){let t=ad(e,`animation-name`),n=ad(e,`animation-delay`),r=ad(e,`animation-duration`),i=ad(e,`animation-iteration-count`),a={animationName:``,propertyName:void 0,duration:0};for(let e=0;ea.duration&&s!==`infinite`&&(a.animationName=t[e],a.duration=o)}return a}function cd(e,t){return e!==void 0&&e.duration>t.duration}function ld(e){return(e.animationName!=null||e.propertyName!=null)&&e.duration>0}function ud(e){let t=e.effect?.getTiming();if(t===void 0)return;let n=typeof t.duration==`number`?t.duration:0,r=(t.delay??0)+n,i=e.playbackRate;return i!==void 0&&i!==0&&i!==1&&(r/=Math.abs(i)),r}function dd(e,t){let n=getComputedStyle(e),r=sd(n),i=od(n),a=r.duration>i.duration?r:i;cd(t.get(e),a)||ld(a)&&t.set(e,a)}function fd(e,t,n){if(!n)return;let r=e.getAnimations();return r.length===0?dd(e,t):pd(e,t,r)}function pd(e,t,n){let r={animationName:void 0,propertyName:void 0,duration:0};for(let e of n){if(e.effect?.getTiming()?.iterations===1/0)continue;let t=ud(e)??0,n,i;e.animationName?i=e.animationName:n=e.transitionProperty,t>=r.duration&&(r={animationName:i,propertyName:n,duration:t})}cd(t.get(e),r)||ld(r)&&t.set(e,r)}var md=new Set,hd=!1,gd=1,_d=typeof document<`u`&&typeof document?.documentElement?.getAnimations==`function`;function vd(e){return e[9].get(rd,hd)}function yd(e,t,n){let r=xd.get(e);if(r){for(let e of t)r.classList.push(e);for(let e of n)r.cleanupFns.push(e)}else xd.set(e,{classList:t,cleanupFns:n})}function bd(e){let t=xd.get(e);if(t){for(let e of t.cleanupFns)e();xd.delete(e)}Sd.delete(e)}var xd=new WeakMap,Sd=new WeakMap,Cd=new WeakMap;function wd(e){return e?e[14]??e:null}var Td=new WeakSet;function Ed(e,t,n){let r=Cd.get(e);if(!r||r.length===0)return;let i=t.parentNode,a=t.previousSibling,o=wd(n);for(let e=r.length-1;e>=0;e--){let{el:n,declarationView:s}=r[e],c=n.parentNode;n===t?(r.splice(e,1),Td.add(n),n.dispatchEvent(new CustomEvent(`animationend`,{detail:{cancel:!0}}))):(a&&n===a||c&&i&&c!==i&&(o===null||s===null||o===s))&&(r.splice(e,1),n.dispatchEvent(new CustomEvent(`animationend`,{detail:{cancel:!0}})),n.parentNode?.removeChild(n))}}function Dd(e,t,n){let r=wd(n),i=Cd.get(e);i?i.some(e=>e.el===t)||i.push({el:t,declarationView:r}):Cd.set(e,[{el:t,declarationView:r}])}function Od(e){let t=e[26]??={};return t.enter??=new Map}function kd(e){let t=typeof e==`function`?e():e,n=Array.isArray(t)?t:null;return typeof t==`string`&&(n=t.trim().split(/\s+/).filter(e=>e)),n}function Ad(e){return e.composedPath?e.composedPath()[0]:e.target}function jd(e,t){let n=Sd.get(t);if(n===void 0)return!0;if(t!==Ad(e))return!1;let r=e.animation;if(r){let e=ud(r);if(e!==void 0&&e+gd{class e{impl=null;execute(){this.impl?.execute()}static ɵprov=pi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),Rd=[0,1,2,3],zd=(()=>{class e{ngZone=w(Rs);scheduler=w(sc);errorHandler=w(Xs,{optional:!0});sequences=new Set;deferredRegistrations=new Set;executing=!1;constructor(){w(Pd,{optional:!0})}execute(){let e=this.sequences.size>0;e&&Rc(Tc.AfterRenderHooksStart),this.executing=!0;for(let e of Rd)for(let t of this.sequences)if(!t.erroredOrDestroyed&&t.hooks[e])try{t.pipelinedValue=this.ngZone.runOutsideAngular(()=>this.maybeTrace(()=>{let n=t.hooks[e];return n(t.pipelinedValue)},t.snapshot))}catch(e){t.erroredOrDestroyed=!0,this.errorHandler?.handleError(e)}this.executing=!1;for(let e of this.sequences)e.afterRun(),e.once&&(this.sequences.delete(e),e.destroy());for(let e of this.deferredRegistrations)this.sequences.add(e);this.deferredRegistrations.size>0&&this.scheduler.notify(7),this.deferredRegistrations.clear(),e&&Rc(Tc.AfterRenderHooksEnd)}register(e){let{view:t}=e;t===void 0?this.executing?this.deferredRegistrations.add(e):this.addSequence(e):((t[25]??=[]).push(e),bo(t),t[2]|=8192)}addSequence(e){this.sequences.add(e),this.scheduler.notify(7)}unregister(e){this.executing&&this.sequences.has(e)?(e.erroredOrDestroyed=!0,e.pipelinedValue=void 0,e.once=!0):(this.sequences.delete(e),this.deferredRegistrations.delete(e))}maybeTrace(e,t){return t?t.run(Nd.AFTER_NEXT_RENDER,e):e()}static ɵprov=pi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),Bd=class{impl;hooks;view;once;snapshot;erroredOrDestroyed=!1;pipelinedValue=void 0;unregisterOnDestroy;constructor(e,t,n,r,i,a=null){this.impl=e,this.hooks=t,this.view=n,this.once=r,this.snapshot=a,this.unregisterOnDestroy=i?.onDestroy(()=>this.destroy())}afterRun(){this.erroredOrDestroyed=!1,this.pipelinedValue=void 0,this.snapshot?.dispose(),this.snapshot=null}destroy(){this.impl.unregister(this),this.unregisterOnDestroy?.();let e=this.view?.[25];e&&(this.view[25]=e.filter(e=>e!==this))}};function Vd(e,t){let n=t?.injector??w(ws);return Id(`NgAfterNextRender`),Ud(e,n,t,!0)}function Hd(e){return e instanceof Function?[void 0,void 0,e,void 0]:[e.earlyRead,e.write,e.mixedReadWrite,e.read]}function Ud(e,t,n,r){let i=t.get(Ld);i.impl??=t.get(zd);let a=t.get(Pd,null,{optional:!0}),o=n?.manualCleanup===!0?null:t.get(Es),s=t.get(ac,null,{optional:!0}),c=new Bd(i.impl,Hd(e),s?.view,r,o,a?.snapshot(null));return i.impl.register(c),c}var Wd=new bi(``,{factory:()=>{let e=w(Na),t=new Set;return e.onDestroy(()=>t.clear()),{queue:t,isScheduled:!1,scheduler:null,injector:e}}});function Gd(e,t,n){let r=e.get(Wd);if(Array.isArray(t))for(let e of t)r.queue.add(e),n?.detachedLeaveAnimationFns?.push(e);else r.queue.add(t),n?.detachedLeaveAnimationFns?.push(t);r.scheduler&&r.scheduler(e)}function Kd(e,t){let n=e.get(Wd);if(Array.isArray(t))for(let e of t)n.queue.delete(e);else n.queue.delete(t)}function qd(e,t){let n=e.get(Wd);if(t.detachedLeaveAnimationFns){for(let e of t.detachedLeaveAnimationFns)n.queue.delete(e);t.detachedLeaveAnimationFns=void 0}}function Jd(e){let t=e.get(Wd);t.isScheduled||=(Vd(()=>{t.isScheduled=!1;for(let e of t.queue)e();t.queue.clear()},{injector:t.injector}),!0)}function Yd(e){let t=e.get(Wd);t.scheduler=Jd,t.scheduler(e)}function Xd(e,t){for(let[n,r]of t)Gd(e,r.animateFns)}function Zd(e,t,n,r){let i=e?.[26]?.enter;t!==null&&i&&i.has(n.index)&&Xd(r,i)}function Qd(e,t,n,r){try{n.get(ha)}catch{return r(!1)}let i=e?.[26];i?.enter?.has(t.index)&&Kd(n,i.enter.get(t.index).animateFns);let a=$d(e,t,i);if(a.size===0){let n=!1;if(e){let r=[];tf(e,t,r),n=r.length>0}if(!n)return r(!1)}e&&md.add(e[19]),Gd(n,()=>ef(e,t,i||void 0,a,r),i||void 0)}function $d(e,t,n){let r=new Map,i=n?.leave;if(i&&i.has(t.index)&&r.set(t.index,i.get(t.index)),e&&i)for(let[n,a]of i){if(r.has(n))continue;let i=e[1].data[n].parent;for(;i;){if(i===t){r.set(n,a);break}i=i.parent}}return r}function ef(e,t,n,r,i){let a=[];if(n&&n.leave)for(let[e]of r){if(!n.leave.has(e))continue;let t=n.leave.get(e);for(let e of t.animateFns){let{promise:t}=e();a.push(t)}n.detachedLeaveAnimationFns=void 0}if(e&&tf(e,t,a),a.length>0){let t=n||e?.[26];if(t){let n=t.running;n&&a.push(n),t.running=Promise.allSettled(a),rf(e,t.running,i)}else Promise.allSettled(a).then(()=>{e&&md.delete(e[19]),i(!0)})}else e&&md.delete(e[19]),i(!1)}function tf(e,t,n){if(t.type&12){let r=e[t.index];if(Ya(r))for(let e=10;e{e[26]?.running===t&&(e[26].running=void 0,md.delete(e[19])),n(!0)})}function af(e,t,n,r,i,a,o,s){if(i!=null){let c,l=!1;Ya(i)?c=i:Ja(i)&&(l=!0,i=i[0]);let u=io(i);e===0&&r!==null?(Zd(s,r,a,n),o==null?Eu(t,r,u):Tu(t,r,u,o||null,!0)):e===1&&r!==null?(Zd(s,r,a,n),Tu(t,r,u,o||null,!0),Ed(a,u,s)):e===2?(s?.[26]?.leave?.has(a.index)&&Dd(a,u,s),Td.delete(u),Qd(s,a,n,e=>{if(Td.has(u)){Td.delete(u);return}Ou(t,u,l,e)})):e===3&&(Td.delete(u),Qd(s,a,n,()=>{t.destroyNode(u)})),c!=null&&kf(t,e,n,c,a,r,o)}}function of(e,t){cf(e,t),t[0]=null,t[5]=null}function sf(e,t,n,r,i,a){r[0]=i,r[5]=t,Tf(e,r,n,1,i,a)}function cf(e,t){t[10].changeDetectionScheduler?.notify(9),Tf(e,t,t[11],2,null,null)}function lf(e){let t=e[12];if(!t)return ff(e[1],e);for(;t;){let n=null;if(Ja(t))n=t[12];else{let e=t[10];e&&(n=e)}if(!n){for(;t&&!t[4]&&t!==e;)Ja(t)&&ff(t[1],t),t=t[3];t===null&&(t=e),Ja(t)&&ff(t[1],t),n=t&&t[4]}t=n}}function uf(e,t){let n=e[9],r=n.indexOf(t);n.splice(r,1)}function df(e,t){if(to(t))return;let n=t[11];n.destroyNode&&Tf(e,t,n,3,null,null),lf(t)}function ff(e,t){if(to(t))return;let n=C(null);try{t[2]&=-129,t[2]|=256,t[24]&&Dn(t[24]),mf(e,t),pf(e,t),t[1].type===1&&t[11].destroy();let n=t[16];if(n!==null&&Ya(t[3])){n!==t[3]&&uf(n,t);let r=t[18];r!==null&&r.detachView(e)}Gl(t)}finally{C(n)}}function pf(e,t){let n=e.cleanup,r=t[7];if(n!==null)for(let e=0;e=0?r[t]():r[-t].unsubscribe(),e+=2}else{let t=r[n[e+1]];n[e].call(t)}r!==null&&(t[7]=null);let i=t[21];if(i!==null){t[21]=null;for(let e=0;e27&&zf(e,t,27,!1),Rc(o?Tc.TemplateUpdateStart:Tc.TemplateCreateStart,i,n),n(r,i)}finally{ms(a),Rc(o?Tc.TemplateUpdateEnd:Tc.TemplateCreateEnd,i,n)}}function Uf(e,t,n){Xf(e,t,n),(n.flags&64)==64&&Zf(e,t,n)}function Wf(e,t,n=oo){let r=t.localNames;if(r!==null){let i=t.index+1;for(let a=0;a{bo(e.lView)},consumerOnSignalRead(){this.lView[24]=this}};function xp(e){let t=e[24]??Object.create(Sp);return t.lView=e,t}var Sp={...mn,consumerIsAlwaysLive:!0,kind:`template`,consumerMarkedDirty:e=>{let t=Co(e.lView);for(;t&&!Cp(t[1]);)t=Co(t);t&&go(t)},consumerOnSignalRead(){this.lView[24]=this}};function Cp(e){return e.type!==2}function wp(e){if(e[23]===null)return;let t=!0;for(;t;){let n=!1;for(let t of e[23])if(t.dirty&&(n=!0,t.zone===null||Zone.current===t.zone?t.run():t.zone.run(()=>t.run()),e[23]===null))return;t=n&&!!(e[2]&8192)}}var Tp=100;function Ep(e,t=0){let n=e[10].rendererFactory;n.begin?.();try{Dp(e,t)}finally{n.end?.()}}function Dp(e,t){let n=Wo();try{Go(!0),Np(e,t);let n=0;for(;vo(e);){if(n===Tp)throw new ri(103,!1);n++,Np(e,1)}}finally{Go(n)}}function Op(e,t,n,r){if(to(t))return;let i=t[2];os(t);let a=!0,o=null,s=null;Cp(e)?(s=_p(t),o=Sn(s)):pn()===null?(a=!1,s=xp(t),o=Sn(s)):t[24]&&=(Dn(t[24]),null);try{ho(t),Jo(e.bindingStartIndex),n!==null&&Hf(e,t,n,2,r);let a=(i&3)==3;if(a){let n=e.preOrderCheckHooks;n!==null&&Vc(t,n,null)}else{let n=e.preOrderHooks;n!==null&&Hc(t,n,0,null),Uc(t,0)}if(Ap(t),wp(t),kp(t,0),e.contentQueries!==null&&su(e,t),a){let n=e.contentCheckHooks;n!==null&&Vc(t,n)}else{let n=e.contentHooks;n!==null&&Hc(t,n,1),Uc(t,1)}Fp(e,t);let o=e.components;o!==null&&Pp(t,o,0);let s=e.viewQuery;if(s!==null&&cu(2,s,r),a){let n=e.viewCheckHooks;n!==null&&Vc(t,n)}else{let n=e.viewHooks;n!==null&&Hc(t,n,2),Uc(t,2)}if(e.firstUpdatePass===!0&&(e.firstUpdatePass=!1),t[22]){for(let e of t[22])e();t[22]=null}hp(t),t[2]&=-73}catch(e){throw bo(t),e}finally{s!==null&&(wn(s,o),a&&yp(s)),ds()}}function kp(e,t){for(let n=Jl(e);n!==null;n=Yl(n))for(let e=10;e0&&(e[n-1][4]=r[4]);let a=aa(e,10+t);of(r[1],r);let o=a[18];o!==null&&o.detachView(a[1]),r[3]=null,r[4]=null,r[2]&=-129}return r}function Hp(e,t,n,r){let i=10+r,a=n.length;r>0&&(n[i-1][4]=t),r-1&&(Vp(e,n),aa(t,n))}this._attachedToViewContainer=!1}df(this._lView[1],this._lView)}onDestroy(e){xo(this._lView,e)}markForCheck(){Ip(this._cdRefInjectingView||this._lView,4)}detach(){this._lView[2]&=-129}reattach(){yo(this._lView),this._lView[2]|=128}detectChanges(){this._lView[2]|=1024,Ep(this._lView)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new ri(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null;let e=eo(this._lView),t=this._lView[16];t!==null&&!e&&uf(t,this._lView),cf(this._lView[1],this._lView)}attachToAppRef(e){if(this._attachedToViewContainer)throw new ri(902,!1);this._appRef=e;let t=eo(this._lView),n=this._lView[16];n!==null&&!t&&Up(n,this._lView),yo(this._lView)}},Gp=(()=>{class e{_declarationLView;_declarationTContainer;elementRef;static __NG_ELEMENT_ID__=Kp;constructor(e,t,n){this._declarationLView=e,this._declarationTContainer=t,this.elementRef=n}get ssrId(){return this._declarationTContainer.tView?.ssrId||null}createEmbeddedView(e,t){return this.createEmbeddedViewImpl(e,t)}createEmbeddedViewImpl(e,t,n){return new Wp(dp(this._declarationLView,this._declarationTContainer,e,{embeddedViewInjector:t,dehydratedView:n}))}}return e})();function Kp(){return qp(Lo(),T())}function qp(e,t){return e.type&4?new Gp(t,e,Pl(e,t)):null}function Jp(e,t,n,r,i){let a=e.data[t];if(a===null)a=Yp(e,t,n,r,i),Zo()&&(a.flags|=32);else if(a.type&64){a.type=n,a.value=r,a.attrs=i;let e=zo();a.injectorIndex=e===null?-1:e.injectorIndex}return Bo(a,!0),a}function Yp(e,t,n,r,i){let a=Ro(),o=Vo(),s=o?a:a&&a.parent,c=e.data[t]=Zp(e,s,n,t,r,i);return Xp(e,c,a,o),c}function Xp(e,t,n,r){e.firstChild===null&&(e.firstChild=t),n!==null&&(r?n.child==null&&t.parent!==null&&(n.child=t):n.next===null&&(n.next=t,t.prev=n))}function Zp(e,t,n,r,i,a){let o=t?t.injectorIndex:-1,s=0;return No()&&(s|=128),{type:n,index:r,insertBeforeIndex:null,injectorIndex:o,directiveStart:-1,directiveEnd:-1,directiveStylingLast:-1,componentOffset:-1,controlDirectiveIndex:-1,customControlIndex:-1,propertyBindings:null,flags:s,providerIndexes:0,value:i,namespace:vs(),attrs:a,mergedAttrs:null,localNames:null,initialInputs:null,inputs:null,hostDirectiveInputs:null,outputs:null,hostDirectiveOutputs:null,directiveToIndex:null,tView:null,next:null,prev:null,projectionNext:null,child:null,parent:t,projection:null,styles:null,stylesWithoutHost:null,residualStyles:void 0,classes:null,classesWithoutHost:null,residualClasses:void 0,classBindings:0,styleBindings:0}}function Qp(e){let t=e[6]??[],n=e[3][11],r=[];for(let e of t)e.data.di===void 0?$p(e,n):r.push(e);e[6]=r}function $p(e,t){let n=0,r=e.firstChild;if(r){let i=e.data.r;for(;nnull,tm=()=>null;function nm(e,t){return em(e,t)}function rm(e,t,n){return tm(e,t,n)}var im=class{},am=class{},om=(()=>{class e{static ɵprov=pi({token:e,providedIn:`root`,factory:()=>null})}return e})();function sm(e){return e.debugInfo?.className||e.type.name||null}var cm={},lm=class{injector;parentInjector;constructor(e,t){this.injector=e,this.parentInjector=t}get(e,t,n){let r=this.injector.get(e,cm,n);return r!==cm||t===cm?r:this.parentInjector.get(e,t,n)}};function um(e,t,n){return e[t]=n}function dm(e,t){return e[t]}function fm(e,t,n){if(n===$u)return!1;let r=e[t];return!Object.is(r,n)&&(e[t]=n,!0)}function pm(e,t,n,r){let i=fm(e,t,n);return fm(e,t+1,r)||i}function mm(e,t,n,r,i){let a=pm(e,t,n,r);return fm(e,t+2,i)||a}function hm(e,t,n,r,i,a){let o=pm(e,t,n,r);return pm(e,t+2,i,a)||o}function gm(e,t,n){return function r(i){let a=r.__ngNativeEl__;a!==void 0&&ru(i,a),Ip(Za(e)?uo(e.index,t):t,5);let o=t[8],s=_m(t,o,n,i),c=r.__ngNextListenerFn__;for(;c;)s=_m(t,o,c,i)&&s,c=c.__ngNextListenerFn__;return s}}function _m(e,t,n,r){let i=C(null);try{return Rc(Tc.OutputStart,t,n),n(r)!==!1}catch(t){return ap(e,t),!1}finally{Rc(Tc.OutputEnd,t,n),C(i)}}function vm(e,t,n,r,i,a,o,s){let c=Qa(e),l=!1,u=null;if(!r&&c&&(u=bm(t,n,a,e.index)),u!==null){let e=u.__ngLastListenerFn__||u;e.__ngNextListenerFn__=o,u.__ngLastListenerFn__=o,l=!0}else{let o=oo(e,n),c=r?r(o):o;r||(s.__ngNativeEl__=o);let l=i.listen(c,a,s);ym(a)||xm(r?t=>r(io(t[e.index])):e.index,t,n,a,s,l,!1)}return l}function ym(e){return e.startsWith(`animation`)||e.startsWith(`transition`)}function bm(e,t,n,r){let i=e.cleanup;if(i!=null)for(let e=0;er?n[r]:null}typeof a==`string`&&(e+=2)}return null}function xm(e,t,n,r,i,a,o){let s=t.firstCreatePass?To(t):null,c=wo(n),l=c.length;c.push(i,a),s&&s.push(r,e,l,(l+1)*(o?-1:1))}function Sm(e,t,n,r,i,a){let o=t[n],s=t[1],c=o[s.data[n].outputs[r]].subscribe(a);xm(e.index,s,t,i,a,c,!0)}var Cm=Symbol(`BINDING`),wm=new bi(``);function Tm(e,t,n){let r=n?e.styles:null,i=n?e.classes:null,a=0;if(t!==null)for(let e=0;e0&&(n.directiveToIndex=new Map);for(let c=0;c0;){let n=e[--t];if(typeof n==`number`&&n<0)return n}return 0}function zm(e,t,n){if(n){if(t.exportAs)for(let r=0;r{let[n,r,i]=e[t],a={propName:n,templateName:t,isSignal:(r&Bf.SignalBased)!==0};return i&&(a.transform=i),a})}function qm(e){return Object.keys(e).map(t=>({propName:e[t],templateName:t}))}function Jm(e,t,n){let r=t instanceof Na?t:t?.injector;return r&&e.getStandaloneInjector!==null&&(r=e.getStandaloneInjector(r)||r),r?new lm(n,r):n}function Ym(e){let t=e.get(am,null);if(t===null)throw new ri(407,!1);return{rendererFactory:t,sanitizer:e.get(om,null),changeDetectionScheduler:e.get(sc,null),ngReflect:!1,tracingService:e.get(Pd,null,{optional:!0})}}function Xm(e,t,n){let r=Qm(e);return wu(t,r,r===`svg`?`svg`:r===`math`?ro:n)}function Zm(e){if((e&&`localName`in e&&typeof e.localName==`string`?e.localName:e?.tagName)?.toLowerCase()===`script`)throw new ri(905,!1)}function Qm(e){return(e.selectors[0][0]||`div`).toLowerCase()}var $m=class{componentDef;ngModule;selector;componentType;ngContentSelectors;isBoundToModule;cachedInputs=null;cachedOutputs=null;get inputs(){return this.cachedInputs??=Km(this.componentDef.inputs),this.cachedInputs}get outputs(){return this.cachedOutputs??=qm(this.componentDef.outputs),this.cachedOutputs}constructor(e,t){this.componentDef=e,this.ngModule=t,this.componentType=e.type,this.selector=Zu(e.selectors),this.ngContentSelectors=e.ngContentSelectors??[],this.isBoundToModule=!!t}create(e,t,n,r,i,a,o){Rc(Tc.DynamicComponentStart);let s=C(null);try{let s=this.componentDef,c=Jm(s,r||this.ngModule,e),l=Ym(c),u=l.tracingService;return u&&u.componentCreate?u.componentCreate(sm(s),()=>this.createComponentRef(l,c,t,n,i,a,o)):this.createComponentRef(l,c,t,n,i,a,o)}finally{C(s)}}createComponentRef(e,t,n,r,i,a,o){let s=this.componentDef,c=eh(r,s,a,i),l=e.rendererFactory.createRenderer(null,s),u=r?Gf(l,r,s.encapsulation,t):Xm(s,l,o??null);Zm(u);let d=t.get(wm,null),f=th(u,()=>t.get(Ts,null)??$l());d&&d.addHost(f);let p=a?.some(rh)||i?.some(e=>typeof e!=`function`&&e.bindings.some(rh)),m=Pf(null,c,null,512|If(s),null,null,e,l,t,null,ou(u,t,!0));d&&Wm&&f instanceof ShadowRoot&&xo(m,()=>{d.removeHost(f)}),m[27]=u,os(m);let h=null;try{let e=Vm(27,m,2,`#host`,()=>c.directiveRegistry,!0,0);ju(l,u,e),ql(u,m),Uf(c,m,e),lu(c,e,m),Hm(c,e),n!==void 0&&ah(e,this.ngContentSelectors,n),h=uo(e.index,m),m[8]=h[8],lp(c,m,null)}catch(e){throw h!==null&&Gl(h),Gl(m),e}finally{Rc(Tc.DynamicComponentEnd),ds()}return new ih(this.componentType,m,!!p)}};function eh(e,t,n,r){let i=e?[`ng-version`,`22.1.7`]:Qu(t.selectors[0]),a=null,o=null,s=0;if(n)for(let e of n)s+=e[Cm].requiredVars,e.create&&(e.targetIdx=0,(a??=[]).push(e)),e.update&&(e.targetIdx=0,(o??=[]).push(e));if(r)for(let e=0;e{if(n&1&&e)for(let t of e)t.create();if(n&2&&t)for(let e of t)e.update()}}function rh(e){let t=e[Cm].kind;return t===`input`||t===`twoWay`}var ih=class extends im{_rootLView;_hasInputBindings;instance;hostView;changeDetectorRef;componentType;location;previousInputValues=null;_tNode;constructor(e,t,n){super(),this._rootLView=t,this._hasInputBindings=n,this._tNode=so(t[1],27),this.location=Pl(this._tNode,t),this.instance=uo(this._tNode.index,t)[8],this.hostView=this.changeDetectorRef=new Wp(t,void 0),this.componentType=e}setInput(e,t){this._hasInputBindings;let n=this._tNode;if(this.previousInputValues??=new Map,this.previousInputValues.has(e)&&Object.is(this.previousInputValues.get(e),t))return;let r=this._rootLView;op(n,r[1],r,e,t),this.previousInputValues.set(e,t),Ip(uo(n.index,r),1)}get injector(){return new Ol(this._tNode,this._rootLView)}destroy(){this.hostView.destroy()}onDestroy(e){this.hostView.onDestroy(e)}};function ah(e,t,n){let r=e.projection=[];for(let e=0;e{class e{static __NG_ELEMENT_ID__=sh}return e})();function sh(){return dh(Lo(),T())}var ch=class e extends oh{_lContainer;_hostTNode;_hostLView;constructor(e,t,n){super(),this._lContainer=e,this._hostTNode=t,this._hostLView=n}get element(){return Pl(this._hostTNode,this._hostLView)}get injector(){return new Ol(this._hostTNode,this._hostLView)}get parentInjector(){let e=gl(this._hostTNode,this._hostLView);if(nl(e)){let t=al(e,this._hostLView),n=rl(e),r=t[1].data[n+8];return new Ol(r,t)}return new Ol(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(e){let t=lh(this._lContainer);return t!==null&&t[e]||null}get length(){return this._lContainer.length-10}createEmbeddedView(e,t,n){let r,i;typeof n==`number`?r=n:n!=null&&(r=n.index,i=n.injector);let a=nm(this._lContainer,e.ssrId),o=e.createEmbeddedViewImpl(t||{},i,a);return this.insertImpl(o,r,fp(this._hostTNode,a)),o}createComponent(e,t,n,r,i,a,o){let s,c=t||{};s=c.index,n=c.injector,r=c.projectableNodes,i=c.environmentInjector||c.ngModuleRef,a=c.directives,o=c.bindings;let l=new $m(Oi(e)),u=n||this.parentInjector;if(!i&&l.ngModule==null){let e=this.parentInjector.get(Na,null);e&&(i=e)}let d=Oi(l.componentType??{}),f=nm(this._lContainer,d?.id??null),p=f?.firstChild??null,m=l.create(u,r,p,i,a,o,this._getHostElementNamespace());return this.insertImpl(m.hostView,s,fp(this._hostTNode,f)),m}_getHostElementNamespace(){if(this._hostTNode.type&2){let e=this._hostTNode.parent??this._hostLView[5];return e!==null&&e.type&2&&typeof e.value==`string`&&e.value.toLowerCase()===`foreignobject`?null:e?.namespace??null}return this._hostTNode.namespace}insert(e,t){return this.insertImpl(e,t,!0)}insertImpl(t,n,r){let i=t._lView;if(po(i)){let n=this.indexOf(t);if(n!==-1)this.detach(n);else{let n=i[3],r=new e(n,n[5],n[3]);r.detach(r.indexOf(t))}}let a=this._adjustIndex(n),o=this._lContainer;return zp(o,i,a,r),t.attachToViewContainerRef(),ia(uh(o),a,t),t}move(e,t){return this.insert(e,t)}indexOf(e){let t=lh(this._lContainer);return t===null?-1:t.indexOf(e)}remove(e){let t=this._adjustIndex(e,-1),n=Vp(this._lContainer,t);n&&(aa(uh(this._lContainer),t),df(n[1],n))}detach(e){let t=this._adjustIndex(e,-1),n=Vp(this._lContainer,t);return n&&aa(uh(this._lContainer),t)!=null?new Wp(n):null}_adjustIndex(e,t=0){return e??this.length+t}};function lh(e){return e[8]}function uh(e){return e[8]||=[]}function dh(e,t){let n,r=t[e.index];return Ya(r)?n=r:(n=Lp(r,t,null,e),t[e.index]=n,Rf(t,n)),ph(n,t,e,r),new ch(n,e,t)}function fh(e,t){let n=e[11],r=n.createComment(``),i=oo(t,e);return Tu(n,n.parentNode(i),r,n.nextSibling(i),!1),r}var ph=gh,mh=()=>!1;function hh(e,t,n){return mh(e,t,n)}function gh(e,t,n,r){if(e[7])return;let i;i=n.type&8?io(r):fh(t,n),e[7]=i}var _h=class e{queryList;matches=null;constructor(e){this.queryList=e}clone(){return new e(this.queryList)}setDirty(){this.queryList.setDirty()}},vh=class e{queries;constructor(e=[]){this.queries=e}createEmbeddedView(t){let n=t.queries;if(n!==null){let r=t.contentQueries===null?n.length:t.contentQueries[0],i=[];for(let e=0;e0)r.push(o[e/2]);else{let i=a[e+1],o=t[-n];for(let e=10;ee.trim())}function Mh(e,t,n){e.queries===null&&(e.queries=new bh),e.queries.track(new xh(t,n))}function Nh(e,t){return e.queries.getByIndex(t)}function Ph(e,t){let n=e[1],r=Nh(n,t);return r.crossesNgTemplate?Dh(n,e,t,[]):Eh(n,e,r,t)}function Fh(e,t,n){let r,i=Nn(()=>{r._dirtyCounter();let n=zh(r,e);if(t&&n===void 0)throw new ri(-951,!1);return n});return r=i[fn],r._dirtyCounter=k(0),r._flatValue=void 0,i}function Ih(e){return Fh(!0,!1,e)}function Lh(e){return Fh(!0,!0,e)}function Rh(e,t){let n=e[fn];n._lView=T(),n._queryIndex=t,n._queryList=Oh(n._lView,t),n._queryList.onDirty(()=>n._dirtyCounter.update(e=>e+1))}function zh(e,t){let n=e._lView,r=e._queryIndex;if(n===void 0||r===void 0||n[2]&4)return t?void 0:pa;let i=Oh(n,r),a=Ph(n,r);return i.reset(a,Il),t?i.first:i._changesDetected||e._flatValue===void 0?e._flatValue=i.toArray():e._flatValue}function Bh(e){return!!e&&typeof e.then==`function`}function Vh(e){return!!e&&typeof e.subscribe==`function`}var Hh=class{},Uh=class extends Hh{injector;instance=null;constructor(e){super();let t=new Pa([...e.providers,{provide:Hh,useValue:this}],e.parent||Ma(),e.debugName,new Set([`environment`]));this.injector=t,e.runEnvironmentInitializers&&t.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(e){this.injector.onDestroy(e)}};function Wh(e,t,n=null){return new Uh({providers:e,parent:t,debugName:n,runEnvironmentInitializers:!0}).injector}var Gh=(()=>{class e{_injector;cachedInjectors=new Map;constructor(e){this._injector=e}getOrCreateStandaloneInjector(e){if(!e.standalone)return null;if(!this.cachedInjectors.has(e)){let t=ya(!1,e.type),n=t.length>0?Wh([t],this._injector,``):null;this.cachedInjectors.set(e,n)}return this.cachedInjectors.get(e)}ngOnDestroy(){try{for(let e of this.cachedInjectors.values())e!==null&&e.destroy()}finally{this.cachedInjectors.clear()}}static ɵprov=pi({token:e,providedIn:`environment`,factory:()=>new e(Yi(Na))})}return e})();function Kh(e){return wc(()=>{let t=Qh(e),n={...t,decls:e.decls,vars:e.vars,template:e.template,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,onPush:e.changeDetection!==Bl.Eager,directiveDefs:null,pipeDefs:null,dependencies:t.standalone&&e.dependencies||null,getStandaloneInjector:t.standalone?e=>e.get(Gh).getOrCreateStandaloneInjector(n):null,getExternalStyles:null,signals:e.signals??!1,data:e.data||{},encapsulation:e.encapsulation||uu.Emulated,styles:e.styles||pa,_:null,schemas:e.schemas||null,tView:null,id:``};t.standalone&&Id(`NgStandalone`),$h(n);let r=e.dependencies;return n.directiveDefs=eg(r,qh),n.pipeDefs=eg(r,Ai),n.id=tg(n),n})}function qh(e){return Oi(e)||ki(e)}function Jh(e,t){if(e==null)return fa;let n={};for(let r in e)if(Object.hasOwn(e,r)){let i=e[r],a,o,s,c;Array.isArray(i)?(s=i[0],a=i[1],o=i[2]??a,c=i[3]||null):(a=i,o=i,s=Bf.None,c=null),n[a]=[r,s,c],t[a]=o}return n}function Yh(e){if(e==null)return fa;let t={};for(let n in e)Object.hasOwn(e,n)&&(t[e[n]]=n);return t}function Xh(e){return wc(()=>{let t=Qh(e);return $h(t),t})}function Zh(e){return{type:e.type,name:e.name,factory:null,pure:e.pure!==!1,standalone:e.standalone??!0,onDestroy:e.type.prototype.ngOnDestroy||null}}function Qh(e){let t={};return{type:e.type,providersResolver:null,viewProvidersResolver:null,factory:null,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:t,inputConfig:e.inputs||fa,exportAs:e.exportAs||null,standalone:e.standalone??!0,signals:e.signals===!0,selectors:e.selectors||pa,viewQuery:e.viewQuery||null,features:e.features||null,setInput:null,resolveHostDirectives:null,hostDirectives:null,controlDef:null,signalFormsInputPresence:null,inputs:Jh(e.inputs,t),outputs:Yh(e.outputs),debugInfo:null}}function $h(e){e.features?.forEach(t=>t(e))}function eg(e,t){return e?()=>{let n=typeof e==`function`?e():e,r=[];for(let e of n){let n=t(e);n!==null&&r.push(n)}return r}:null}function tg(e){let t=0,n=typeof e.consts==`function`?``:e.consts,r=[e.selectors,e.ngContentSelectors,e.hostVars,e.hostAttrs,n,e.vars,e.decls,e.encapsulation,e.standalone,e.signals,e.exportAs,JSON.stringify(e.inputs),JSON.stringify(e.outputs),Object.getOwnPropertyNames(e.type.prototype),!!e.contentQueries,!!e.viewQuery];for(let e of r.join(`|`))t=Math.imul(31,t)+e.charCodeAt(0)<<0;return t+=2147483648,`c`+t}var ng=new bi(``),rg=(()=>{class e{resolve;reject;initialized=!1;done=!1;donePromise=new Promise((e,t)=>{this.resolve=e,this.reject=t});appInits=w(ng,{optional:!0})??[];injector=w(ws);constructor(){}runInitializers(){if(this.initialized)return;let e=[];for(let t of this.appInits){let n=Ga(this.injector,t);if(Bh(n))e.push(n);else if(Vh(n)){let t=new Promise((e,t)=>{n.subscribe({complete:e,error:t})});e.push(t)}}let t=()=>{this.done=!0,this.resolve()};Promise.all(e).then(()=>{t()}).catch(e=>{this.reject(e)}),e.length===0&&t(),this.initialized=!0}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})}return e})();function ig(e,t,n,r,i,a,o,s){if(n.firstCreatePass){e.mergedAttrs=el(e.mergedAttrs,e.attrs);let t=e.tView=jf(2,e,i,a,o,n.directiveRegistry,n.pipeRegistry,null,n.schemas,n.consts,null);n.queries!==null&&(n.queries.template(n,e),t.queries=n.queries.embeddedTView(e))}s&&(e.flags|=s),Bo(e,!1);let c=cg(n,t,e,r);bs()&&bf(n,t,c,e),ql(c,t);let l=Lp(c,t,c,e);t[r+27]=l,Rf(t,l),hh(l,e,t)}function ag(e,t,n,r,i,a,o,s,c,l,u){let d=n+27,f;return t.firstCreatePass?(f=Jp(t,d,4,o||null,s||null),Mo()&&Dm(t,e,f,mo(t.consts,l),$f),Bc(t,f)):f=t.data[d],ig(f,e,t,n,r,i,a,c),Qa(f)&&Uf(t,e,f),l!=null&&Wf(e,f,u),f}function og(e,t,n,r,i,a,o,s,c,l,u){let d=n+27,f;if(t.firstCreatePass){if(f=Jp(t,d,4,o||null,s||null),l!=null){let e=mo(t.consts,l);f.localNames=[];for(let t=0;t{throw new ri(600,``)})}var pg=10,mg=(()=>{class e{_runningTick=!1;_destroyed=!1;_destroyListeners=[];_views=[];internalErrorHandler=w(Zs);afterRenderManager=w(Ld);zonelessEnabled=w(cc);rootEffectScheduler=w(uc);dirtyFlags=0;tracingSnapshot=null;allTestViews=new Set;autoDetectTestViews=new Set;includeAllTestViews=!1;afterTick=new Qr;get allViews(){return[...(this.includeAllTestViews?this.allTestViews:this.autoDetectTestViews).keys(),...this._views]}get destroyed(){return this._destroyed}componentTypes=[];components=[];internalPendingTask=w(As);get isStable(){return this.internalPendingTask.hasPendingTasksObservable.pipe(ti(e=>!e))}constructor(){w(Pd,{optional:!0})}whenStable(){let e;return new Promise(t=>{e=this.isStable.subscribe({next:e=>{e&&t()}})}).finally(()=>{e.unsubscribe()})}_injector=w(Na);_rendererFactory=null;get injector(){return this._injector}bootstrap(e,t){return this.bootstrapImpl(e,t)}bootstrapImpl(e,t,n=ws.NULL){return this._injector.get(Rs).run(()=>{if(Rc(Tc.BootstrapComponentStart),!this._injector.get(rg).done)throw new ri(405,``);let r=Oi(e),i=this._injector.get(Hh),a=new $m(r,i);this.componentTypes.push(e);let{hostElement:o,directives:s,bindings:c}=hg(t),l=o||a.selector,u=a.create(n,[],l,i.injector,s,c),d=u.location.nativeElement,f=u.injector.get(ug,null);return f?.registerApplication(d),u.onDestroy(()=>{this.detachView(u.hostView),gg(this.components,u),f?.unregisterApplication(d)}),this._loadComponent(u),Rc(Tc.BootstrapComponentEnd,u),u})}tick(){this.zonelessEnabled||(this.dirtyFlags|=1),this._tick()}_tick(){Rc(Tc.ChangeDetectionStart),this.tracingSnapshot===null?this.tickImpl():this.tracingSnapshot.run(Nd.CHANGE_DETECTION,this.tickImpl)}tickImpl=()=>{if(this._runningTick)throw Rc(Tc.ChangeDetectionEnd),new ri(101,!1);let e=C(null);try{this._runningTick=!0,this.synchronize()}finally{this._runningTick=!1,this.tracingSnapshot?.dispose(),this.tracingSnapshot=null,C(e),this.afterTick.next(),Rc(Tc.ChangeDetectionEnd)}};synchronize(){this._rendererFactory===null&&!this._injector.destroyed&&(this._rendererFactory=this._injector.get(am,null,{optional:!0}));let e=0;for(;this.dirtyFlags!==0&&e++vo(e))){this.dirtyFlags|=2;return}this.dirtyFlags&=-8}attachView(e){let t=e;this._views.push(t),t.attachToAppRef(this)}detachView(e){let t=e;gg(this._views,t),t.detachFromAppRef()}_loadComponent(e){this.attachView(e.hostView);try{this.tick()}catch(e){this.internalErrorHandler(e)}this.components.push(e),this._injector.get(dg,[]).forEach(t=>t(e))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(e=>e()),this._views.slice().forEach(e=>e.destroy())}finally{this._destroyed=!0,this._views=[],this._destroyListeners=[]}}onDestroy(e){return this._destroyListeners.push(e),()=>gg(this._destroyListeners,e)}destroy(){if(this._destroyed)throw new ri(406,!1);let e=this._injector;e.destroy&&!e.destroyed&&e.destroy()}get viewCount(){return this._views.length}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})}return e})();function hg(e){return e===void 0||typeof e==`string`||e instanceof Element?{hostElement:e}:e}function gg(e,t){let n=e.indexOf(t);n>-1&&e.splice(n,1)}function j(e,t,n,r){let i=T();return fm(i,Yo(),t)&&(Io(),ep(hs(),i,e,t,n,r)),j}function _g(e){if(Id(`NgAnimateEnter`),!_d)return _g;let t=T();if(vd(t))return _g;let n=Lo(),r=t[9].get(Rs);return Md(Od(t),n,()=>vg(t,n,e,r)),Yd(t[9]),Xd(t[9],Od(t)),_g}function vg(e,t,n,r){let i=oo(t,e),a=e[11],o=kd(n),s=[],c=!1,l=e=>{if(Ad(e)!==i)return;let t=e instanceof AnimationEvent?`animationend`:`transitionend`;r.runOutsideAngular(()=>{a.listen(i,t,u)})},u=e=>{Ad(e)===i&&(jd(e,i)&&(c=!0),yg(e,i,a))};if(o&&o.length>0){r.runOutsideAngular(()=>{s.push(a.listen(i,`animationstart`,l)),s.push(a.listen(i,`transitionstart`,l))}),yd(i,o,s);for(let e of o)a.addClass(i,e);r.runOutsideAngular(()=>{requestAnimationFrame(()=>{if(!c&&(fd(i,Sd,_d),!Sd.has(i))){for(let e of o)a.removeClass(i,e);bd(i)}})})}}function yg(e,t,n){let r=xd.get(t);if(Ad(e)===t&&r&&jd(e,t)){e.stopPropagation();for(let e of r.classList)n.removeClass(t,e);bd(t)}}var bg=class{destroy(e){}updateValue(e,t){}swap(e,t){let n=Math.min(e,t),r=Math.max(e,t),i=this.detach(r);if(r-n>1){let e=this.detach(n);this.attach(n,i),this.attach(r,e)}else this.attach(n,i)}move(e,t){this.attach(t,this.detach(e))}};function xg(e,t,n,r,i){return e===n&&Object.is(t,r)?1:Object.is(i(e,t),i(n,r))?-1:0}function Sg(e,t,n,r){let i,a,o=0,s=e.length-1;if(Array.isArray(t)){C(r);let c=t.length-1;for(C(null);o<=s&&o<=c;){let r=e.at(o),l=t[o],u=xg(o,r,o,l,n);if(u!==0){u<0&&e.updateValue(o,l),o++;continue}let d=e.at(s),f=t[c],p=xg(s,d,c,f,n);if(p!==0){p<0&&e.updateValue(s,f),s--,c--;continue}let m=n(o,r),h=n(s,d),g=n(o,l);if(Object.is(g,h)){let t=n(c,f);Object.is(t,m)?(e.swap(o,s),e.updateValue(s,f),c--,s--):e.move(s,o),e.updateValue(o,l),o++;continue}if(i??=new Eg,a??=Tg(e,o,s,n),Cg(e,i,o,g))e.updateValue(o,l),o++,s++;else if(a.has(g))i.set(m,e.detach(o)),s--;else{let n=e.create(o,t[o]);e.attach(o,n),o++,s++}}for(;o<=c;)wg(e,i,n,o,t[o]),o++}else if(t!=null){C(r);let c=t[Symbol.iterator]();C(null);let l=c.next();for(;!l.done&&o<=s;){let t=e.at(o),r=l.value,u=xg(o,t,o,r,n);if(u!==0)u<0&&e.updateValue(o,r),o++,l=c.next();else{i??=new Eg,a??=Tg(e,o,s,n);let u=n(o,r);if(Cg(e,i,o,u))e.updateValue(o,r),o++,s++,l=c.next();else if(!a.has(u))e.attach(o,e.create(o,r)),o++,s++,l=c.next();else{let r=n(o,t);i.set(r,e.detach(o)),s--}}}for(;!l.done;)wg(e,i,n,e.length,l.value),l=c.next()}for(;o<=s;)e.destroy(e.detach(s--));i?.forEach(t=>{e.destroy(t)})}function Cg(e,t,n,r){return t!==void 0&&t.has(r)?(e.attach(n,t.get(r)),t.delete(r),!0):!1}function wg(e,t,n,r,i){if(Cg(e,t,r,n(r,i)))e.updateValue(r,i);else{let t=e.create(r,i);e.attach(r,t)}}function Tg(e,t,n,r){let i=new Set;for(let a=t;a<=n;a++)i.add(r(a,e.at(a)));return i}var Eg=class{kvMap=new Map;_vMap=void 0;has(e){return this.kvMap.has(e)}delete(e){if(!this.has(e))return!1;let t=this.kvMap.get(e);return this._vMap!==void 0&&this._vMap.has(t)?(this.kvMap.set(e,this._vMap.get(t)),this._vMap.delete(t)):this.kvMap.delete(e),!0}get(e){return this.kvMap.get(e)}set(e,t){if(this.kvMap.has(e)){let n=this.kvMap.get(e);this._vMap===void 0&&(this._vMap=new Map);let r=this._vMap;for(;r.has(n);)n=r.get(n);r.set(n,t)}else this.kvMap.set(e,t)}forEach(e){for(let[t,n]of this.kvMap)if(e(n,t),this._vMap!==void 0){let r=this._vMap;for(;r.has(n);)n=r.get(n),e(n,t)}}};function M(e,t,n,r,i,a,o,s){Id(`NgControlFlow`);let c=T(),l=Io();return og(c,l,e,t,n,r,i,mo(l.consts,a),256,o,s),Dg}function Dg(e,t,n,r,i,a,o,s){Id(`NgControlFlow`);let c=T(),l=Io();return og(c,l,e,t,n,r,i,mo(l.consts,a),512,o,s),Dg}function N(e,t){Id(`NgControlFlow`);let n=T(),r=Yo(),i=n[r]===$u?-1:n[r],a=i===-1?void 0:Ng(n,27+i);if(fm(n,r,e)){let r=C(null);try{if(a!==void 0&&Bp(a,0),e!==-1){let r=27+e,i=Ng(n,r),a=Rg(n[1],r),o=rm(i,a,n);zp(i,dp(n,a,t,{dehydratedView:o}),0,fp(a,o))}}finally{C(r)}}else if(a!==void 0){let e=Rp(a,0);e!==void 0&&(e[8]=t)}}var Og=class{lContainer;$implicit;$index;constructor(e,t,n){this.lContainer=e,this.$implicit=t,this.$index=n}get $count(){return this.lContainer.length-10}};function kg(e){return e}function Ag(e,t){return t}var jg=class{hasEmptyBlock;trackByFn;liveCollection;constructor(e,t,n){this.hasEmptyBlock=e,this.trackByFn=t,this.liveCollection=n}};function P(e,t,n,r,i,a,o,s,c,l,u,d,f){Id(`NgControlFlow`);let p=T(),m=Io(),h=c!==void 0,g=T(),_=new jg(h,s?o.bind(g[15][8]):o);g[27+e]=_,og(p,m,e+1,t,n,r,i,mo(m.consts,a),256),h&&og(p,m,e+2,c,l,u,d,mo(m.consts,f),512)}var Mg=class extends bg{lContainer;hostLView;templateTNode;operationsCounter=void 0;needsIndexUpdate=!1;constructor(e,t,n){super(),this.lContainer=e,this.hostLView=t,this.templateTNode=n}get length(){return this.lContainer.length-10}at(e){return this.getLView(e)[8].$implicit}attach(e,t){let n=t[6];this.needsIndexUpdate||=e!==this.length,zp(this.lContainer,t,e,fp(this.templateTNode,n)),Pg(this.lContainer,e)}detach(e){return this.needsIndexUpdate||=e!==this.length-1,Fg(this.lContainer,e),Ig(this.lContainer,e)}create(e,t){let n=nm(this.lContainer,this.templateTNode.tView.ssrId);return dp(this.hostLView,this.templateTNode,new Og(this.lContainer,t,e),{dehydratedView:n})}destroy(e){df(e[1],e)}updateValue(e,t){this.getLView(e)[8].$implicit=t}reset(){this.needsIndexUpdate=!1}updateIndexes(){if(this.needsIndexUpdate)for(let e=0;e0){let e=n[9];qd(e,r),md.delete(n[19]),r.detachedLeaveAnimationFns=void 0}}function Fg(e,t){if(e.length<=10)return;let n=e[10+t],r=n?n[26]:void 0;r&&r.leave&&r.leave.size>0&&(r.detachedLeaveAnimationFns=[])}function Ig(e,t){return Vp(e,t)}function Lg(e,t){return Rp(e,t)}function Rg(e,t){return so(e,t)}function I(e,t,n){let r=T();return fm(r,Yo(),t)&&(Io(),qf(hs(),r,e,t,r[11],n)),I}function zg(e,t,n,r,i){op(t,e,n,i?`class`:`style`,r)}function L(e,t,n,r){let i=T(),a=i[1],o=e+27,s=a.firstCreatePass?Vm(o,i,2,t,$f,Mo(),n,r):a.data[o];if(Za(s)){let n=i[10].tracingService;if(n&&n.componentCreate){let o=a.data[s.directiveStart+s.componentOffset];return n.componentCreate(sm(o),()=>(Bg(e,t,i,s,r),L))}}return Bg(e,t,i,s,r),L}function Bg(e,t,n,r,i){if(rp(r,n,e,t,Hg),Qa(r)){let e=n[1];Uf(e,n,r),lu(e,r,n)}i!=null&&Wf(n,r)}function R(){let e=Io(),t=ip(Lo());return e.firstCreatePass&&Hm(e,t),Po(t)&&Fo(),jo(),t.classesWithoutHost!=null&&Yc(t)&&zg(e,t,T(),t.classesWithoutHost,!0),t.stylesWithoutHost!=null&&Xc(t)&&zg(e,t,T(),t.stylesWithoutHost,!1),R}function z(e,t,n,r){return L(e,t,n,r),R(),z}function B(e,t,n,r){let i=T(),a=i[1],o=e+27,s=a.firstCreatePass?Um(o,a,2,t,n,r):a.data[o];return rp(s,i,e,t,Hg),r!=null&&Wf(i,s),B}function V(){return Po(ip(Lo()))&&Fo(),jo(),V}function Vg(e,t,n,r){return B(e,t,n,r),V(),Vg}var Hg=(e,t,n,r,i)=>(xs(!0),wu(t[11],r,vs()));function Ug(e,t,n){let r=T(),i=r[1],a=e+27,o=i.firstCreatePass?Vm(a,r,8,`ng-container`,$f,Mo(),t,n):i.data[a];if(rp(o,r,e,`ng-container`,Kg),Qa(o)){let e=r[1];Uf(e,r,o),lu(e,o,r)}return n!=null&&Wf(r,o),Ug}function Wg(){let e=Io(),t=ip(Lo());return e.firstCreatePass&&Hm(e,t),Wg}function Gg(e,t,n){return Ug(e,t,n),Wg(),Gg}var Kg=(e,t,n,r,i)=>(xs(!0),Cu(t[11],``));function H(){return T()}function qg(e,t,n){let r=T();return fm(r,Yo(),t)&&(Io(),Jf(hs(),r,e,t,r[11],n)),qg}var Jg=void 0;function Yg(e){let t=Math.floor(Math.abs(e)),n=e.toString().replace(/^[^.]*\.?/,``).length;return t===1&&n===0?1:5}var Xg=[`en`,[[`a`,`p`],[`AM`,`PM`]],[[`AM`,`PM`]],[[`S`,`M`,`T`,`W`,`T`,`F`,`S`],[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],[`Sunday`,`Monday`,`Tuesday`,`Wednesday`,`Thursday`,`Friday`,`Saturday`],[`Su`,`Mo`,`Tu`,`We`,`Th`,`Fr`,`Sa`]],Jg,[[`J`,`F`,`M`,`A`,`M`,`J`,`J`,`A`,`S`,`O`,`N`,`D`],[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`],[`January`,`February`,`March`,`April`,`May`,`June`,`July`,`August`,`September`,`October`,`November`,`December`]],Jg,[[`B`,`A`],[`BC`,`AD`],[`Before Christ`,`Anno Domini`]],0,[6,0],[`M/d/yy`,`MMM d, y`,`MMMM d, y`,`EEEE, MMMM d, y`],[`h:mm a`,`h:mm:ss a`,`h:mm:ss a z`,`h:mm:ss a zzzz`],[`{1}, {0}`,Jg,Jg,Jg],[`.`,`,`,`;`,`%`,`+`,`-`,`E`,`×`,`‰`,`∞`,`NaN`,`:`],[`#,##0.###`,`#,##0%`,`¤#,##0.00`,`#E0`],`USD`,`$`,`US Dollar`,{},`ltr`,Yg],Zg=Object.create(null);function Qg(e){let t=t_(e),n=$g(t);if(n)return n;let r=t.split(`-`)[0];if(n=$g(r),n)return n;if(r===`en`)return Xg;throw new ri(701,!1)}function $g(e){if(!(e in Zg)){let t=Wi.ng&&Wi.ng.common&&Wi.ng.common.locales&&Wi.ng.common.locales[e];return t!==void 0&&(Zg[e]=t),t}return Zg[e]}var e_={LocaleId:0,DayPeriodsFormat:1,DayPeriodsStandalone:2,DaysFormat:3,DaysStandalone:4,MonthsFormat:5,MonthsStandalone:6,Eras:7,FirstDayOfWeek:8,WeekendRange:9,DateFormat:10,TimeFormat:11,DateTimeFormat:12,NumberSymbols:13,NumberFormats:14,CurrencyCode:15,CurrencySymbol:16,CurrencyName:17,Currencies:18,Directionality:19,PluralCase:20,ExtraData:21};function t_(e){return e.toLowerCase().replace(/_/g,`-`)}var n_=`en-US`;function r_(e){typeof e==`string`&&e.toLowerCase().replace(/_/g,`-`)}function U(e,t,n){let r=T(),i=Io(),a=Lo();return i_(i,r,r[11],a,e,t,n),U}function W(e,t,n){let r=T(),i=Io(),a=Lo();return(a.type&3||n)&&vm(a,i,r,n,r[11],e,t,gm(a,r,t)),W}function i_(e,t,n,r,i,a,o){let s=!0,c=null;if((r.type&3||o)&&(c??=gm(r,t,a),vm(r,e,t,o,n,i,a,c)&&(s=!1)),s){let e=r.outputs?.[i],n=r.hostDirectiveOutputs?.[i];if(n&&n.length)for(let e=0;e>17&32767}function m_(e){return(e&2)==2}function h_(e,t){return e&131071|t<<17}function g_(e){return e|2}function __(e){return(e&131068)>>2}function v_(e,t){return e&-131069|t<<2}function y_(e){return(e&1)==1}function b_(e){return e|1}function x_(e,t,n,r,i,a){let o=a?t.classBindings:t.styleBindings,s=p_(o),c=__(o);e[r]=n;let l=!1,u;if(Array.isArray(n)){let e=n;u=e[1],(u===null||ua(e,u)>0)&&(l=!0)}else u=n;if(i){if(c!==0){let t=p_(e[s+1]);e[r+1]=f_(t,s),t!==0&&(e[t+1]=v_(e[t+1],r)),e[s+1]=h_(e[s+1],r)}else e[r+1]=f_(s,0),s!==0&&(e[s+1]=v_(e[s+1],r)),s=r}else e[r+1]=f_(c,0),s===0?s=r:e[c+1]=v_(e[c+1],r),c=r;l&&(e[r+1]=g_(e[r+1])),C_(e,u,r,!0),C_(e,u,r,!1),S_(t,u,e,r,a),o=f_(s,c),a?t.classBindings=o:t.styleBindings=o}function S_(e,t,n,r,i){let a=i?e.residualClasses:e.residualStyles;a!=null&&typeof t==`string`&&ua(a,t)>=0&&(n[r+1]=b_(n[r+1]))}function C_(e,t,n,r){let i=e[n+1],a=t===null,o=r?p_(i):__(i),s=!1;for(;o!==0&&(s===!1||a);){let n=e[o],i=e[o+1];w_(n,t)&&(s=!0,e[o+1]=r?b_(i):g_(i)),o=r?p_(i):__(i)}s&&(e[n+1]=r?g_(i):b_(i))}function w_(e,t){return e===null||t==null||(Array.isArray(e)?e[1]:e)===t?!0:Array.isArray(e)&&typeof t==`string`?ua(e,t)>=0:!1}var T_={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function E_(e){return e.substring(T_.key,T_.keyEnd)}function D_(e){return k_(e),O_(e,A_(e,0,T_.textEnd))}function O_(e,t){let n=T_.textEnd;return n===t?-1:(t=T_.keyEnd=j_(e,T_.key=t,n),A_(e,t,n))}function k_(e){T_.key=0,T_.keyEnd=0,T_.value=0,T_.valueEnd=0,T_.textEnd=e.length}function A_(e,t,n){for(;t32;)t++;return t}function K(e,t,n){return P_(e,t,n,!1),K}function q(e,t){return P_(e,t,null,!0),q}function M_(e){F_(G_,N_,e,!0)}function N_(e,t){for(let n=D_(t);n>=0;n=O_(t,n))ca(e,E_(t),!0)}function P_(e,t,n,r){let i=T(),a=Io(),o=Xo(2);if(a.firstUpdatePass&&L_(a,e,o,r),t!==$u&&fm(i,o,t)){let s=a.data[ps()];q_(a,s,i,i[11],e,i[o+1]=X_(t,n),r,o)}}function F_(e,t,n,r){let i=Io(),a=Xo(2);i.firstUpdatePass&&L_(i,null,a,r);let o=T();if(n!==$u&&fm(o,a,n)){let s=i.data[ps()];if(Z_(s,r)&&!I_(i,a)){let e=r?s.classesWithoutHost:s.stylesWithoutHost;e!==null&&(n=ci(e,n||``)),zg(i,s,o,n,r)}else K_(i,s,o,o[11],o[a+1],o[a+1]=W_(e,t,n),r,a)}}function I_(e,t){return t>=e.expandoStartIndex}function L_(e,t,n,r){let i=e.data;if(i[n+1]===null){let a=i[ps()],o=I_(e,n);Z_(a,r)&&t===null&&!o&&(t=!1),t=R_(i,a,t,r),x_(i,a,t,n,o,r)}}function R_(e,t,n,r){let i=ts(e),a=r?t.residualClasses:t.residualStyles;if(i===null)(r?t.classBindings:t.styleBindings)===0&&(n=H_(null,e,t,n,r),n=U_(n,t.attrs,r),a=null);else{let o=t.directiveStylingLast;if(o===-1||e[o]!==i){if(n=H_(i,e,t,n,r),a===null){let n=z_(e,t,r);n!==void 0&&Array.isArray(n)&&(n=H_(null,e,t,n[1],r),n=U_(n,t.attrs,r),B_(e,t,r,n))}else a=V_(e,t,r)}}return a!==void 0&&(r?t.residualClasses=a:t.residualStyles=a),n}function z_(e,t,n){let r=n?t.classBindings:t.styleBindings;if(__(r)!==0)return e[p_(r)]}function B_(e,t,n,r){let i=n?t.classBindings:t.styleBindings;e[p_(i)]=r}function V_(e,t,n){let r,i=t.directiveEnd;for(let a=1+t.directiveStylingLast;a0;){let t=e[i],a=Array.isArray(t),c=a?t[1]:t,l=c===null,u=n[i+1];u===$u&&(u=l?pa:void 0);let d=l?la(u,r):c===r?u:void 0;if(a&&!Y_(d)&&(d=la(t,r)),Y_(d)&&(s=d,o))return s;let f=e[i+1];i=o?p_(f):__(f)}if(t!==null){let e=a?t.residualClasses:t.residualStyles;e!=null&&(s=la(e,r))}return s}function Y_(e){return e!==void 0}function X_(e,t){return e==null||e===``||(typeof t==`string`?e=fu(e)+t:typeof e==`object`&&(e=si(fu(e)))),e}function Z_(e,t){return!!(e.flags&(t?8:16))}function J(e,t=``){let n=T(),r=Io(),i=e+27,a=r.firstCreatePass?Jp(r,i,1,t,null):r.data[i],o=Q_(r,n,a,t);n[i]=o,bs()&&bf(r,n,o,a),Bo(a,!1)}var Q_=(e,t,n,r)=>(xs(!0),xu(t[11],r));function $_(e,t,n,r=``){return fm(e,Yo(),n)?t+Mi(n)+r:$u}function ev(e,t,n,r,i,a=``){let o=pm(e,qo(),n,i);return Xo(2),o?t+Mi(n)+r+Mi(i)+a:$u}function tv(e,t,n,r,i,a,o,s=``){let c=mm(e,qo(),n,i,o);return Xo(3),c?t+Mi(n)+r+Mi(i)+a+Mi(o)+s:$u}function nv(e,t,n,r,i,a,o,s,c,l=``){let u=hm(e,qo(),n,i,o,c);return Xo(4),u?t+Mi(n)+r+Mi(i)+a+Mi(o)+s+Mi(c)+l:$u}function Y(e){return X(``,e),Y}function X(e,t,n){let r=T(),i=$_(r,e,t,n);return i!==$u&&av(r,ps(),i),X}function Z(e,t,n,r,i){let a=T(),o=ev(a,e,t,n,r,i);return o!==$u&&av(a,ps(),o),Z}function rv(e,t,n,r,i,a,o){let s=T(),c=tv(s,e,t,n,r,i,a,o);return c!==$u&&av(s,ps(),c),rv}function iv(e,t,n,r,i,a,o,s,c){let l=T(),u=nv(l,e,t,n,r,i,a,o,s,c);return u!==$u&&av(l,ps(),u),iv}function av(e,t,n){let r=ao(t,e);Su(e[11],r,n)}function ov(e,t,n){xc(t)&&(t=t());let r=T();return fm(r,Yo(),t)&&(Io(),qf(hs(),r,e,t,r[11],n)),ov}function sv(e,t){let n=xc(e);return n&&e.set(t),n}function cv(e,t){let n=T(),r=Io(),i=Lo();return i_(r,n,n[11],i,e,t),cv}var lv={};function uv(e){Id(`NgLet`);let t=Io(),n=T(),r=e+27;return Bo(Jp(t,r,128,null,null),!1),lo(t,n,r,lv),uv}function dv(e){return lo(Io(),T(),ps(),e),e}function fv(e){let t=co(Uo(),27+e);if(t===lv)throw new ri(314,!1);return t}function pv(e,t,n=``){return $_(T(),e,t,n)}function mv(e,t){let n=Ko()+e,r=T();return r[n]===$u?um(r,n,t()):dm(r,n)}function hv(e,t,n){return vv(T(),Ko(),e,t,n)}function gv(e,t,n,r,i){return bv(T(),Ko(),e,t,n,r,i)}function _v(e,t){let n=e[t];return n===$u?void 0:n}function vv(e,t,n,r,i,a){let o=t+n;return fm(e,o,i)?um(e,o+1,a?r.call(a,i):r(i)):_v(e,o+1)}function yv(e,t,n,r,i,a,o){let s=t+n;return pm(e,s,i,a)?um(e,s+2,o?r.call(o,i,a):r(i,a)):_v(e,s+2)}function bv(e,t,n,r,i,a,o,s){let c=t+n;return mm(e,c,i,a,o)?um(e,c+3,s?r.call(s,i,a,o):r(i,a,o)):_v(e,c+3)}function xv(e,t){let n=Io(),r,i=e+27;n.firstCreatePass?(r=Sv(t,n.pipeRegistry),n.data[i]=r,r.onDestroy&&(n.destroyHooks??=[]).push(i,r.onDestroy)):r=n.data[i];let a=r.factory||(r.factory=ea(r.type,!0)),o=Hi(Em);try{let e=sl(!1),t=a();return sl(e),lo(n,T(),i,t),t}finally{Hi(o)}}function Sv(e,t){if(t)for(let n=t.length-1;n>=0;n--){let r=t[n];if(e===r.name)return r}}function Cv(e,t,n){let r=e+27,i=T(),a=co(i,r);return Tv(i,r)?vv(i,Ko(),t,a.transform,n,a):a.transform(n)}function wv(e,t,n,r){let i=e+27,a=T(),o=co(a,i);return Tv(a,i)?yv(a,Ko(),t,o.transform,n,r,o):o.transform(n,r)}function Tv(e,t){return e[1].data[t].pure}function Ev(e,t){return qp(e,t)}var Dv=(()=>{class e{applicationErrorHandler=w(Zs);appRef=w(mg);taskService=w(As);ngZone=w(Rs);zonelessEnabled=w(cc);tracing=w(Pd,{optional:!0});zoneIsDefined=typeof Zone<`u`&&!!Zone.root.run;schedulerTickApplyArgs=[{data:{__scheduler_tick__:!0}}];subscriptions=new gr;angularZoneId=this.zoneIsDefined?this.ngZone._inner?.get(Is):null;scheduleInRootZone=!this.zonelessEnabled&&this.zoneIsDefined&&(w(lc,{optional:!0})??!1);cancelScheduledCallback=null;useMicrotaskScheduler=!1;runningTick=!1;pendingRenderTaskId=null;constructor(){this.subscriptions.add(this.appRef.afterTick.subscribe(()=>{let e=this.taskService.add();if(!this.runningTick&&(this.cleanup(),!this.zonelessEnabled||this.appRef.includeAllTestViews)){this.taskService.remove(e);return}this.switchToMicrotaskScheduler(),this.taskService.remove(e)})),this.subscriptions.add(this.ngZone.onUnstable.subscribe(()=>{this.runningTick||this.cleanup()}))}switchToMicrotaskScheduler(){this.ngZone.runOutsideAngular(()=>{let e=this.taskService.add();this.useMicrotaskScheduler=!0,queueMicrotask(()=>{this.useMicrotaskScheduler=!1,this.taskService.remove(e)})})}notify(e){if(!this.zonelessEnabled&&e===5)return;switch(e){case 0:case 2:this.appRef.dirtyFlags|=2;break;case 3:case 4:case 5:case 1:this.appRef.dirtyFlags|=4;break;case 6:this.appRef.dirtyFlags|=2;break;case 12:this.appRef.dirtyFlags|=16;break;case 13:this.appRef.dirtyFlags|=2;break;case 11:break;default:this.appRef.dirtyFlags|=8}if(this.appRef.tracingSnapshot=this.tracing?.snapshot(this.appRef.tracingSnapshot)??null,!this.shouldScheduleTick())return;let t=this.useMicrotaskScheduler?Ps:Ns;this.pendingRenderTaskId=this.taskService.add(),this.cancelScheduledCallback=this.scheduleInRootZone?Zone.root.run(()=>t(()=>this.tick())):this.ngZone.runOutsideAngular(()=>t(()=>this.tick()))}shouldScheduleTick(){return!(this.appRef.destroyed||this.pendingRenderTaskId!==null||this.runningTick||this.appRef._runningTick||!this.zonelessEnabled&&this.zoneIsDefined&&Zone.current.get(`isAngularZone_ID`+this.angularZoneId))}tick(){if(this.runningTick||this.appRef.destroyed)return;if(this.appRef.dirtyFlags===0){this.cleanup();return}!this.zonelessEnabled&&this.appRef.dirtyFlags&7&&(this.appRef.dirtyFlags|=1);let e=this.taskService.add();try{this.ngZone.run(()=>{this.runningTick=!0,this.appRef._tick()},void 0,this.schedulerTickApplyArgs)}catch(e){this.applicationErrorHandler(e)}finally{this.taskService.remove(e),this.cleanup()}}ngOnDestroy(){this.subscriptions.unsubscribe(),this.cleanup()}cleanup(){if(this.runningTick=!1,this.cancelScheduledCallback?.(),this.cancelScheduledCallback=null,this.pendingRenderTaskId!==null){let e=this.pendingRenderTaskId;this.pendingRenderTaskId=null,this.taskService.remove(e)}}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})}return e})();function Ov(){return[{provide:sc,useExisting:Dv},{provide:Rs,useClass:Ks},{provide:cc,useValue:!0}]}function kv(){return typeof $localize<`u`&&$localize.locale||`en-US`}var Av=new bi(``,{factory:()=>w(Av,{optional:!0,skipSelf:!0})||kv()}),jv=class{destroyed=!1;listeners=null;errorHandler=w(Xs,{optional:!0});isEmitting=!1;hasNullListeners=!1;destroyRef=w(Es);constructor(){this.destroyRef.onDestroy(()=>{this.destroyed=!0,this.listeners=null})}subscribe(e){if(this.destroyed)throw new ri(953,!1);return(this.listeners??=[]).push(e),{unsubscribe:()=>{let t=this.listeners?this.listeners.indexOf(e):-1;t>-1&&(this.isEmitting?(this.hasNullListeners=!0,this.listeners[t]=null):this.listeners.splice(t,1))}}}emit(e){if(this.destroyed){console.warn(ai(953,!1));return}if(this.listeners===null)return;this.isEmitting=!0;let t=C(null);try{for(let t of this.listeners)try{t!==null&&t(e)}catch(e){this.errorHandler?.handleError(e)}}finally{this.hasNullListeners&&(this.hasNullListeners=!1,this.listeners&&Mv(this.listeners)),C(t),this.isEmitting=!1}}};function Mv(e){let t=e.length-1;for(;t>-1;)e[t]===null&&e.splice(t,1),t--}function Q(e,t){return Nn(e,t?.equal)}function Nv(e){return or(e)}(class e extends Error{_brand;constructor(e){super(e)}static IDLE=new e(`IDLE`);static LOADING=new e(`LOADING`)});var Pv=e=>e;function Fv(e,t){return typeof e==`function`?Iv(nr(e,Pv,t?.equal),t?.debugName,t?.set):Iv(nr(e.source,e.computation,e.equal),e.debugName,e.set)}function Iv(e,t,n){let r=e[fn],i=e;if(n!==void 0){let t=e=>rr(r,e);i.set=e=>n(e,t),i.update=r=>n(r(Nv(e)),t)}else i.set=e=>rr(r,e),i.update=e=>ir(r,e);return i.asReadonly=$s.bind(e),i}function Lv(e,t){let n=Object.create(Cc);n.value=e,n.transformFn=t?.transform;function r(){if(hn(n),n.value===Sc)throw new ri(-950,null);return n.value}return r[fn]=n,r}function Rv(e){return new jv}function zv(e,t){return Lv(e,t)}function Bv(e){return Lv(Sc,e)}var $=(zv.required=Bv,zv);function Vv(e,t){let n=Object.create(Cc),r=new jv;n.value=e;function i(){return hn(n),Hv(n.value),n.value}return i[fn]=n,i.asReadonly=$s.bind(i),i.set=e=>{n.equal(n.value,e)||(Gn(n,e),r.emit(e))},i.update=e=>{Hv(n.value),i.set(e(n.value))},i.subscribe=r.subscribe.bind(r),i.destroyRef=r.destroyRef,i}function Hv(e){if(e===Sc)throw new ri(952,!1)}function Uv(e,t){return Vv(e,t)}function Wv(e){return Vv(Sc,e)}var Gv=(Uv.required=Wv,Uv);function Kv(e,t){return Ih(t)}function qv(e,t){return Lh(t)}var Jv=(Kv.required=qv,Kv),Yv=new bi(``),Xv=new bi(``);function Zv(e){return!e.moduleRef}function Qv(e){let t=Zv(e)?e.r3Injector:e.moduleRef.injector,n=t.get(Rs);return n.run(()=>{Zv(e)?e.r3Injector.resolveInjectorInitializers():e.moduleRef.resolveInjectorInitializers();let r=t.get(Zs),i;if(n.runOutsideAngular(()=>{i=n.onError.subscribe({next:r})}),Zv(e)){let n=()=>t.destroy(),r=e.platformInjector.get(Yv);r.add(n),t.onDestroy(()=>{i.unsubscribe(),r.delete(n)})}else{let t=()=>e.moduleRef.destroy(),n=e.platformInjector.get(Yv);n.add(t),e.moduleRef.onDestroy(()=>{gg(e.allPlatformModules,e.moduleRef),i.unsubscribe(),n.delete(t)})}return ey(r,n,()=>{let n=t.get(As),r=n.add(),i=t.get(rg);return i.runInitializers(),i.donePromise.then(()=>{if(r_(t.get(Av,n_)||`en-US`),!t.get(Xv,!0))return Zv(e)?t.get(mg):(e.allPlatformModules.push(e.moduleRef),e.moduleRef);if(Zv(e)){let n=t.get(mg);return e.rootComponent!==void 0&&n.bootstrap(e.rootComponent),n}return $v?.(e.moduleRef,e.allPlatformModules),e.moduleRef}).finally(()=>void n.remove(r))})})}var $v;function ey(e,t,n){try{let r=n();return Bh(r)?r.catch(n=>{throw t.runOutsideAngular(()=>e(n)),n}):r}catch(n){throw t.runOutsideAngular(()=>e(n)),n}}var ty=null;function ny(e=[],t){return ws.create({name:t,providers:[{provide:Oa,useValue:`platform`},{provide:Yv,useValue:new Set([()=>ty=null])},...e]})}function ry(e=[]){if(ty)return ty;let t=ny(e);return ty=t,fg(),iy(t),t}function iy(e){let t=e.get(nc,null);Ga(e,()=>{t?.forEach(e=>e())})}function ay(e){let{rootComponent:t,appProviders:n,platformProviders:r,platformRef:i}=e;Rc(Tc.BootstrapApplicationStart);try{let e=i?.injector??ry(r);return Qv({r3Injector:new Uh({providers:[Ov(),Qs,...n||[]],parent:e,debugName:``,runEnvironmentInitializers:!1}).injector,platformInjector:e,rootComponent:t})}catch(e){return Promise.reject(e)}finally{Rc(Tc.BootstrapApplicationEnd)}}var oy=Symbol(`NOT_SET`),sy=new Set,cy={...qn,kind:`afterRenderEffectPhase`,consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!0,value:oy,cleanup:null,consumerMarkedDirty(){if(this.sequence.impl.executing){if(this.sequence.lastPhase===null||this.sequence.lastPhase(hn(r),r.value),r.signal[fn]=r,r.registerCleanupFn=e=>(r.cleanup??=new Set).add(e),this.nodes[e]=r,this.hooks[e]=e=>r.phaseFn(e)}}afterRun(){super.afterRun(),this.lastPhase=null}destroy(){if(this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();super.destroy();for(let e of this.nodes)if(e)try{for(let t of e.cleanup??sy)t()}finally{Dn(e)}}};function uy(e,t){let n=t?.injector??w(ws),r=n.get(sc),i=n.get(Ld),a=n.get(Pd,null,{optional:!0});i.impl??=n.get(zd);let o=e;typeof o==`function`&&(o={mixedReadWrite:e});let s=n.get(ac,null,{optional:!0}),c=new ly(i.impl,[o.earlyRead,o.write,o.mixedReadWrite,o.read],s?.view,r,n,a?.snapshot(null));return i.impl.register(c),c}var dy=null;function fy(){return dy}function py(e){dy??=e}var my=class{},hy=(function(e){return e[e.Format=0]=`Format`,e[e.Standalone=1]=`Standalone`,e})(hy||{}),gy=(function(e){return e[e.Narrow=0]=`Narrow`,e[e.Abbreviated=1]=`Abbreviated`,e[e.Wide=2]=`Wide`,e[e.Short=3]=`Short`,e})(gy||{}),_y=(function(e){return e[e.Short=0]=`Short`,e[e.Medium=1]=`Medium`,e[e.Long=2]=`Long`,e[e.Full=3]=`Full`,e})(_y||{}),vy={Decimal:0,Group:1,List:2,PercentSign:3,PlusSign:4,MinusSign:5,Exponential:6,SuperscriptingExponent:7,PerMille:8,Infinity:9,NaN:10,TimeSeparator:11,CurrencyDecimal:12,CurrencyGroup:13};function yy(e){return Qg(e)[e_.LocaleId]}function by(e,t,n){let r=Qg(e);return jy(jy([r[e_.DayPeriodsFormat],r[e_.DayPeriodsStandalone]],t),n)}function xy(e,t,n){let r=Qg(e);return jy(jy([r[e_.DaysFormat],r[e_.DaysStandalone]],t),n)}function Sy(e,t,n){let r=Qg(e);return jy(jy([r[e_.MonthsFormat],r[e_.MonthsStandalone]],t),n)}function Cy(e,t){let n=Qg(e)[e_.Eras];return jy(n,t)}function wy(e,t){return jy(Qg(e)[e_.DateFormat],t)}function Ty(e,t){return jy(Qg(e)[e_.TimeFormat],t)}function Ey(e,t){let n=Qg(e)[e_.DateTimeFormat];return jy(n,t)}function Dy(e,t){let n=Qg(e),r=n[e_.NumberSymbols][t];if(r===void 0){if(t===vy.CurrencyDecimal)return n[e_.NumberSymbols][vy.Decimal];if(t===vy.CurrencyGroup)return n[e_.NumberSymbols][vy.Group]}return r}function Oy(e){if(!e[e_.ExtraData])throw new ri(2303,!1)}function ky(e){let t=Qg(e);return Oy(t),(t[e_.ExtraData][2]||[]).map(e=>typeof e==`string`?My(e):[My(e[0]),My(e[1])])}function Ay(e,t,n){let r=Qg(e);return Oy(r),jy(jy([r[e_.ExtraData][0],r[e_.ExtraData][1]],t)||[],n)||[]}function jy(e,t){for(let n=t;n>-1;n--)if(e[n]!==void 0)return e[n];throw new ri(2304,!1)}function My(e){let[t,n]=e.split(`:`);return{hours:+t,minutes:+n}}var Ny=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,Py=Object.create(null),Fy=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/,Iy=256;function Ly(e,t,n,r){let i=ob(e);Ry(t),t=By(n,t)||t;let a=[],o;for(;t;)if(o=Fy.exec(t),o){a=a.concat(o.slice(1));let e=a.pop();if(!e)break;t=e}else{a.push(t);break}let s=i.getTimezoneOffset();r&&(s=rb(r,s),i=ab(i,r));let c=``;return a.forEach(e=>{let t=nb(e);c+=t?t(i,n,s):e===`''`?`'`:e.replace(/(^'|'$)/g,``).replace(/''/g,`'`)}),c}function Ry(e){if(e.length>Iy)throw new ri(2300,!1)}function zy(e,t,n){let r=new Date(0);return r.setFullYear(e,t,n),r.setHours(0,0,0),r}function By(e,t){let n=yy(e);if(Py[n]??=Object.create(null),Py[n][t])return Py[n][t];let r=``;switch(t){case`shortDate`:r=wy(e,_y.Short);break;case`mediumDate`:r=wy(e,_y.Medium);break;case`longDate`:r=wy(e,_y.Long);break;case`fullDate`:r=wy(e,_y.Full);break;case`shortTime`:r=Ty(e,_y.Short);break;case`mediumTime`:r=Ty(e,_y.Medium);break;case`longTime`:r=Ty(e,_y.Long);break;case`fullTime`:r=Ty(e,_y.Full);break;case`short`:let t=By(e,`shortTime`),n=By(e,`shortDate`);r=Vy(Ey(e,_y.Short),[t,n]);break;case`medium`:let i=By(e,`mediumTime`),a=By(e,`mediumDate`);r=Vy(Ey(e,_y.Medium),[i,a]);break;case`long`:let o=By(e,`longTime`),s=By(e,`longDate`);r=Vy(Ey(e,_y.Long),[o,s]);break;case`full`:let c=By(e,`fullTime`),l=By(e,`fullDate`);r=Vy(Ey(e,_y.Full),[c,l])}return r&&(Py[n][t]=r),r}function Vy(e,t){return t&&(e=e.replace(/\{([^}]+)}/g,function(e,n){return Object.hasOwn(t,n)?t[n]:e})),e}function Hy(e,t,n=`-`,r,i){let a=``;(e<0||i&&e<=0)&&(i?e=-e+1:(e=-e,a=n));let o=String(e);for(;o.length0||s>-n)&&(s+=n),e===3)s===0&&n===-12&&(s=12);else if(e===6)return Uy(s,t);let c=Dy(o,vy.MinusSign);return Hy(s,t,c,r,i)}}function Gy(e,t){switch(e){case 0:return t.getFullYear();case 1:return t.getMonth();case 2:return t.getDate();case 3:return t.getHours();case 4:return t.getMinutes();case 5:return t.getSeconds();case 6:return t.getMilliseconds();case 7:return t.getDay();default:throw new ri(2301,!1)}}function Ky(e,t,n=hy.Format,r=!1){return function(i,a){return qy(i,a,e,t,n,r)}}function qy(e,t,n,r,i,a){switch(n){case 2:return Sy(t,i,r)[e.getMonth()];case 1:return xy(t,i,r)[e.getDay()];case 0:let n=e.getHours(),o=e.getMinutes();if(a){let e=ky(t),a=Ay(t,i,r),s=e.findIndex(e=>{if(Array.isArray(e)){let[t,r]=e,i=n>=t.hours&&o>=t.minutes,a=n0?Math.floor(i/60):Math.ceil(i/60);switch(e){case 0:return(i>=0?`+`:``)+Hy(o,2,a)+Hy(Math.abs(i%60),2,a);case 1:return`GMT`+(i>=0?`+`:``)+Hy(o,1,a);case 2:return`GMT`+(i>=0?`+`:``)+Hy(o,2,a)+`:`+Hy(Math.abs(i%60),2,a);case 3:return r===0?`Z`:(i>=0?`+`:``)+Hy(o,2,a)+`:`+Hy(Math.abs(i%60),2,a);default:throw new ri(2310,!1)}}}var Yy=0,Xy=4;function Zy(e){let t=zy(e,Yy,1).getDay();return zy(e,0,1+(t<=Xy?Xy:11)-t)}function Qy(e){let t=e.getDay(),n=t===0?-3:Xy-t;return zy(e.getFullYear(),e.getMonth(),e.getDate()+n)}function $y(e,t=!1){return function(n,r){let i;if(t){let e=new Date(n.getFullYear(),n.getMonth(),1).getDay()-1,t=n.getDate();i=1+Math.floor((t+e)/7)}else{let e=Qy(n),t=Zy(e.getFullYear()),r=e.getTime()-t.getTime();i=1+Math.round(r/6048e5)}return Hy(i,e,Dy(r,vy.MinusSign))}}function eb(e,t=!1){return function(n,r){return Hy(Qy(n).getFullYear(),e,Dy(r,vy.MinusSign),t)}}var tb=Object.create(null);function nb(e){if(tb[e])return tb[e];let t;switch(e){case`G`:case`GG`:case`GGG`:t=Ky(3,gy.Abbreviated);break;case`GGGG`:t=Ky(3,gy.Wide);break;case`GGGGG`:t=Ky(3,gy.Narrow);break;case`y`:t=Wy(0,1,0,!1,!0);break;case`yy`:t=Wy(0,2,0,!0,!0);break;case`yyy`:t=Wy(0,3,0,!1,!0);break;case`yyyy`:t=Wy(0,4,0,!1,!0);break;case`Y`:t=eb(1);break;case`YY`:t=eb(2,!0);break;case`YYY`:t=eb(3);break;case`YYYY`:t=eb(4);break;case`M`:case`L`:t=Wy(1,1,1);break;case`MM`:case`LL`:t=Wy(1,2,1);break;case`MMM`:t=Ky(2,gy.Abbreviated);break;case`MMMM`:t=Ky(2,gy.Wide);break;case`MMMMM`:t=Ky(2,gy.Narrow);break;case`LLL`:t=Ky(2,gy.Abbreviated,hy.Standalone);break;case`LLLL`:t=Ky(2,gy.Wide,hy.Standalone);break;case`LLLLL`:t=Ky(2,gy.Narrow,hy.Standalone);break;case`w`:t=$y(1);break;case`ww`:t=$y(2);break;case`W`:t=$y(1,!0);break;case`d`:t=Wy(2,1);break;case`dd`:t=Wy(2,2);break;case`c`:case`cc`:t=Wy(7,1);break;case`ccc`:t=Ky(1,gy.Abbreviated,hy.Standalone);break;case`cccc`:t=Ky(1,gy.Wide,hy.Standalone);break;case`ccccc`:t=Ky(1,gy.Narrow,hy.Standalone);break;case`cccccc`:t=Ky(1,gy.Short,hy.Standalone);break;case`E`:case`EE`:case`EEE`:t=Ky(1,gy.Abbreviated);break;case`EEEE`:t=Ky(1,gy.Wide);break;case`EEEEE`:t=Ky(1,gy.Narrow);break;case`EEEEEE`:t=Ky(1,gy.Short);break;case`a`:case`aa`:case`aaa`:t=Ky(0,gy.Abbreviated);break;case`aaaa`:t=Ky(0,gy.Wide);break;case`aaaaa`:t=Ky(0,gy.Narrow);break;case`b`:case`bb`:case`bbb`:t=Ky(0,gy.Abbreviated,hy.Standalone,!0);break;case`bbbb`:t=Ky(0,gy.Wide,hy.Standalone,!0);break;case`bbbbb`:t=Ky(0,gy.Narrow,hy.Standalone,!0);break;case`B`:case`BB`:case`BBB`:t=Ky(0,gy.Abbreviated,hy.Format,!0);break;case`BBBB`:t=Ky(0,gy.Wide,hy.Format,!0);break;case`BBBBB`:t=Ky(0,gy.Narrow,hy.Format,!0);break;case`h`:t=Wy(3,1,-12);break;case`hh`:t=Wy(3,2,-12);break;case`H`:t=Wy(3,1);break;case`HH`:t=Wy(3,2);break;case`m`:t=Wy(4,1);break;case`mm`:t=Wy(4,2);break;case`s`:t=Wy(5,1);break;case`ss`:t=Wy(5,2);break;case`S`:t=Wy(6,1);break;case`SS`:t=Wy(6,2);break;case`SSS`:t=Wy(6,3);break;case`Z`:case`ZZ`:case`ZZZ`:t=Jy(0);break;case`ZZZZZ`:t=Jy(3);break;case`O`:case`OO`:case`OOO`:case`z`:case`zz`:case`zzz`:t=Jy(1);break;case`OOOO`:case`ZZZZ`:case`zzzz`:t=Jy(2);break;default:return null}return tb[e]=t,t}function rb(e,t){e=e.replace(/:/g,``);let n=Date.parse(`Jan 01, 1970 00:00:00 `+e)/6e4;return isNaN(n)?t:n}function ib(e,t){return e=new Date(e.getTime()),e.setMinutes(e.getMinutes()+t),e}function ab(e,t,n){let r=e.getTimezoneOffset();return ib(e,-1*(rb(t,r)-r))}function ob(e){if(cb(e))return e;if(typeof e==`number`&&!isNaN(e))return new Date(e);if(typeof e==`string`){if(e=e.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(e)){let[t,n=1,r=1]=e.split(`-`).map(e=>+e);return zy(t,n-1,r)}let t=parseFloat(e);if(!isNaN(e-t))return new Date(t);let n;if(n=e.match(Ny))return sb(n)}let t=new Date(e);if(!cb(t))throw new ri(2311,!1);return t}function sb(e){let t=new Date(0),n=0,r=0,i=e[8]?t.setUTCFullYear:t.setFullYear,a=e[8]?t.setUTCHours:t.setHours;e[9]&&(n=Number(e[9]+e[10]),r=Number(e[9]+e[11])),i.call(t,Number(e[1]),Number(e[2])-1,Number(e[3]));let o=Number(e[4]||0)-n,s=Number(e[5]||0)-r,c=Number(e[6]||0),l=Math.floor(parseFloat(`0.`+(e[7]||0))*1e3);return a.call(t,o,s,c,l),t}function cb(e){return e instanceof Date&&!isNaN(e.valueOf())}var lb=(()=>{class e{_viewContainerRef;_viewRef=null;ngTemplateOutletContext=null;ngTemplateOutlet=null;ngTemplateOutletInjector=null;injector=w(ws);constructor(e){this._viewContainerRef=e}ngOnChanges(e){if(this._shouldRecreateView(e)){let e=this._viewContainerRef;if(this._viewRef&&e.remove(e.indexOf(this._viewRef)),!this.ngTemplateOutlet){this._viewRef=null;return}let t=this._createContextForwardProxy();this._viewRef=e.createEmbeddedView(this.ngTemplateOutlet,t,{injector:this._getInjector()})}}_getInjector(){return this.ngTemplateOutletInjector===`outlet`?this.injector:this.ngTemplateOutletInjector??void 0}_shouldRecreateView(e){return!!e.ngTemplateOutlet||!!e.ngTemplateOutletInjector}_createContextForwardProxy(){return new Proxy({},{set:(e,t,n)=>this.ngTemplateOutletContext?Reflect.set(this.ngTemplateOutletContext,t,n):!1,get:(e,t,n)=>{if(this.ngTemplateOutletContext)return Reflect.get(this.ngTemplateOutletContext,t,n)}})}static ɵfac=function(t){return new(t||e)(Em(oh))};static ɵdir=Xh({type:e,selectors:[[``,`ngTemplateOutlet`,``]],inputs:{ngTemplateOutletContext:`ngTemplateOutletContext`,ngTemplateOutlet:`ngTemplateOutlet`,ngTemplateOutletInjector:`ngTemplateOutletInjector`},features:[kc]})}return e})();function ub(e,t){return new ri(2100,!1)}var db=`mediumDate`,fb=new bi(``),pb=new bi(``),mb=(()=>{class e{locale;defaultTimezone;defaultOptions;constructor(e,t,n){this.locale=e,this.defaultTimezone=t,this.defaultOptions=n}transform(t,n,r,i){if(t==null||t===``||t!==t)return null;try{let e=n??this.defaultOptions?.dateFormat??db,a=r??this.defaultOptions?.timezone??this.defaultTimezone??void 0;return Ly(t,e,i||this.locale,a)}catch(t){throw ub(e,t.message)}}static ɵfac=function(t){return new(t||e)(Em(Av,16),Em(fb,24),Em(pb,24))};static ɵpipe=Zh({name:`date`,type:e,pure:!0})}return e})(),hb=(()=>{class e{transform(e){return JSON.stringify(e,null,2)}static ɵfac=function(t){return new(t||e)};static ɵpipe=Zh({name:`json`,type:e,pure:!1})}return e})();function gb(e,t){t=encodeURIComponent(t);for(let n of e.split(`;`)){let e=n.indexOf(`=`),[r,i]=e==-1?[n,``]:[n.slice(0,e),n.slice(e+1)];if(r.trim()!==t)continue;let a=i;try{a=decodeURIComponent(i)}catch{}return a.length>1&&a[0]===`"`&&a[a.length-1]===`"`&&(a=a.slice(1,-1)),a}return null}var _b=`browser`,vb=class{_doc;constructor(e){this._doc=e}manager},yb=(()=>{class e extends vb{constructor(e){super(e)}supports(e){return!0}addEventListener(e,t,n,r){return e.addEventListener(t,n,r),()=>this.removeEventListener(e,t,n,r)}removeEventListener(e,t,n,r){return e.removeEventListener(t,n,r)}static ɵfac=function(t){return new(t||e)(Yi(Ts))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})(),bb=new bi(``),xb=(()=>{class e{_zone;_plugins;_eventNameToPlugin=new Map;constructor(e,t){this._zone=t,e.forEach(e=>{e.manager=this});let n=e.filter(e=>!(e instanceof yb));this._plugins=n.slice().reverse();let r=e.find(e=>e instanceof yb);r&&this._plugins.push(r)}addEventListener(e,t,n,r){return this._findPluginFor(t).addEventListener(e,t,n,r)}getZone(){return this._zone}_findPluginFor(e){let t=this._eventNameToPlugin.get(e);if(t)return t;if(t=this._plugins.find(t=>t.supports(e)),!t)throw new ri(-5101,!1);return this._eventNameToPlugin.set(e,t),t}static ɵfac=function(t){return new(t||e)(Yi(bb),Yi(Rs))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})(),Sb=`ng-app-id`;function Cb(e){for(let t of e)t.remove()}function wb(e,t){let n=t.createElement(`style`);return n.textContent=e,n}function Tb(e,t,n,r){let i=e.head?.querySelectorAll(`style[${Sb}="${t}"],link[${Sb}="${t}"]`);if(!i||i.length===0)return!1;for(let e of i)e.removeAttribute(Sb),e instanceof HTMLLinkElement?r.set(e.href.slice(e.href.lastIndexOf(`/`)+1),{usage:0,elements:[e]}):e.textContent&&n.set(e.textContent,{usage:0,elements:[e]});return!0}function Eb(e,t){let n=t.createElement(`link`);return n.setAttribute(`rel`,`stylesheet`),n.setAttribute(`href`,e),n}var Db=(()=>{class e{doc;appId;nonce;inline=new Map;external=new Map;hosts=new Set;constructor(e,t,n,r={}){this.doc=e,this.appId=t,this.nonce=n,Tb(e,t,this.inline,this.external)&&this.hosts.add(e.head)}addStyles(e,t){for(let t of e)this.addUsage(t,this.inline,wb);t?.forEach(e=>this.addUsage(e,this.external,Eb))}removeStyles(e,t){for(let t of e)this.removeUsage(t,this.inline);t?.forEach(e=>this.removeUsage(e,this.external))}addUsage(e,t,n){let r=t.get(e);r?r.usage++:t.set(e,{usage:1,elements:[...this.hosts].map(t=>this.addElement(t,n(e,this.doc)))})}removeUsage(e,t){let n=t.get(e);n&&(n.usage--,n.usage<=0&&(Cb(n.elements),t.delete(e)))}ngOnDestroy(){for(let[,{elements:e}]of[...this.inline,...this.external])Cb(e);this.hosts.clear()}addHost(e){if(!this.hosts.has(e)){this.hosts.add(e);for(let[t,{elements:n}]of this.inline)n.push(this.addElement(e,wb(t,this.doc)));for(let[t,{elements:n}]of this.external)n.push(this.addElement(e,Eb(t,this.doc)))}}removeHost(e){this.hosts.delete(e);for(let t of[...this.inline.values(),...this.external.values()]){let n=[];for(let r of t.elements)r.parentNode===e?r.remove():n.push(r);t.elements=n}}addElement(e,t){return this.nonce&&t.setAttribute(`nonce`,this.nonce),e.appendChild(t)}static ɵfac=function(t){return new(t||e)(Yi(Ts),Yi(ec),Yi(ic,8),Yi(rc))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})(),Ob={svg:`http://www.w3.org/2000/svg`,xhtml:`http://www.w3.org/1999/xhtml`,xlink:`http://www.w3.org/1999/xlink`,xml:`http://www.w3.org/XML/1998/namespace`,xmlns:`http://www.w3.org/2000/xmlns/`,math:`http://www.w3.org/1998/Math/MathML`},kb=/%COMP%/g,Ab=`%COMP%`,jb=`_nghost-${Ab}`,Mb=`_ngcontent-${Ab}`,Nb=!0,Pb=new bi(``,{factory:()=>Nb}),Fb=new bi(``);function Ib(e){return Mb.replace(kb,e)}function Lb(e){return jb.replace(kb,e)}function Rb(e,t){return t.map(t=>t.replace(kb,e))}var zb=(()=>{class e{eventManager;sharedStylesHost;appId;removeStylesOnCompDestroy;doc;ngZone;nonce;tracingService;rendererByCompId=new Map;defaultRenderer;cssVarNamespace;constructor(e,t,n,r,i,a,o=null,s=null,c=null){this.eventManager=e,this.sharedStylesHost=t,this.appId=n,this.removeStylesOnCompDestroy=r,this.doc=i,this.ngZone=a,this.nonce=o,this.tracingService=s,this.cssVarNamespace=c??``,this.defaultRenderer=new Bb(e,i,a,this.tracingService,this.cssVarNamespace)}createRenderer(e,t){if(!e||!t)return this.defaultRenderer;let n=this.getOrCreateRenderer(e,t);return n instanceof Wb?n.applyToHost(e):n instanceof Ub&&n.applyStyles(),n}getOrCreateRenderer(e,t){let n=this.rendererByCompId,r=n.get(t.id);if(!r){let i=this.doc,a=this.ngZone,o=this.eventManager,s=this.sharedStylesHost,c=this.removeStylesOnCompDestroy,l=this.tracingService;switch(t.encapsulation){case uu.Emulated:r=new Wb(o,s,t,this.appId,c,i,a,l,this.cssVarNamespace);break;case uu.ShadowDom:return new Hb(o,e,t,i,a,this.nonce,l,this.cssVarNamespace,s);case uu.ExperimentalIsolatedShadowDom:return new Hb(o,e,t,i,a,this.nonce,l,this.cssVarNamespace);default:r=new Ub(o,s,t,c,i,a,l,this.cssVarNamespace)}n.set(t.id,r)}return r}ngOnDestroy(){this.rendererByCompId.clear()}componentReplaced(e){this.rendererByCompId.delete(e)}static ɵfac=function(t){return new(t||e)(Yi(xb),Yi(wm),Yi(ec),Yi(Pb),Yi(Ts),Yi(Rs),Yi(ic),Yi(Pd,8),Yi(Fb,8))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})(),Bb=class{eventManager;doc;ngZone;tracingService;cssVarNamespace;data=Object.create(null);throwOnSyntheticProps=!0;constructor(e,t,n,r,i=``){this.eventManager=e,this.doc=t,this.ngZone=n,this.tracingService=r,this.cssVarNamespace=i}destroy(){}destroyNode=null;createElement(e,t){return t?this.doc.createElementNS(Ob[t]||t,e):this.doc.createElement(e)}createComment(e){return this.doc.createComment(e)}createText(e){return this.doc.createTextNode(e)}appendChild(e,t){(Vb(e)?e.content:e).appendChild(t)}insertBefore(e,t,n){if(e){let r=Vb(e)?e.content:e;if(n!=null&&n.parentNode!==r)throw new ri(-5106,!1);r.insertBefore(t,n)}}removeChild(e,t){t.remove()}selectRootElement(e,t){let n=typeof e==`string`?this.doc.querySelector(e):e;if(!n)throw new ri(-5104,!1);return t||(n.textContent=``),n}parentNode(e){return e.parentNode}nextSibling(e){return e.nextSibling}setAttribute(e,t,n,r){if(r){t=r+`:`+t;let i=Ob[r];i?e.setAttributeNS(i,t,n):e.setAttribute(t,n)}else e.setAttribute(t,n)}removeAttribute(e,t,n){if(n){let r=Ob[n];r?e.removeAttributeNS(r,t):e.removeAttribute(`${n}:${t}`)}else e.removeAttribute(t)}addClass(e,t){e.classList.add(t)}removeClass(e,t){e.classList.remove(t)}setStyle(e,t,n,r){let i=t.startsWith(`--`);i&&(t=t.replace(`%NS%`,this.cssVarNamespace)),i||r&(ed.DashCase|ed.Important)?e.style.setProperty(t,n,r&ed.Important?`important`:``):e.style[t]=n}removeStyle(e,t,n){let r=t.startsWith(`--`);r&&(t=t.replace(`%NS%`,this.cssVarNamespace)),r||n&ed.DashCase?e.style.removeProperty(t):e.style[t]=``}setProperty(e,t,n){e!=null&&(e[t]=n)}setValue(e,t){e.nodeValue=t}listen(e,t,n,r){if(typeof e==`string`&&(e=fy().getGlobalEventTarget(this.doc,e),!e))throw new ri(-5102,!1);let i=this.decoratePreventDefault(n);return this.tracingService?.wrapEventListener&&(i=this.tracingService.wrapEventListener(e,t,i)),this.eventManager.addEventListener(e,t,i,r)}decoratePreventDefault(e){return t=>{if(t===`__ngUnwrap__`)return e;e(t)===!1&&t.preventDefault()}}};function Vb(e){return e.tagName===`TEMPLATE`&&e.content!==void 0}var Hb=class extends Bb{hostEl;sharedStylesHost;shadowRoot;constructor(e,t,n,r,i,a,o,s,c){super(e,r,i,o,s),this.hostEl=t,this.sharedStylesHost=c,this.shadowRoot=t.attachShadow({mode:`open`}),this.sharedStylesHost&&this.sharedStylesHost.addHost(this.shadowRoot);let l=n.styles;l=Rb(n.id,l).map(e=>e.replace(/%NS%/g,s));for(let e of l){let t=document.createElement(`style`);a&&t.setAttribute(`nonce`,a),t.textContent=e,this.shadowRoot.appendChild(t)}let u=n.getExternalStyles?.();if(u)for(let e of u){let t=Eb(e,r);a&&t.setAttribute(`nonce`,a),this.shadowRoot.appendChild(t)}}nodeOrShadowRoot(e){return e===this.hostEl?this.shadowRoot:e}appendChild(e,t){return super.appendChild(this.nodeOrShadowRoot(e),t)}insertBefore(e,t,n){return super.insertBefore(this.nodeOrShadowRoot(e),t,n)}removeChild(e,t){return super.removeChild(null,t)}parentNode(e){return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(e)))}destroy(){this.sharedStylesHost&&this.sharedStylesHost.removeHost(this.shadowRoot)}},Ub=class extends Bb{sharedStylesHost;removeStylesOnCompDestroy;styles;styleUrls;constructor(e,t,n,r,i,a,o,s,c){super(e,i,a,o,s),this.sharedStylesHost=t,this.removeStylesOnCompDestroy=r;let l=n.styles,u=c?Rb(c,l):l;this.styles=u.map(e=>e.replace(/%NS%/g,s)),this.styleUrls=n.getExternalStyles?.(c)}applyStyles(){this.sharedStylesHost.addStyles(this.styles,this.styleUrls)}destroy(){this.removeStylesOnCompDestroy&&md.size===0&&this.sharedStylesHost.removeStyles(this.styles,this.styleUrls)}},Wb=class extends Ub{contentAttr;hostAttr;constructor(e,t,n,r,i,a,o,s,c){let l=r+`-`+n.id;super(e,t,n,i,a,o,s,c,l),this.contentAttr=Ib(l),this.hostAttr=Lb(l)}applyToHost(e){this.applyStyles(),this.setAttribute(e,this.hostAttr,``)}createElement(e,t){let n=super.createElement(e,t);return super.setAttribute(n,this.contentAttr,``),n}},Gb=class e extends my{supportsDOMEvents=!0;static makeCurrent(){py(new e)}onAndCancel(e,t,n,r){return e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}}dispatchEvent(e,t){e.dispatchEvent(t)}remove(e){e.remove()}createElement(e,t){return t||=this.getDefaultDocument(),t.createElement(e)}createHtmlDocument(){return document.implementation.createHTMLDocument(`fakeTitle`)}getDefaultDocument(){return document}isElementNode(e){return e.nodeType===Node.ELEMENT_NODE}isShadowRoot(e){return e instanceof DocumentFragment}getGlobalEventTarget(e,t){return t===`window`?window:t===`document`?e:t===`body`?e.body:null}getBaseHref(e){let t=qb();return t==null?null:Jb(t)}resetBaseElement(){Kb=null}getUserAgent(){return window.navigator.userAgent}getCookie(e){return gb(document.cookie,e)}},Kb=null;function qb(){return Kb||=document.head.querySelector(`base`),Kb?Kb.getAttribute(`href`):null}function Jb(e){return new URL(e,document.baseURI).pathname}var Yb=[`alt`,`control`,`meta`,`shift`],Xb={"\b":`Backspace`," ":`Tab`,"":`Delete`,"\x1B":`Escape`,Del:`Delete`,Esc:`Escape`,Left:`ArrowLeft`,Right:`ArrowRight`,Up:`ArrowUp`,Down:`ArrowDown`,Menu:`ContextMenu`,Scroll:`ScrollLock`,Win:`OS`},Zb={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey},Qb=(()=>{class e extends vb{constructor(e){super(e)}supports(t){return e.parseEventName(t)!=null}addEventListener(t,n,r,i){let a=e.parseEventName(n),o=e.eventCallback(a.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>fy().onAndCancel(t,a.domEventName,o,i))}static parseEventName(t){let n=t.toLowerCase().split(`.`),r=n.shift();if(n.length===0||r!==`keydown`&&r!==`keyup`)return null;let i=e._normalizeKey(n.pop()),a=``,o=n.indexOf(`code`);if(o>-1&&(n.splice(o,1),a=`code.`),Yb.forEach(e=>{let t=n.indexOf(e);t>-1&&(n.splice(t,1),a+=e+`.`)}),a+=i,n.length!=0||i.length===0)return null;let s={};return s.domEventName=r,s.fullKey=a,s}static matchEventFullKeyCode(e,t){let n=Xb[e.key]||e.key,r=``;return t.indexOf(`code.`)>-1&&(n=e.code,r=`code.`),n==null||!n?!1:(n=n.toLowerCase(),n===` `?n=`space`:n===`.`&&(n=`dot`),Yb.forEach(t=>{if(t!==n){let n=Zb[t];n(e)&&(r+=t+`.`)}}),r+=n,r===t)}static eventCallback(t,n,r){return i=>{e.matchEventFullKeyCode(i,t)&&r.runGuarded(()=>n(i))}}static _normalizeKey(e){return e===`esc`?`escape`:e}static ɵfac=function(t){return new(t||e)(Yi(Ts))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})();async function $b(e,t,n){return ay({rootComponent:e,...ex(t,n)})}function ex(e,t){return{platformRef:t?.platformRef,appProviders:[...ax,...e?.providers??[]],platformProviders:ix}}function tx(){Gb.makeCurrent()}function nx(){return new Xs}function rx(){return Ql(document),document}var ix=[{provide:rc,useValue:_b},{provide:nc,useValue:tx,multi:!0},{provide:Ts,useFactory:rx}],ax=[{provide:Oa,useValue:`root`},{provide:Xs,useFactory:nx},{provide:bb,useClass:yb,multi:!0},{provide:bb,useClass:Qb,multi:!0},zb,{provide:wm,useClass:Db},{provide:Db,useExisting:wm},xb,{provide:am,useExisting:zb},[]];function ox(e,t){let n=`\x1B[${e}m`,r=`\x1B[${t}m`;return((e,...t)=>{if(Array.isArray(e)&&`raw`in e){let i=e,a=``;for(let e=0;e{let r=new ux({code:i,why:cx(a.why,e),fix:cx(a.fix,e),docs:o,cause:e.cause,sources:e.sources,data:cx(a.data,e)},s);for(let e of t)e(r,n);return r};n[i]=s}return n}function px(e){return t=>{let n=`${e.bold(e.red(`[${t.name}]`))} ${t.message}`,r=[];return t.fix&&r.push(`${e.dim(`fix:`)} ${t.fix}`),t.sources?.length&&r.push(`${e.dim(`sources:`)} ${t.sources.join(`, `)}`),t.docs&&r.push(`${e.dim(`see:`)} ${e.cyan(t.docs)}`),r.length===0?n:[n,...r.map((t,n)=>`${e.dim(n{e=n,t=r}),resolve:e,reject:t}}var yx=Math.random.bind(Math),bx=`useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict`;function xx(e=21){let t=``,n=e;for(;n--;)t+=bx[yx()*64|0];return t}var Sx=6e4,Cx=e=>e,wx=Cx,{clearTimeout:Tx,setTimeout:Ex}=globalThis;function Dx(e,t){let{post:n,on:r,off:i=()=>{},eventNames:a=[],serialize:o=Cx,deserialize:s=wx,resolver:c,bind:l=`rpc`,timeout:u=Sx,proxify:d=!0}=t,f=!1,p=new Map,m,h;async function g(e,r,i,a){if(f)throw Error(`[birpc] rpc is closed, cannot call "${e}"`);let s={m:e,a:r,t:`q`};a&&(s.o=!0);let c=async e=>n(o(e));if(i){await c(s);return}if(m)try{await m}finally{m=void 0}let{promise:l,resolve:d,reject:g}=vx(),_=xx();s.i=_;let ee;async function te(n=s){return u>=0&&(ee=Ex(()=>{try{if(t.onTimeoutError?.call(h,e,r)!==!0)throw Error(`[birpc] timeout on calling "${e}"`)}catch(e){g(e)}p.delete(_)},u),typeof ee==`object`&&(ee=ee.unref?.())),p.set(_,{resolve:d,reject:g,timeoutId:ee,method:e}),await c(n),l}try{t.onRequest?await t.onRequest.call(h,s,te,d):await te()}catch(e){if(t.onGeneralError?.call(h,e)!==!0)throw e;return}finally{Tx(ee),p.delete(_)}return l}let _={$call:(e,...t)=>g(e,t,!1),$callOptional:(e,...t)=>g(e,t,!1,!0),$callEvent:(e,...t)=>g(e,t,!0),$callRaw:e=>g(e.method,e.args,e.event,e.optional),$rejectPendingCalls:te,get $closed(){return f},get $meta(){return t.meta},$close:ee,$functions:e};h=d?new Proxy({},{get(t,n){if(Object.hasOwn(_,n))return _[n];if(n===`then`&&!a.includes(`then`)&&!(`then`in e))return;let r=(...e)=>g(n,e,!0);if(a.includes(n))return r.asEvent=r,r;let i=(...e)=>g(n,e,!1);return i.asEvent=r,i}}):_;function ee(e){f=!0,p.forEach(({reject:t,method:n})=>{let r=Error(`[birpc] rpc is closed, cannot call "${n}"`);if(e)return e.cause??=r,t(e);t(r)}),p.clear(),i(ne)}function te(e){let t=Array.from(p.values()).map(({method:t,reject:n})=>e?e({method:t,reject:n}):n(Error(`[birpc]: rejected pending call "${t}".`)));return p.clear(),t}async function ne(r,...i){let a;try{a=s(r)}catch(e){if(t.onGeneralError?.call(h,e)!==!0)throw e;return}if(a.t===`q`){let{m:r,a:s,o:u}=a,d,f,p=await(c?c.call(h,r,e[r]):e[r]);if(u&&(p||=()=>void 0),!p)f=Error(`[birpc] function "${r}" not found`);else try{d=await p.apply(l===`rpc`?h:e,s)}catch(e){f=e}if(a.i){if(f&&t.onFunctionError&&t.onFunctionError.call(h,f,r,s)===!0)return;if(!f)try{await n(o({t:`s`,i:a.i,r:d}),...i);return}catch(e){if(f=e,t.onGeneralError?.call(h,e,r,s)!==!0)throw e}try{await n(o({t:`s`,i:a.i,e:f}),...i)}catch(e){if(t.onGeneralError?.call(h,e,r,s)!==!0)throw e}}}else{let{i:e,r:t,e:n}=a,r=p.get(e);r&&(Tx(r.timeoutId),n?r.reject(n):r.resolve(t)),p.delete(e)}}return m=r(ne),h}function Ox(e,t){return t.safety?t.safety:e===`static`||e===`query`||e==null?`read`:`action`}var kx=Object.freeze({type:`object`,additionalProperties:!0});function Ax(e){let t=e[`~standard`];if(t.jsonSchema)try{return t.jsonSchema.input({target:`draft-2020-12`})}catch{return kx}return kx}function jx(e){if(!e||e.length===0)return{type:`object`,properties:{}};let t={},n=[];for(let r=0;rn[`arg${t}`]);if(`arg0`in n){let e=[];for(;`arg${e.length}`in n;)e.push(n[`arg${e.length}`]);return e}return Object.keys(n).length===0?[]:void 0}function Nx(e,t){return Mx(e,t)??[e]}function Px(e){return typeof e==`string`?`'${e}'`:new Rx().serialize(e)}var Fx=` _-,;:!?.'"()[]{}@*/\\&#%\`^+<=>|~$0123456789abcdefghijklmnopqrstuvwxyz`,Ix=(function(){let e=new Uint8Array(128);for(let t=0;t<69;t++)e[Fx.charCodeAt(t)]=t+1;for(let t=65;t<=90;t++)e[t]=e[t+32];return e})();function Lx(e,t){if(e===t)return 0;let n=Math.min(e.length,t.length),r=0;for(let i=0;ia?-1:1)}return e.length===t.length?r:e.lengththis.compare(e[0],t[0])),r=`${e}{`;for(let e=0;ethis.compare(e,t)))}`}$Map(e){return this.serializeObjectEntries(`Map`,e.entries())}}for(let t of[`Error`,`RegExp`,`URL`])e.prototype[`$`+t]=function(e){return`${t}(${e})`};for(let t of[`Int8Array`,`Uint8Array`,`Uint8ClampedArray`,`Int16Array`,`Uint16Array`,`Int32Array`,`Uint32Array`,`Float32Array`,`Float64Array`])e.prototype[`$`+t]=function(e){return`${t}[${e.join(`,`)}]`};for(let t of[`BigInt64Array`,`BigUint64Array`])e.prototype[`$`+t]=function(e){return`${t}[${e.join(`n,`)}${e.length>0?`n`:``}]`};return e})(),zx=[1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225],Bx=[1116352408,1899447441,-1245643825,-373957723,961987163,1508970993,-1841331548,-1424204075,-670586216,310598401,607225278,1426881987,1925078388,-2132889090,-1680079193,-1046744716,-459576895,-272742522,264347078,604807628,770255983,1249150122,1555081692,1996064986,-1740746414,-1473132947,-1341970488,-1084653625,-958395405,-710438585,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,-2117940946,-1838011259,-1564481375,-1474664885,-1035236496,-949202525,-778901479,-694614492,-200395387,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,-2067236844,-1933114872,-1866530822,-1538233109,-1090935817,-965641998],Vx=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`,Hx=[],Ux=class{_data=new Wx;_hash=new Wx([...zx]);_nDataBytes=0;_minBufferSize=0;finalize(e){e&&this._append(e);let t=this._nDataBytes*8,n=this._data.sigBytes*8;return this._data.words[n>>>5]|=128<<24-n%32,this._data.words[(n+64>>>9<<4)+14]=Math.floor(t/4294967296),this._data.words[(n+64>>>9<<4)+15]=t,this._data.sigBytes=this._data.words.length*4,this._process(),this._hash}_doProcessBlock(e,t){let n=this._hash.words,r=n[0],i=n[1],a=n[2],o=n[3],s=n[4],c=n[5],l=n[6],u=n[7];for(let n=0;n<64;n++){if(n<16)Hx[n]=e[t+n]|0;else{let e=Hx[n-15],t=(e<<25|e>>>7)^(e<<14|e>>>18)^e>>>3,r=Hx[n-2],i=(r<<15|r>>>17)^(r<<13|r>>>19)^r>>>10;Hx[n]=t+Hx[n-7]+i+Hx[n-16]}let d=s&c^~s&l,f=r&i^r&a^i&a,p=(r<<30|r>>>2)^(r<<19|r>>>13)^(r<<10|r>>>22),m=(s<<26|s>>>6)^(s<<21|s>>>11)^(s<<7|s>>>25),h=u+m+d+Bx[n]+Hx[n],g=p+f;u=l,l=c,c=s,s=o+h|0,o=a,a=i,i=r,r=h+g|0}n[0]=n[0]+r|0,n[1]=n[1]+i|0,n[2]=n[2]+a|0,n[3]=n[3]+o|0,n[4]=n[4]+s|0,n[5]=n[5]+c|0,n[6]=n[6]+l|0,n[7]=n[7]+u|0}_append(e){typeof e==`string`&&(e=Wx.fromUtf8(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes}_process(e){let t,n=this._data.sigBytes/64;n=e?Math.ceil(n):Math.max((n|0)-this._minBufferSize,0);let r=n*16,i=Math.min(r*4,this._data.sigBytes);if(r){for(let e=0;e>>2]|=(n.charCodeAt(e)&255)<<24-e%4*8;return new e(i,r)}toBase64(){let e=[];for(let t=0;t>>2]>>>24-t%4*8&255,r=this.words[t+1>>>2]>>>24-(t+1)%4*8&255,i=this.words[t+2>>>2]>>>24-(t+2)%4*8&255,a=n<<16|r<<8|i;for(let n=0;n<4&&t*8+n*6>>6*(3-n)&63))}return e.join(``)}concat(e){if(this.words[this.sigBytes>>>2]&=4294967295<<32-this.sigBytes%4*8,this.words.length=Math.ceil(this.sigBytes/4),this.sigBytes%4)for(let t=0;t>>2]>>>24-t%4*8&255;this.words[this.sigBytes+t>>>2]|=n<<24-(this.sigBytes+t)%4*8}else for(let t=0;t>>2]=e.words[t>>>2];this.sigBytes+=e.sigBytes}};function Gx(e){return new Ux().finalize(e).toBase64()}function Kx(e){return Gx(Px(e))}function qx(e){return Kx(e)}function Jx(){let e={};function t(t,...n){let r=e[t]||[];for(let e=0,t=r.length;e{e[t]=e[t]?.filter(e=>n!==e)}}function i(e,t){let n=r(e,((...e)=>(n(),t(...e))));return n}return{_listeners:e,emit:t,emitOnce:n,on:r,once:i}}var Yx=/^[\w+.-]{2,}:\/\//;function Xx(e){return e.endsWith(`/`)?e:`${e}/`}function Zx(e){return(e.endsWith(`/`)?e.slice(0,-1):e)||`/`}function Qx(e,...t){let n=e;for(let e of t)e&&e!==`/`&&(n=n?Xx(n)+e.replace(/^\.?\//,``):e);return n}function $x(e,t){if(!t||t===`/`||Yx.test(e))return e;let n=Zx(t);return e.startsWith(n)?e:Qx(n,e)}function eS(e,t){let n=e.match(Yx);return t+(n?e.slice(n[0].length):e)}var tS=`useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict`;function nS(e=21){let t=``,n=e;for(;n--;)t+=tS[Math.random()*64|0];return t}var rS=Symbol.for(`immer-nothing`),iS=Symbol.for(`immer-draftable`),aS=Symbol.for(`immer-state`),oS=[function(e){return`The plugin for '${e}' has not been loaded into Immer. To enable the plugin, import and call \`enable${e}()\` when initializing your application.`},function(e){return`produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${e}'`},`This object has been frozen and should not be mutated`,function(e){return`Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? `+e},`An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.`,`Immer forbids circular references`,"The first or second argument to `produce` must be a function","The third argument to `produce` must be a function or undefined","First argument to `createDraft` must be a plain object, an array, or an immerable object","First argument to `finishDraft` must be a draft returned by `createDraft`",function(e){return`'current' expects a draft, got: ${e}`},`Object.defineProperty() cannot be used on an Immer draft`,`Object.setPrototypeOf() cannot be used on an Immer draft`,`Immer only supports deleting array indices`,`Immer only supports setting array indices and the 'length' property`,function(e){return`'original' expects a draft, got: ${e}`}];function sS(e,...t){{let n=oS[e],r=jS(n)?n.apply(null,t):n;throw Error(`[Immer] ${r}`)}}var cS=Object,lS=cS.getPrototypeOf,uS=`constructor`,dS=`prototype`,fS=`configurable`,pS=`enumerable`,mS=`writable`,hS=`value`,gS=e=>!!e&&!!e[aS];function _S(e){return e?bS(e)||DS(e)||!!e[iS]||!!e[uS]?.[iS]||OS(e)||kS(e):!1}var vS=cS[dS][uS].toString(),yS=new WeakMap;function bS(e){if(!e||!AS(e))return!1;let t=lS(e);if(t===null||t===cS[dS])return!0;let n=cS.hasOwnProperty.call(t,uS)&&t[uS];if(n===Object)return!0;if(!jS(n))return!1;let r=yS.get(n);return r===void 0&&(r=Function.toString.call(n),yS.set(n,r)),r===vS}function xS(e,t,n=!0){SS(e)===0?(n?Reflect.ownKeys(e):cS.keys(e)).forEach(n=>{t(n,e[n],e)}):e.forEach((n,r)=>t(r,n,e))}function SS(e){let t=e[aS];return t?t.type_:DS(e)?1:OS(e)?2:kS(e)?3:0}var CS=(e,t,n=SS(e))=>n===2?e.has(t):cS[dS].hasOwnProperty.call(e,t),wS=(e,t,n=SS(e))=>n===2?e.get(t):e[t],TS=(e,t,n,r=SS(e))=>{r===2?e.set(t,n):r===3?e.add(n):e[t]=n};function ES(e,t){return e===t?e!==0||1/e==1/t:e!==e&&t!==t}var DS=Array.isArray,OS=e=>e instanceof Map,kS=e=>e instanceof Set,AS=e=>typeof e==`object`,jS=e=>typeof e==`function`,MS=e=>typeof e==`boolean`;function NS(e){let t=+e;return Number.isInteger(t)&&String(t)===e}var PS=e=>AS(e)?e?.[aS]:null,FS=e=>e.copy_||e.base_,IS=e=>e.modified_?e.copy_:e.base_;function LS(e,t){if(OS(e))return new Map(e);if(kS(e))return new Set(e);if(DS(e))return Array[dS].slice.call(e);let n=bS(e);if(t===!0||t===`class_only`&&!n){let t=cS.getOwnPropertyDescriptors(e);delete t[aS];let n=Reflect.ownKeys(t);for(let r=0;r1&&cS.defineProperties(e,{set:BS,add:BS,clear:BS,delete:BS}),cS.freeze(e),t&&xS(e,(e,t)=>{RS(t,!0)},!1),e)}function zS(){sS(2)}var BS={[hS]:zS};function VS(e){return e===null||!AS(e)||cS.isFrozen(e)}var HS=`MapSet`,US=`Patches`,WS=`ArrayMethods`,GS={};function KS(e){let t=GS[e];return t||sS(0,e),t}var qS=e=>!!GS[e];function JS(e,t){GS[e]||(GS[e]=t)}var YS,XS=()=>YS,ZS=(e,t)=>({drafts_:[],parent_:e,immer_:t,canAutoFreeze_:!0,unfinalizedDrafts_:0,handledSet_:new Set,processedForPatches_:new Set,mapSetPlugin_:qS(HS)?KS(HS):void 0,arrayMethodsPlugin_:qS(WS)?KS(WS):void 0});function QS(e,t){t&&(e.patchPlugin_=KS(US),e.patches_=[],e.inversePatches_=[],e.patchListener_=t)}function $S(e){eC(e),e.drafts_.forEach(nC),e.drafts_=null}function eC(e){e===YS&&(YS=e.parent_)}var tC=e=>YS=ZS(YS,e);function nC(e){let t=e[aS];t.type_===0||t.type_===1?t.revoke_():t.revoked_=!0}function rC(e,t){t.unfinalizedDrafts_=t.drafts_.length;let n=t.drafts_[0];if(e!==void 0&&e!==n){n[aS].modified_&&($S(t),sS(4)),_S(e)&&(e=iC(t,e));let{patchPlugin_:r}=t;r&&r.generateReplacementPatches_(n[aS].base_,e,t)}else e=iC(t,n);return aC(t,e,!0),$S(t),t.patches_&&t.patchListener_(t.patches_,t.inversePatches_),e===rS?void 0:e}function iC(e,t){if(VS(t))return t;let n=t[aS];if(!n)return pC(t,e.handledSet_,e);if(!sC(n,e))return t;if(!n.modified_)return n.base_;if(!n.finalized_){let{callbacks_:t}=n;if(t)for(;t.length>0;)t.pop()(e);dC(n,e)}return n.copy_}function aC(e,t,n=!1){!e.parent_&&e.immer_.autoFreeze_&&e.canAutoFreeze_&&RS(t,n)}function oC(e){e.finalized_=!0,e.scope_.unfinalizedDrafts_--}var sC=(e,t)=>e.scope_===t,cC=[];function lC(e,t,n,r){let i=FS(e),a=e.type_;if(r!==void 0&&wS(i,r,a)===t){TS(i,r,n,a);return}if(!e.draftLocations_){let t=e.draftLocations_=new Map;xS(i,(e,n)=>{if(gS(n)){let r=t.get(n)||[];r.push(e),t.set(n,r)}})}let o=e.draftLocations_.get(t)??cC;for(let e of o)TS(i,e,n,a)}function uC(e,t,n){e.callbacks_.push(function(r){let i=t;if(!i||!sC(i,r))return;r.mapSetPlugin_?.fixSetContents(i);let a=IS(i);lC(e,i.draft_??i,a,n),dC(i,r)})}function dC(e,t){if(e.modified_&&!e.finalized_&&(e.type_===3||e.type_===1&&e.allIndicesReassigned_||(e.assigned_?.size??0)>0)){let{patchPlugin_:n}=t;if(n){let r=n.getPath(e);r&&n.generatePatches_(e,r,t)}oC(e)}}function fC(e,t,n){let{scope_:r}=e;if(gS(n)){let i=n[aS];sC(i,r)&&i.callbacks_.push(function(){SC(e),lC(e,n,IS(i),t)})}else _S(n)&&e.callbacks_.push(function(){let i=FS(e);e.type_===3?i.has(n)&&pC(n,r.handledSet_,r):wS(i,t,e.type_)===n&&r.drafts_.length>1&&(e.assigned_.get(t)??!1)===!0&&e.copy_&&pC(wS(e.copy_,t,e.type_),r.handledSet_,r)})}function pC(e,t,n){return!n.immer_.autoFreeze_&&n.unfinalizedDrafts_<1||gS(e)||t.has(e)||!_S(e)||VS(e)?e:(t.add(e),xS(e,(r,i)=>{if(gS(i)){let t=i[aS];sC(t,n)&&(TS(e,r,IS(t),e.type_),oC(t))}else _S(i)&&pC(i,t,n)}),e)}function mC(e,t){let n=DS(e),r={type_:+!!n,scope_:t?t.scope_:XS(),modified_:!1,finalized_:!1,assigned_:void 0,parent_:t,base_:e,draft_:null,copy_:null,revoke_:null,isManual_:!1,callbacks_:void 0},i=r,a=hC;n&&(i=[r],a=gC);let{revoke:o,proxy:s}=Proxy.revocable(i,a);return r.draft_=s,r.revoke_=o,[s,r]}var hC={get(e,t){if(t===aS)return e;let n=e.scope_.arrayMethodsPlugin_,r=e.type_===1&&typeof t==`string`;if(r&&n?.isArrayOperationMethod(t))return n.createMethodInterceptor(e,t);let i=FS(e);if(!CS(i,t,e.type_))return yC(e,i,t);let a=i[t];if(e.finalized_||!_S(a)||r&&e.operationMethod&&n?.isMutatingArrayMethod(e.operationMethod)&&NS(t))return a;if(a===_C(e.base_,t)||vC(e,t,a)){SC(e);let n=e.type_===1?+t:t,r=wC(e.scope_,a,e,n);return e.copy_[n]=r}return a},has(e,t){return t in FS(e)},ownKeys(e){return Reflect.ownKeys(FS(e))},set(e,t,n){let r=bC(FS(e),t);if(r?.set)return r.set.call(e.draft_,n),!0;if(!e.modified_){let r=_C(FS(e),t),i=r?.[aS];if(i&&i.base_===n)return e.copy_[t]=n,e.assigned_.delete(t),!0;if(ES(n,r)&&(n!==void 0||CS(e.base_,t,e.type_)))return!0;SC(e),xC(e)}return e.copy_[t]===n&&(n!==void 0||CS(e.copy_,t,e.type_))||Number.isNaN(n)&&Number.isNaN(e.copy_[t])?!0:(e.copy_[t]=n,e.assigned_.set(t,!0),fC(e,t,n),!0)},deleteProperty(e,t){return SC(e),_C(e.base_,t)!==void 0||t in e.base_?(e.assigned_.set(t,!1),xC(e)):e.assigned_.delete(t),e.copy_&&delete e.copy_[t],!0},getOwnPropertyDescriptor(e,t){let n=FS(e),r=Reflect.getOwnPropertyDescriptor(n,t);return r&&{[mS]:!0,[fS]:e.type_!==1||t!==`length`,[pS]:r[pS],[hS]:n[t]}},defineProperty(){sS(11)},getPrototypeOf(e){return lS(e.base_)},setPrototypeOf(){sS(12)}},gC={};for(let e in hC){let t=hC[e];gC[e]=function(){let e=arguments;return e[0]=e[0][0],t.apply(this,e)}}gC.deleteProperty=function(e,t){return isNaN(parseInt(t))&&sS(13),gC.set.call(this,e,t,void 0)},gC.set=function(e,t,n){return t!==`length`&&isNaN(parseInt(t))&&sS(14),hC.set.call(this,e[0],t,n,e[0])};function _C(e,t){let n=e[aS];return(n?FS(n):e)[t]}function vC(e,t,n){return e.type_!==1||!e.allIndicesReassigned_||e.assigned_?.get(t)||!_S(n)||n[aS]?!1:e.baseRefs_.has(n)}function yC(e,t,n){let r=bC(t,n);return r?hS in r?r[hS]:r.get?.call(e.draft_):void 0}function bC(e,t){if(!(t in e))return;let n=lS(e);for(;n;){let e=Object.getOwnPropertyDescriptor(n,t);if(e)return e;n=lS(n)}}function xC(e){e.modified_||(e.modified_=!0,e.parent_&&xC(e.parent_))}function SC(e){e.copy_||=(e.assigned_=new Map,LS(e.base_,e.scope_.immer_.useStrictShallowCopy_))}var CC=class{constructor(e){this.autoFreeze_=!0,this.useStrictShallowCopy_=!1,this.useStrictIteration_=!1,this.produce=(e,t,n)=>{if(jS(e)&&!jS(t)){let n=t;t=e;let r=this;return function(e=n,...i){return r.produce(e,e=>t.call(this,e,...i))}}jS(t)||sS(6),n!==void 0&&!jS(n)&&sS(7);let r;if(_S(e)){let i=tC(this),a=wC(i,e,void 0),o=!0;try{r=t(a),o=!1}finally{o?$S(i):eC(i)}return QS(i,n),rC(r,i)}if(!e||!AS(e)){if(r=t(e),r===void 0&&(r=e),r===rS&&(r=void 0),this.autoFreeze_&&RS(r,!0),n){let t=[],i=[];KS(US).generateReplacementPatches_(e,r,{patches_:t,inversePatches_:i}),n(t,i)}return r}sS(1,e)},this.produceWithPatches=(e,t)=>{if(jS(e))return(t,...n)=>this.produceWithPatches(t,t=>e(t,...n));let n,r;return[this.produce(e,t,(e,t)=>{n=e,r=t}),n,r]},MS(e?.autoFreeze)&&this.setAutoFreeze(e.autoFreeze),MS(e?.useStrictShallowCopy)&&this.setUseStrictShallowCopy(e.useStrictShallowCopy),MS(e?.useStrictIteration)&&this.setUseStrictIteration(e.useStrictIteration)}createDraft(e){_S(e)||sS(8),gS(e)&&(e=TC(e));let t=tC(this),n=wC(t,e,void 0);return n[aS].isManual_=!0,eC(t),n}finishDraft(e,t){let n=e&&e[aS];(!n||!n.isManual_)&&sS(9);let{scope_:r}=n;return QS(r,t),rC(void 0,r)}setAutoFreeze(e){this.autoFreeze_=e}setUseStrictShallowCopy(e){this.useStrictShallowCopy_=e}setUseStrictIteration(e){this.useStrictIteration_=e}shouldUseStrictIteration(){return this.useStrictIteration_}applyPatches(e,t){let n;for(n=t.length-1;n>=0;n--){let r=t[n];if(r.path.length===0&&r.op===`replace`){e=r.value;break}}n>-1&&(t=t.slice(n+1));let r=KS(US).applyPatches_;return gS(e)?r(e,t):this.produce(e,e=>r(e,t))}};function wC(e,t,n,r){let[i,a]=OS(t)?KS(HS).proxyMap_(t,n):kS(t)?KS(HS).proxySet_(t,n):mC(t,n);return(n?.scope_??XS()).drafts_.push(i),a.callbacks_=n?.callbacks_??[],a.key_=r,n&&r!==void 0?uC(n,a,r):a.callbacks_.push(function(e){e.mapSetPlugin_?.fixSetContents(a);let{patchPlugin_:t}=e;a.modified_&&t&&t.generatePatches_(a,[],e)}),i}function TC(e){return gS(e)||sS(10,e),EC(e)}function EC(e){if(!_S(e)||VS(e))return e;let t=e[aS],n,r=!0;if(t){if(!t.modified_)return t.base_;t.finalized_=!0,n=LS(e,t.scope_.immer_.useStrictShallowCopy_),r=t.scope_.immer_.shouldUseStrictIteration()}else n=LS(e,!0);return xS(n,(e,t)=>{TS(n,e,EC(t))},r),t&&(t.finalized_=!1),n}function DC(){oS.push(`Sets cannot have "replace" patches.`,function(e){return`Unsupported patch operation: `+e},function(e){return`Cannot apply patch, path doesn't resolve: `+e},`Patching reserved attributes like __proto__, prototype and constructor is not allowed`);function e(n,r=[]){if(n.key_!==void 0){let e=n.parent_.copy_??n.parent_.base_,t=PS(wS(e,n.key_)),i=wS(e,n.key_);if(i===void 0||i!==n.draft_&&i!==n.base_&&i!==n.copy_||t!=null&&t.base_!==n.base_)return null;let a=n.parent_.type_===3,o;if(a){let e=n.parent_;o=Array.from(e.drafts_.keys()).indexOf(n.key_)}else o=n.key_;if(!(a&&e.size>o||CS(e,o)))return null;r.push(o)}if(n.parent_)return e(n.parent_,r);r.reverse();try{t(n.copy_,r)}catch{return null}return r}function t(e,t){let n=e;for(let e=0;e{let u=wS(o,e,c),f=wS(s,e,c),p=l?CS(o,e)?n:`add`:r;if(u===f&&p===n)return;let m=t.concat(e);i.push(p===r?{op:p,path:m}:{op:p,path:m,value:d(f)}),a.push(p===`add`?{op:r,path:m}:p===r?{op:`add`,path:m,value:d(u)}:{op:n,path:m,value:d(u)})})}function s(e,t,n,i){let{base_:a,copy_:o}=e,s=0;a.forEach(e=>{if(!o.has(e)){let a=t.concat([s]);n.push({op:r,path:a,value:e}),i.unshift({op:`add`,path:a,value:e})}s++}),s=0,o.forEach(e=>{if(!a.has(e)){let a=t.concat([s]);n.push({op:`add`,path:a,value:e}),i.unshift({op:r,path:a,value:e})}s++})}function c(e,t,r){let{patches_:i,inversePatches_:a}=r;i.push({op:n,path:[],value:t===rS?void 0:t}),a.push({op:n,path:[],value:e})}function l(e,t){return t.forEach(t=>{let{path:i,op:a}=t,o=e;for(let e=0;e[e,u(t)]));if(kS(e))return new Set(Array.from(e).map(u));let t=Object.create(lS(e));for(let n in e)t[n]=u(e[n]);return CS(e,iS)&&(t[iS]=e[iS]),t}function d(e){return gS(e)?u(e):e}JS(US,{applyPatches_:l,generatePatches_:i,generateReplacementPatches_:c,getPath:e})}globalThis.Iterator?.from;var OC=new CC,kC=OC.produce,AC=OC.produceWithPatches.bind(OC),jC=OC.applyPatches.bind(OC),MC=1e3;function NC(e,t){if(e.add(t),e.size>MC){let t=e.values().next().value;t!==void 0&&e.delete(t)}}function PC(e){let{enablePatches:t=!1}=e;t&&DC();let n=Jx(),r=e.initialValue,i=new Set;return{on:n.on,value:()=>r,patch:(e,t=nS())=>{i.has(t)||(DC(),r=jC(r,e),NC(i,t),n.emit(`updated`,r,void 0,t))},mutate:(e,a=nS())=>{if(!i.has(a)){if(NC(i,a),t){let[t,i]=AC(r,e);if(t===r)return;r=t,n.emit(`updated`,r,i,a)}else{let t=kC(r,e);if(t===r)return;r=t,n.emit(`updated`,r,void 0,a)}}},syncIds:i}}var FC=typeof self==`object`?self:globalThis,IC=new Set([`Error`,`EvalError`,`RangeError`,`ReferenceError`,`SyntaxError`,`TypeError`,`URIError`,`AggregateError`]),LC=new Set([`Boolean`,`Number`,`String`,`Int8Array`,`Uint8Array`,`Uint8ClampedArray`,`Int16Array`,`Uint16Array`,`Int32Array`,`Uint32Array`,`Float16Array`,`Float32Array`,`Float64Array`,`BigInt64Array`,`BigUint64Array`]);function RC(e,t){let n=(t,n)=>(e.set(n,t),t),r=i=>{if(e.has(i))return e.get(i);let[a,o]=t[i];switch(a){case 0:case-1:return n(o,i);case 1:{let e=n([],i);for(let t of o)e.push(r(t));return e}case 2:{let e=n({},i);for(let[t,n]of o)e[r(t)]=r(n);return e}case 3:return n(new Date(o),i);case 4:{let{source:e,flags:t}=o;return n(new RegExp(e,t),i)}case 5:{let e=n(new Map,i);for(let[t,n]of o)e.set(r(t),r(n));return e}case 6:{let e=n(new Set,i);for(let t of o)e.add(r(t));return e}case 7:{let{name:e,message:t}=o,r=IC.has(e)?FC[e]:void 0;return n(new(r??FC.Error)(t),i)}case 8:return n(BigInt(o),i);case`BigInt`:return n(Object(BigInt(o)),i);case`ArrayBuffer`:return n(new Uint8Array(o).buffer,o);case`DataView`:{let{buffer:e}=new Uint8Array(o);return n(new DataView(e),o)}}if(typeof a==`string`&&LC.has(a))return n(new FC[a](o),i);throw TypeError(`unable to deserialize unsafe or unknown type: ${String(a)}`)};return r}function zC(e){return RC(new Map,e)(0)}var BC=``,{toString:VC}={},{keys:HC}=Object;function UC(e){let t=typeof e;if(t!==`object`||!e)return[0,t];let n=VC.call(e).slice(8,-1);switch(n){case`Array`:return[1,BC];case`Object`:return[2,BC];case`Date`:return[3,BC];case`RegExp`:return[4,BC];case`Map`:return[5,BC];case`Set`:return[6,BC];case`DataView`:return[1,n]}return n.includes(`Array`)?[1,n]:n.includes(`Error`)?[7,n]:[2,n]}function WC([e,t]){return e===0&&(t===`function`||t===`symbol`)}function GC(e,t,n,r){let i=(e,t)=>{let i=r.push(e)-1;return n.set(t,i),i},a=r=>{if(n.has(r))return n.get(r);let[o,s]=UC(r);switch(o){case 0:{let t=r;switch(s){case`bigint`:o=8,t=r.toString();break;case`function`:case`symbol`:if(e)throw TypeError(`unable to serialize ${s}`);t=null;break;case`undefined`:return i([-1],r)}return i([o,t],r)}case 1:{if(s){let e=r;return s===`DataView`?e=new Uint8Array(r.buffer):s===`ArrayBuffer`&&(e=new Uint8Array(r)),i([s,[...e]],r)}let e=[],t=i([o,e],r);for(let t of r)e.push(a(t));return t}case 2:{if(s)switch(s){case`BigInt`:return i([s,r.toString()],r);case`Boolean`:case`Number`:case`String`:return i([s,r.valueOf()],r)}if(t&&`toJSON`in r)return a(r.toJSON());let n=[],c=i([o,n],r);for(let t of HC(r))(e||!WC(UC(r[t])))&&n.push([a(t),a(r[t])]);return c}case 3:return i([o,r.toISOString()],r);case 4:{let{source:e,flags:t}=r;return i([o,{source:e,flags:t}],r)}case 5:{let t=[],n=i([o,t],r);for(let[n,i]of r)(e||!(WC(UC(n))||WC(UC(i))))&&t.push([a(n),a(i)]);return n}case 6:{let t=[],n=i([o,t],r);for(let n of r)(e||!WC(UC(n)))&&t.push(a(n));return n}}let{message:c}=r;return i([o,{name:s,message:c}],r)};return a}function KC(e,t={}){let n=[];return GC(!(t.json||t.lossy),!!t.json,new Map,n)(e),n}var{parse:qC,stringify:JC}=JSON,YC={json:!0,lossy:!0};function XC(e){return zC(qC(e))}function ZC(e){return JC(KC(e,YC))}function QC(e){return zC(e)}function $C(e){return ZC(e)}function ew(e){return XC(e)}var tw=256,nw=class extends Error{name=`StreamClosedError`};function rw(e={}){let t=e.id??nS(),n=Math.max(0,e.replayWindow??0),r=Jx(),i=new AbortController,a=[],o=!1,s=0;function c(e){if(o)throw new nw(`Cannot write to a closed stream "${t}"`);s+=1,n>0&&(a.push({seq:s,chunk:e}),a.length>n&&(a.length-n===1?a.shift():a.splice(0,a.length-n))),r.emit(`chunk`,s,e)}function l(e){if(o)return;o=!0;let t=aw(e);i.abort(e),r.emit(`end`,t)}function u(){o||(o=!0,i.signal.aborted||i.abort(`stream closed`),r.emit(`end`,void 0))}function d(e){o||i.signal.aborted||i.abort(e??`aborted`)}let f=new WritableStream({write(e){c(e)},close(){u()},abort(e){l(e)}});return{id:t,signal:i.signal,get closed(){return o},get lastSeq(){return s},write:c,error:l,close:u,abort:d,writable:f,events:r,buffer:a}}function iw(e={}){let t=e.id??nS(),n=Math.max(1,e.highWaterMark??tw),r=[],i=0,a=!1,o=!1,s,c,l,u;function d(){if(c){if(r.length>0){let e=r.shift(),t=c;c=void 0,t.resolve({value:e,done:!1});return}if(a){let e=c;if(c=void 0,s){let t=Error(s.message);t.name=s.name,e.reject(t)}else e.resolve({value:void 0,done:!0})}}}function f(){if(l){for(;r.length>0;){let e=r.shift();try{l.enqueue(e)}catch{break}}if(a&&l){try{if(s){let e=Error(s.message);e.name=s.name,l.error(e)}else l.close()}catch{}l=void 0}}}function p(t,s){if(!(a||o)&&!(t<=i)){if(i=t,r.push(s),r.length>n){let t=r.length-n;r.splice(0,t),e.onOverflow?.(t)}d(),u&&f()}}function m(e){a||(a=!0,s=e,d(),u&&f())}function h(){o||a||(o=!0,e.onCancel?.(),m(void 0))}function g(){return u||(u=new ReadableStream({start(e){l=e,f()},cancel(){h()}}),u)}return{id:t,get cancelled(){return o},get done(){return a},get lastSeenSeq(){return i},get readable(){return g()},cancel:h,_push:p,_end:m,[Symbol.asyncIterator](){return{next(){if(r.length>0)return Promise.resolve({value:r.shift(),done:!1});if(a){if(s){let e=Error(s.message);return e.name=s.name,Promise.reject(e)}return Promise.resolve({value:void 0,done:!0})}return new Promise((e,t)=>{c={resolve:e,reject:t}})},return(){return h(),Promise.resolve({value:void 0,done:!0})}}}}}function aw(e){if(e instanceof Error)return{name:e.name||`Error`,message:e.message};if(typeof e==`string`)return{name:`Error`,message:e};try{return{name:`Error`,message:JSON.stringify(e)}}catch{return{name:`Error`,message:String(e)}}}var ow=128;function sw(e){return e.replace(/[^\w-]+/g,`_`).slice(0,ow)}var cw=`modulepreload`,lw=function(e,t){return new URL(e,t).href},uw={},dw=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=lw(t,n),t=s(t),t in uw)return;uw[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:cw,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},fw=`__connection.json`,pw=`__DEVFRAME_CONNECTION__`,mw=`x-birpc-session`,hw=`__rpc-dump/index.json`,gw=`devframe:services`,_w=`devframe_otp`,vw=`devframe_auth_token`;mx.postMessage.remoteAssetsError;var yw=class{cacheMap=new Map;options;keySerializer;constructor(e){this.options=e,this.keySerializer=e.keySerializer||(e=>qx(e))}updateOptions(e){this.options={...this.options,...e}}cached(e,t){let n=this.cacheMap.get(e);if(n)return n.get(this.keySerializer(t))}has(e,t){return this.cacheMap.get(e)?.has(this.keySerializer(t))??!1}apply(e,t){let n=this.cacheMap.get(e.m)||new Map;n.set(this.keySerializer(e.a),t),this.cacheMap.set(e.m,n)}validate(e){return this.options.functions.includes(e)}clear(e){e?this.cacheMap.delete(e):this.cacheMap.clear()}},bw=_x({docsBase:`https://devfra.me/errors`,codes:{DF0019:{why:e=>`RPC function "${e.name}" has \`agent\` set but \`jsonSerializable\` is \`false\`; MCP requires JSON-serializable data.`,fix:"Remove `jsonSerializable: false`, or remove `agent` to keep it RPC-only."},DF0020:{why:e=>`RPC function "${e.name}" declares \`jsonSerializable: true\` but the value at "${e.path}" is a ${e.type}.`,fix:"Either drop `jsonSerializable: true` (falls back to structured-clone) or change the value to a JSON-safe shape."},DF0021:{why:e=>`RPC function "${e.name}" is already registered`,fix:"Use the `force` parameter to overwrite an existing registration."},DF0022:{why:e=>`RPC function "${e.name}" is not registered. Use register() to add new functions.`},DF0023:{why:e=>`RPC function "${e.name}" is not registered`},DF0024:{why:e=>`Either handler or setup function must be provided for RPC function "${e.name}"`},DF0025:{why:e=>`Function "${e.name}" not found in dump store`},DF0026:{why:e=>`No dump match for "${e.name}" with args: ${e.args}`},DF0027:{why:e=>`Function "${e.name}" with type "${e.type}" cannot have dump configuration. Only "static" and "query" types support dumps.`},DF0028:{why:e=>`Function "${e.name}" with type "${e.type}" cannot use \`snapshot: true\`. Only "query" functions support this sugar; "static" functions have equivalent default behavior already.`,fix:"Remove `snapshot: true`, or change the function type to `query`."},DF0043:{why:e=>`RPC function "${e.name}" received an invalid argument at position ${e.index}: ${e.issues}`,fix:"Pass a value that satisfies the `args` schema declared for this function."},DF0044:{why:e=>`RPC function "${e.name}" returned a value that failed its \`returns\` schema: ${e.issues}`,fix:"Make the handler return a value that satisfies the `returns` schema, or relax the schema."}}});function xw(e){if(e.agent&&e.jsonSerializable===!1)throw bw.DF0019({name:e.name});e.agent&&!e.jsonSerializable&&(e.jsonSerializable=!0)}async function Sw(e,t){let n=e[`~standard`].validate(t);return n instanceof Promise?await n:n}function Cw(e){return e.map(e=>{let t=e.path?.map(e=>typeof e==`object`?e.key:e).join(`.`);return t?`${t}: ${e.message}`:e.message}).join(`; `)}async function ww(e,t,n){let r=n.slice();if(!t||t.length===0)return r;for(let r=0;r{n.get(t)===r&&n.delete(t)}),n.set(t,r)),await r}if(!e.__promise){let n=Promise.resolve(e.setup(t));n.catch(()=>{e.__promise===n&&(e.__promise=void 0)}),e.__promise=n}return await e.__promise}async function Dw(e,t){let n=e.handler;if(!n){let r=await Ew(e,t);if(!r.handler)throw bw.DF0024({name:e.name});n=r.handler}let r=e.args,i=e.returns;if(!r&&!i)return n;let a=n;return async(...t)=>{let n=await ww(e.name,r,t),o=await a(...n);return await Tw(e.name,i,o)}}var Ow=class{context;definitions=new Map;functions;_onChanged=[];constructor(e){this.context=e;let t=this.definitions,n=this;this.functions=new Proxy({},{get(e,r){let i=t.get(r);if(i)return Dw(i,n.context)},has(e,n){return t.has(n)},getOwnPropertyDescriptor(e,n){return{value:t.get(n)?.handler,configurable:!0,enumerable:!0}},ownKeys(){return Array.from(t.keys())}})}register(e,t=!1){if(this.definitions.has(e.name)&&!t)throw bw.DF0021({name:e.name});xw(e),this.definitions.set(e.name,e),this._onChanged.forEach(t=>t(e.name))}update(e,t=!1){if(!this.definitions.has(e.name)&&!t)throw bw.DF0022({name:e.name});xw(e),this.definitions.set(e.name,e),this._onChanged.forEach(t=>t(e.name))}onChanged(e){return this._onChanged.push(e),()=>{let t=this._onChanged.indexOf(e);t!==-1&&this._onChanged.splice(t,1)}}async getHandler(e){return await Dw(this.definitions.get(e),this.context)}getSchema(e){let t=this.definitions.get(e);if(!t)throw bw.DF0023({name:String(e)});return{args:t.args,returns:t.returns}}has(e){return this.definitions.has(e)}get(e){return this.definitions.get(e)}list(){return Array.from(this.definitions.keys())}};function kw(e,t=``){return JSON.stringify(e,function(e,n){let r=this,i=r==null?n:r[e];if(i===void 0){if(Array.isArray(r))throw jw(t,`undefined`,r,e);return n}return i!==null&&Aw(i,r,e,t),n})}function Aw(e,t,n,r){if(typeof e==`bigint`)throw jw(r,`BigInt`,t,n);if(typeof e!=`object`)return;if(e instanceof Map)throw jw(r,`Map`,t,n);if(e instanceof Set)throw jw(r,`Set`,t,n);if(e instanceof Date)throw jw(r,`Date`,t,n);if(Array.isArray(e))return;let i=Object.getPrototypeOf(e);if(i!==null&&i!==Object.prototype)throw jw(r,e.constructor?.name??`class instance`,t,n)}function jw(e,t,n,r){let i=Mw(n,r);return bw.DF0020({name:e||``,type:t,path:i})}function Mw(e,t){return Array.isArray(e)?`[${t}]`:t===``?``:t}var Nw=`__DEVFRAME_CONNECTION_META__`,Pw=`__DEVFRAME_CONNECTION_AUTH_TOKEN__`;function Fw(e){let t=[()=>window?.[e],()=>globalThis?.[e],()=>parent.window?.[e]];for(let e of t)try{let t=e();if(t)return t}catch{}}function Iw(){return Fw(pw)}function Lw(){return Fw(Nw)}function Rw(e){if(e)return e;try{let e=localStorage.getItem(Pw);if(e)return e}catch{}return Fw(Pw)}function zw(e){globalThis[pw]=e,globalThis[Nw]={...e.connectionMeta,baseUrl:e.metaBaseUrl},e.authToken&&Bw(e.authToken)}function Bw(e){try{localStorage.setItem(Pw,e)}catch{}globalThis[Pw]=e;let t=Iw();t&&(globalThis[pw]={...t,authToken:e})}function Vw(e){let t=$x(fw,e);try{return new URL(t,globalThis.location?.href).href}catch{return t}}function Hw(e,t){return t&&t!==e.authToken?{...e,authToken:t}:e}function Uw(){let e=Iw();if(e)return Hw(e,Rw()??e.authToken??e.connectionMeta.authToken);let t=Lw();if(t)return{connectionMeta:t,metaBaseUrl:t.baseUrl??Vw(`./`),authToken:Rw(t.authToken)}}async function Ww(e={}){if(e.connection){let t=Hw(e.connection,Rw(e.authToken??e.connection.authToken??e.connection.connectionMeta.authToken));return zw(t),t}let t=Array.isArray(e.baseURL)?e.baseURL:[e.baseURL??`./`];if(e.connectionMeta){let n={connectionMeta:e.connectionMeta,metaBaseUrl:Vw(t[0]??`./`),authToken:Rw(e.authToken??e.connectionMeta.authToken)};return zw(n),n}let n=Uw();if(n){let t=Hw(n,Rw(e.authToken??n.authToken??n.connectionMeta.authToken));return zw(t),t}let r=[];for(let n of t){let t=$x(fw,n),i=Vw(n);try{let n=await fetch(t);if(!n.ok)throw Error(`Failed to fetch connection meta from ${i}: ${n.status}`);let r=await n.json(),a=n.url||i,o={connectionMeta:r,metaBaseUrl:r.baseUrl?new URL(r.baseUrl,a).href:a,authToken:Rw(e.authToken??r.authToken)};return zw(o),o}catch(e){r.push(e)}}throw Error(`Failed to get connection meta from ${t.join(`, `)}`,{cause:r})}var Gw=class extends Error{name=`DevframeConnectionError`;kind;constructor(e,t,n){super(t,n),this.kind=e}};function Kw(e=_w){try{let t=globalThis.location?.hash?.replace(/^#/,``)??``;return new URLSearchParams(t).get(e)||void 0}catch{return}}function qw(e){try{let t=new URL(globalThis.location.href),n=new URLSearchParams(t.hash.replace(/^#/,``));if(!n.has(e))return;n.delete(e),t.hash=n.toString(),globalThis.history?.replaceState(globalThis.history.state,``,t.href)}catch{}}function Jw(e=_w){let t=Kw(e);return t&&qw(e),t}async function Yw(e,t={}){let n=Jw(t.param??`devframe_otp`);return n?e.isTrusted?!0:e.requestTrustWithCode(n):!1}function Xw(e){let t={},n=new WeakMap,r,i=()=>(r??=e.sharedState.get(gw,{initialValue:{}}).then(e=>(t=e.value(),e.on(`updated`,e=>{t=e}),e)),r);return i(),{state:i,has:e=>e in t,keys:()=>Object.keys(t),get:r=>{let i=t[r];if(!i)return;let a=n.get(i);return a||(a={...i,rpc:e.scope(i.scope).rpc},n.set(i,a)),a}}}function Zw(e){let t=new Map,n=new Map,r=new Map,i=new Set,a=e.connectionMeta.backend===`static`;function o(e,t){let n=r.get(e);return n&&typeof n==`object`&&!Array.isArray(n)&&typeof t==`object`&&!Array.isArray(t)?{...n,...t}:t}e.client.register({name:mx.broadcast.clientStateUpdated,type:`event`,handler:(e,n,r)=>{let i=t.get(e);i&&!i.syncIds.has(r)&&i.mutate(()=>o(e,n),r)}}),e.client.register({name:mx.broadcast.clientStatePatch,type:`event`,handler:(e,n,r)=>{let i=t.get(e);i&&!i.syncIds.has(r)&&i.patch(n,r)}});function s(t,n){let r=[];return r.push(n.on(`updated`,(n,r,i)=>{a||(r?e.callEvent(`devframe:rpc:server-state:patch`,t,r,i):e.callEvent(`devframe:rpc:server-state:set`,t,n,i))})),()=>{for(let e of r)e()}}return{keys:()=>Array.from(t.keys()),onKeyAdded(e){return i.add(e),()=>{i.delete(e)}},delete(e){let i=n.get(e);n.delete(e);let a=t.delete(e);return r.delete(e),i?.(),a},get:async(c,l)=>{if(l?.initialValue!==void 0&&r.set(c,l.initialValue),t.has(c))return t.get(c);let u=PC({initialValue:l?.initialValue,enablePatches:!1});async function d(){if(a||e.callEvent(`devframe:rpc:server-state:subscribe`,c),l?.initialValue!==void 0){t.set(c,u);for(let e of i)e(c);return e.call(`devframe:rpc:server-state:get`,c).then(e=>{e!==void 0&&u.mutate(()=>o(c,e))}).catch(e=>{console.error(`Error getting server state`,e)}),n.set(c,s(c,u)),u}{let r=await e.call(`devframe:rpc:server-state:get`,c);u.mutate(()=>o(c,r)),t.set(c,u);for(let e of i)e(c);return n.set(c,s(c,u)),u}}return new Promise(t=>{if(e.isTrusted)d().then(t);else{t(u);let n=!1;e.events.on(mx.client.isTrustedUpdated,e=>{e&&!n&&(n=!0,d())})}})}}}var Qw=new Map;function $w(e=Qw){let t=new Map;return{serialize:n=>{let r;return n.t===`q`?r=n.m:(r=t.get(n.i),t.delete(n.i)),!(n.t===`s`&&`e`in n)&&r&&e.get(r)?.jsonSerializable===!0?kw(n,r??``):`s:${$C(n)}`},deserialize:e=>{let n=e.startsWith(`s:`)?ew(e.slice(2)):JSON.parse(e);return n.t===`q`&&n.i&&n.m&&t.set(n.i,n.m),n}}}function eT(){}function tT(e){let t=e.search(/\n\n|\r\n\r\n/);if(!(t<0))return{frame:e.slice(0,t),rest:e.slice(t+(e[t]===`\r`?4:2))}}function nT(e){let t=`message`,n=[];for(let r of e.split(/\r?\n/))r.startsWith(`:`)||(r.startsWith(`event:`)?t=r.slice(6).trimStart():r.startsWith(`data:`)&&n.push(r.slice(5).replace(/^ /,``)));return{event:t,data:n}}function rT(e){let{onConnected:t=eT,onError:n=eT,onDisconnected:r=eT,definitions:i,fetch:a=globalThis.fetch.bind(globalThis)}=e,o=e.url;e.authToken&&(o=`${o}${o.includes(`?`)?`&`:`?`}${vw}=${encodeURIComponent(e.authToken)}`);let s=$w(i),c=new AbortController,l=!1,u,d,f,p,m=new Promise((e,t)=>{f=e,p=t});m.catch(()=>{});function h(e){l||(l=!0,p(e),n(e),r())}function g(){l||(l=!0,p(Error(`Devframe SSE stream closed`)),r())}function _(e,n){if(e===`session`){f(n),t();return}u?.(n)}async function ee(e){let t=e.getReader();d=t;let n=new TextDecoder,r=``;for(;;){let{done:e,value:i}=await t.read();if(e)break;for(r+=n.decode(i,{stream:!0});;){let e=tT(r);if(!e)break;r=e.rest;let{event:t,data:n}=nT(e.frame);n.length>0&&_(t,n.join(` -`))}}g()}return(async()=>{try{let e=await a(o,{headers:{accept:`text/event-stream`},signal:c.signal});if(!e.ok||!e.body)throw Error(`Devframe SSE stream request failed: ${e.status}`);await ee(e.body)}catch(e){if(c.signal.aborted){g();return}h(e instanceof Error?e:Error(String(e)))}})(),{close:()=>{l=!0,c.abort(),d?.cancel().catch(()=>{})},on:e=>{u=e},post:async e=>{let t;try{t=await m}catch{return}if(l){n(Error(`Devframe SSE channel is closed; message dropped`));return}try{let n=await a(o,{method:`POST`,headers:{"content-type":`text/plain; charset=utf-8`,[mw]:t},body:e});if(n.status===200){let e=await n.text();e&&u?.(e);return}if(!n.ok)throw Error(`Devframe SSE POST failed: ${n.status}`)}catch(e){n(e instanceof Error?e:Error(String(e)))}},serialize:s.serialize,deserialize:s.deserialize}}function iT(e,t){let{channel:n,rpcOptions:r={}}=t;return Dx(e,{...n,timeout:-1,...r,proxify:!1})}function aT(e){let{transport:t,authToken:n,connectionMeta:r,events:i,clientRpc:a,rpcOptions:o={},callTimeout:s=0}=e,c=!1,l=`connecting`,u=null,d=Promise.withResolvers();function f(e,t=null){if(t?u=t:e===`connected`&&(u=null),e===l)return;let n=l;l=e,i.emit(mx.client.connectionStatus,e,n)}let p=new Set;function m(e){for(let t of[...p])t.reject(e)}function h(){return l===`disconnected`||l===`error`?new Gw(`connection`,`[devframe] Not connected to the devframe server`,{cause:u??void 0}):l===`unauthorized`?new Gw(`auth`,`[devframe] Not authorized by the devframe server`,{cause:u??void 0}):null}function g(e,t){return new Promise((n,r)=>{let a=!1,o,c={reject(e){a||(l(),i.emit(mx.client.error,e,t),r(e))}};function l(){a=!0,p.delete(c),o&&clearTimeout(o)}p.add(c),s>0&&(o=setTimeout(()=>{c.reject(new Gw(`timeout`,`[devframe] RPC call "${t}" timed out after ${s}ms`))},s)),e.then(e=>{a||(l(),n(e))},e=>{if(a)return;l();let n=e instanceof Error?e:Error(String(e));i.emit(mx.client.error,n,t),r(n)})})}let _=new Map;for(let e of r.jsonSerializableMethods??[])_.set(e,{jsonSerializable:!0});let ee=e.createChannel({definitions:_,onError(e){f(`error`,e),i.emit(mx.client.connectionError,e),m(new Gw(`connection`,`[devframe] Connection to the devframe server failed`,{cause:e}))},onDisconnected(){l!==`error`&&f(`disconnected`),m(new Gw(`connection`,`[devframe] Disconnected from the devframe server`,{cause:u??void 0}))}}),te=iT(a.functions,{channel:ee,rpcOptions:o});a.register({name:mx.broadcast.authRevoked,type:`event`,handler:()=>{c=!1;let e=new Gw(`auth`,`[devframe] The devframe server revoked this client's trust`);f(`unauthorized`,e),i.emit(mx.client.connectionError,e),m(e),i.emit(mx.client.isTrustedUpdated,!1)}});let ne=n;async function re(e){ne=e;let t=await te.$call(`anonymous:devframe:auth`,{authToken:e,ua:navigator.userAgent,origin:location.origin});if(c=t.isTrusted,c)d.resolve(!0),f(`connected`);else{let e=new Gw(`auth`,`[devframe] The devframe server refused this client's credentials`);f(`unauthorized`,e),i.emit(mx.client.connectionError,e)}return i.emit(mx.client.isTrustedUpdated,c),t.isTrusted}async function ie(e){let t=(await te.$call(`anonymous:devframe:auth:exchange`,{code:e,ua:navigator.userAgent,origin:location.origin}))?.authToken??null;return t&&(ne=t,c=!0,d.resolve(!0),f(`connected`),i.emit(mx.client.isTrustedUpdated,!0)),t}async function ae(e={}){await te.$call(`anonymous:devframe:auth:request-code`,{ua:navigator.userAgent,origin:location.origin,...e.reissue?{reissue:!0}:{}})}async function oe(){return c?!0:re(ne??``)}async function se(e=6e4){if(c&&d.resolve(!0),e<=0)return d.promise;let t;try{return await Promise.race([d.promise,new Promise((n,r)=>{t=setTimeout(()=>{r(Error(`[devframe] Timeout waiting for rpc to be trusted`))},e)})]),c}finally{clearTimeout(t)}}return{transport:t,get isTrusted(){return c},get status(){return l},get connectionError(){return u},requestTrust:oe,requestTrustWithToken:re,requestTrustWithCode:ie,requestAuthCode:ae,ensureTrusted:se,call:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(mx.client.error,n,t),Promise.reject(n)):g(te.$call(...e),t)},callEvent:(...e)=>{let t=h();if(t){i.emit(mx.client.error,t,String(e[0]));return}return te.$callEvent(...e)},callOptional:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(mx.client.error,n,t),Promise.reject(n)):g(te.$callOptional(...e),t)},close:()=>{ee.close()}}}function oT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})();if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`;return new URL(e.path??`/`,`${r.protocol}//${t}`).href}return new URL(e.path??``,r).href}let i=e??``;return/^https?:\/\//i.test(i)?i:new URL(i,r).href}function sT(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},sseOptions:s={},callTimeout:c=0}=e,l=oT(n.sse,r??`./`,location);return aT({transport:`sse`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>rT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(){s.onConnected?.()},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(){e.onDisconnected(),s.onDisconnected?.()}})})}function cT(e){let{name:t,message:n,cause:r,...i}=e,a=r instanceof Error?r:lT(r)?cT(r):r,o=a===void 0?Error(n):Error(n,{cause:a});return o.name=t,Object.assign(o,i),o}function lT(e){return typeof e==`object`&&!!e&&typeof e.message==`string`&&typeof e.name==`string`}function uT(e){return typeof e==`object`&&!!e&&e.type===`static`&&typeof e.path==`string`}function dT(e){return typeof e==`object`&&!!e&&e.type===`query`&&typeof e.records==`object`&&e.records!==null}function fT(e){return typeof e==`object`&&!!e&&(`output`in e||`error`in e)}function pT(e){if(e.error)throw cT(e.error);return e.output}function mT(e){return e.some(e=>e!=null)}function hT(e){return typeof e==`object`&&e&&`serialization`in e&&`data`in e?e.data:e}function gT(e,t){let n=new Map,r=new Map;function i(e,t){return t===`structured-clone`&&Array.isArray(e)?QC(e):e}function a(e,t){return i(hT(e),t)}async function o(e){n.has(e.path)||n.set(e.path,t(e.path).then(t=>a(t,e.serialization)));let r=await n.get(e.path);return fT(r)?pT(r):r}async function s(e,n){return r.has(e)||r.set(e,t(e).then(e=>a(e,n))),await r.get(e)}async function c(t,n){if(!(t in e))throw Error(`[devframe-rpc] Function "${t}" not found in dump store`);let r=e[t];if(uT(r)){if(mT(n))throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`);return await o(r)}if(dT(r)){let e=qx(n),i=r.records[e];if(i)return pT(await s(i,r.serialization));if(r.fallback)return pT(await s(r.fallback,r.serialization));throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}if(!mT(n))return r;throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}return{call:async(e,t)=>await c(e,t),callOptional:async(t,n)=>{if(t in e)return await c(t,n)},callEvent:async(e,t)=>{}}}async function _T(e){let t=gT(await e.fetchJsonFromBases(hw),e.fetchJsonFromBases);return{transport:`static`,isTrusted:!0,status:`connected`,connectionError:null,requestTrust:async()=>!0,requestTrustWithToken:async()=>!0,requestTrustWithCode:async()=>null,requestAuthCode:async()=>{},ensureTrusted:async()=>!0,call:(...e)=>t.call(e[0],e.slice(1)),callEvent:(...e)=>t.callEvent(e[0],e.slice(1)),callOptional:(...e)=>t.callOptional(e[0],e.slice(1)),close:()=>{}}}var vT=``;function yT(e,t){return`${e}${vT}${t}`}function bT(e){let t=new Map,n=new Map;e.client.register({name:mx.broadcast.streamingChunk,type:`event`,handler(e,n,r,i){t.get(yT(e,n))?._push(r,i)}}),e.client.register({name:mx.broadcast.streamingEnd,type:`event`,handler(e,n,r){let i=yT(e,n),a=t.get(i);a&&(a._end(r),t.delete(i))}}),e.client.register({name:mx.broadcast.streamingUploadCancel,type:`event`,handler(e,t){let r=yT(e,t),i=n.get(r);i&&(i.abort(`server cancelled upload`),n.delete(r))}}),e.events.on(mx.client.isTrustedUpdated,n=>{if(n)for(let[n,r]of t){if(r.cancelled||r.done)continue;let t=n.indexOf(vT);if(t<0)continue;let i=n.slice(0,t),a=n.slice(t+1);e.callEvent(`devframe:streaming:subscribe`,i,a,{afterSeq:r.lastSeenSeq})}});function r(n,r,i={}){let a=yT(n,r),o=t.get(a);if(o)return o;let s=iw({id:r,highWaterMark:i.highWaterMark,onOverflow(e){console.warn(`[devframe] DF0029: Stream "${n}#${r}" dropped ${e} chunk(s) after exceeding the client high-water mark.`)},onCancel(){e.callEvent(`devframe:streaming:cancel`,n,r),t.delete(a)}});if(t.set(a,s),e.isTrusted)e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:0});else{let i=e.events.on(mx.client.isTrustedUpdated,o=>{o&&(i(),t.has(a)&&!s.cancelled&&!s.done&&e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:s.lastSeenSeq}))})}return s}function i(t,r){let i=yT(t,r),a=n.get(i);if(a)return a;let o=rw({id:r});return o.events.on(`chunk`,(n,i)=>{e.callEvent(`devframe:streaming:upload-chunk`,t,r,n,i)}),o.events.on(`end`,a=>{e.callEvent(`devframe:streaming:upload-end`,t,r,a),n.delete(i)}),n.set(i,o),o}return{subscribe:r,upload:i}}function xT(){}var ST=new Map;function CT(e){let t=e.url;e.authToken&&(t=`${t}?${vw}=${encodeURIComponent(e.authToken)}`);let n=new WebSocket(t),{onConnected:r=xT,onError:i=xT,onDisconnected:a=xT,definitions:o=ST}=e;n.addEventListener(`open`,e=>{r(e)}),n.addEventListener(`error`,e=>{let t=e instanceof Error?e:Error(e.type);i(t)}),n.addEventListener(`close`,e=>{a(e)});let s=$w(o);return{close:()=>{n.close()},on:e=>{n.addEventListener(`message`,t=>{e(t.data)})},post:e=>{if(n.readyState===WebSocket.OPEN){n.send(e);return}if(n.readyState===WebSocket.CONNECTING){let t=()=>{i(),n.readyState===WebSocket.OPEN&&n.send(e)},r=()=>i();function i(){n.removeEventListener(`open`,t),n.removeEventListener(`close`,r)}n.addEventListener(`open`,t),n.addEventListener(`close`,r);return}i(Error(`Devframe WebSocket is not open; message dropped`))},serialize:s.serialize,deserialize:s.deserialize}}function wT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})(),i=r.protocol===`https:`?`wss:`:`ws:`;if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`,n=new URL(e.path??`/`,`${i}//${t}`);return n.protocol=i,n.href}let t=new URL(e.path??``,r);return t.protocol=i,t.href}if(typeof e==`number`)return`${i}//${r.hostname}:${e}`;let a=e??``;if(/^wss?:\/\//i.test(a))return a;if(/^https?:\/\//i.test(a))return eS(a,/^https/i.test(a)?`wss://`:`ws://`);let o=new URL(a,r);return o.protocol=i,o.href}function TT(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},wsOptions:s={},callTimeout:c=0}=e,l=wT(n.websocket,r??`./`,location);return aT({transport:`websocket`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>CT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(e){s.onConnected?.(e)},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(t){e.onDisconnected(),s.onDisconnected?.(t)}})})}function ET(e){return e.includes(`:`)}function DT(e,t){return ET(t)?t:`${e}:${t}`}function OT(e){return{async get(t){return(await e()).value()[t]},async set(t,n){(await e()).mutate(e=>{e[t]=n})},async delete(t){(await e()).mutate(e=>{delete e[t]})},async all(){return(await e()).value()},async onChange(t){return(await e()).on(`updated`,e=>t(e))}}}function kT(e,t,n){let r=`devframe:settings:${n}:${t}`,i;function a(){return i||=e.sharedState.get(r,{initialValue:{}}),i}return OT(a)}function AT(e,t){return{global:kT(e,t,`global`),project:kT(e,t,`project`)}}function jT(e,t){return{namespace:t,base:e,rpc:{namespace:t,register(n){if(ET(n.name))throw Error(`[devframe] Scoped client RPC registration for namespace "${t}" received an already-namespaced function name "${n.name}". Pass a bare name without a ":" separator.`);e.client.register({...n,name:`${t}:${n.name}`})},call:((n,...r)=>e.call(DT(t,n),...r)),callEvent:((n,...r)=>e.callEvent(DT(t,n),...r)),callOptional:((n,...r)=>e.callOptional(DT(t,n),...r)),sharedState:((n,r)=>e.sharedState.get(DT(t,n),r)),streaming:{subscribe:(n,r,i)=>e.streaming.subscribe(DT(t,n),r,i),upload:(n,r)=>e.streaming.upload(DT(t,n),r)}},settings:AT(e,t),scope:e.scope}}function MT(){if(typeof document<`u`){let e=document.modelContext;if(e)return e}if(typeof navigator<`u`){let e=navigator.modelContext;if(e)return e}}function NT(e,t={}){let n=t.modelContext??MT();if(!n)return()=>{};let r=n,i=new Map,a=new Map;function o(t,n){let o=sw(t.name),s=a.get(o);if(s&&s!==t.name){console.warn(`[devframe] WebMCP tool name "${o}" (from "${t.name}") collides with "${s}"; keeping the first registration.`);return}let c=new AbortController,l=Ox(t.type,n),u=r.registerTool({name:o,description:n.description,inputSchema:jx(t.args),annotations:{title:n.title??t.name,readOnlyHint:l===`read`,destructiveHint:l===`destructive`},execute:n=>PT(t,e.context,n)},{signal:c.signal});u&&`then`in u&&u.then(()=>{},()=>{}),a.set(o,t.name),i.set(t.name,()=>{c.abort(),u&&`unregister`in u&&typeof u.unregister==`function`&&u.unregister(),a.delete(o)})}function s(t){let n=t?[t]:[...e.definitions.keys()];for(let t of n){i.get(t)?.(),i.delete(t);let n=e.definitions.get(t),r=n?.agent;n&&r&&o(n,r)}}s();let c=e.onChanged(e=>s(e));return()=>{c();for(let e of i.values())e();i.clear()}}async function PT(e,t,n){try{let r=Nx(n,e.args?.length);return{content:[{type:`text`,text:FT(await(await Dw(e,t))(...r))}]}}catch(e){return{isError:!0,content:[{type:`text`,text:IT(e)}]}}}function FT(e){return e===void 0?`undefined`:typeof e==`string`?e:JSON.stringify(e,null,2)}function IT(e){if(!(e instanceof Error))return String(e);let t=e.cause instanceof Error?` (cause: ${e.cause.message})`:``;return`${e.name}: ${e.message}${t}`}function LT(e,t){if(t.backend===`static`)return`static`;let n=t.websocket!==void 0,r=t.sse!==void 0;if(e===`websocket`){if(!n)throw Error(`[devframe] transport: 'websocket' was requested, but this server does not advertise a WebSocket endpoint`);return`websocket`}if(e===`sse`){if(!r)throw Error(`[devframe] transport: 'sse' was requested, but this server does not advertise an SSE endpoint`);return`sse`}if(t.backend===`sse`&&r)return`sse`;if(n)return`websocket`;if(r)return`sse`;throw Error(`[devframe] This server advertises no RPC transport (backend "none"), so there is nothing to connect to. Enable the WebSocket or SSE endpoint on the server, or use its static/MCP surfaces instead.`)}async function RT(e={}){let{baseURL:t=`./`,rpcOptions:n={},cacheOptions:r=!1}=e,i=Jx(),a=Array.isArray(t)?t:[t],o=await Ww(e),{connectionMeta:s,metaBaseUrl:c,authToken:l}=o,u=a[0]??`./`;try{u=new URL(`.`,c).href}catch{}let d=new yw({functions:[],...typeof e.cacheOptions==`object`?e.cacheOptions:{}}),f={rpc:void 0},p=new Ow(f),m=e.webmcp===!1?void 0:NT(p),h,g=!1;async function _(e){let t=[u,...a.filter(e=>e!==u)].filter(e=>e!=null),n=[];for(let r of t)try{return await fetch($x(e,r)).then(t=>{if(!t.ok)throw Error(`Failed to fetch ${e} from ${r}: ${t.status}`);return t.json()})}catch(e){n.push(e)}throw Error(`Failed to load ${e} from ${t.join(`, `)}`,{cause:n})}let ee={authToken:l,connectionMeta:s,metaBaseUrl:c,events:i,clientRpc:p,callTimeout:e.callTimeout,rpcOptions:{...n,async onRequest(e,t,i){if(await n.onRequest?.call(this,e,t,i),r&&d?.validate(e.m)){if(d.has(e.m,e.a))return i(d.cached(e.m,e.a));let n=await t(e);d.apply(e,n)}else await t(e)}}},te=LT(e.transport??`auto`,s),ne=te===`static`?await _T({fetchJsonFromBases:_}):te===`sse`?sT({...ee,sseOptions:e.sseOptions}):TT({...ee,wsOptions:e.wsOptions}),re;try{re=new BroadcastChannel(`devframe-auth`)}catch{}let ie,ae=!1;function oe(e){return((...t)=>ae||!ie?e(...t):ie.then(()=>e(...t)))}function se(){g=!0;try{h?.(),m?.()}finally{try{re?.close()}finally{ne.close?.()}}}let ce={events:i,get isTrusted(){return ne.isTrusted},get status(){return ne.status},get connectionError(){return ne.connectionError},get transport(){return ne.transport??te},get connection(){return o},connectionMeta:s,ensureTrusted:ne.ensureTrusted,requestTrust:ne.requestTrust,requestTrustWithToken:async e=>(Bw(e),o={...o,authToken:e},ne.requestTrustWithToken(e)),requestTrustWithCode:async e=>{let t=await ne.requestTrustWithCode(e);if(!t)return!1;Bw(t),o={...o,authToken:t};try{re?.postMessage({type:`auth-update`,authToken:t})}catch{}return!0},requestAuthCode:e=>ne.requestAuthCode(e),call:oe(ne.call),callEvent:oe(ne.callEvent),callOptional:oe(ne.callOptional),client:p,sharedState:void 0,services:void 0,streaming:void 0,cacheManager:d,scope:void 0,close:se};ce.sharedState=Zw(ce),ce.streaming=bT(ce),ce.services=Xw(ce);let le=new Map;ce.scope=(e=>{if(!e)return ce;let t=le.get(e);return t||(t=jT(ce,e),le.set(e,t)),t}),f.rpc=ce;function ue(){try{return typeof window<`u`&&window.self===window.top}catch{return!1}}async function de(){if(e.simpleAuth!==!1&&ue()&&typeof globalThis.prompt==`function`)for(await ce.requestAuthCode().catch(()=>{});!ce.isTrusted;){let e=globalThis.prompt(`devframe: enter the authentication code shown in your terminal`);if(e==null)return;let t=e.trim();if(t&&await ce.requestTrustWithCode(t))return}}async function fe(){let t=await ne.requestTrust(),n=e.otpParam??`devframe_otp`,r=n?await Yw(ce,{param:n}):!1;t||r||ce.isTrusted||await de()}return ie=fe().then(()=>{ae=!0},()=>{ae=!0}),s.mcp&&dw(async()=>{let{setupBrowserAgentRpcBridge:e}=await import(`./browser-agent-rpc-BXhoSh1z-CQE1-tGR.js`);return{setupBrowserAgentRpcBridge:e}},[],import.meta.url).then(({setupBrowserAgentRpcBridge:e})=>{g||(h=e(ce))}).catch(()=>{}),re&&(re.onmessage=e=>{e.data?.type===`auth-update`&&e.data.authToken&&ce.requestTrustWithToken(e.data.authToken)}),ce}var zT=RT,BT=[`components`,`injectors`,`signals`,`ngrx`,`forms`,`router`,`pipes`,`http`,`analog`,`capacitor`],VT=[`angular`,`ngrx`,`analog`,`angular-native`,`nativescript`,`capacitor`];function HT(e){return`pangular:${e}`}var UT=[`forms`,`router`,`ngrx`,`http`,`analog`,`components`],WT={refreshMs:{default:3e3,min:500,max:8e3},navigations:{default:50,min:5,max:500},formTimeline:{default:200,min:10,max:2e3},httpCalls:{default:200,min:10,max:2e3},changeLog:{default:200,min:10,max:2e3},cdCycles:{default:200,min:10,max:2e3},capacitorCalls:{default:200,min:10,max:2e3}},GT={"opted-out":`the request sets transferCache: false`,post:`POST requests are left out unless includePostRequests is set`,method:`only GET, HEAD and POST requests are cached`,"auth-headers":`it sends an Authorization, Proxy-Authorization or Cookie header`,credentials:`it sends credentials (withCredentials or credentials: include/same-origin)`,"no-cache-request":`the request asks for no-store, no-cache or private`,"no-cache-response":`the response has Cache-Control no-store, no-cache or private`,"set-cookie":`the response sets a cookie`,error:`failed responses are not stored`,mocked:`a fault rule answered before the transfer cache ran`,"cache-off-or-filter":`the transfer cache is off, or its filter (or another withHttpTransferCacheOptions setting) left it out`},KT=[[200,`OK`],[201,`Created`],[202,`Accepted`],[203,`Non-Authoritative Information`],[204,`No Content`],[205,`Reset Content`],[206,`Partial Content`],[207,`Multi-Status`],[208,`Already Reported`],[226,`IM Used`],[300,`Multiple Choices`],[301,`Moved Permanently`],[302,`Found`],[303,`See Other`],[304,`Not Modified`],[307,`Temporary Redirect`],[308,`Permanent Redirect`],[400,`Bad Request`],[401,`Unauthorized`],[402,`Payment Required`],[403,`Forbidden`],[404,`Not Found`],[405,`Method Not Allowed`],[406,`Not Acceptable`],[407,`Proxy Authentication Required`],[408,`Request Timeout`],[409,`Conflict`],[410,`Gone`],[411,`Length Required`],[412,`Precondition Failed`],[413,`Content Too Large`],[414,`URI Too Long`],[415,`Unsupported Media Type`],[416,`Range Not Satisfiable`],[417,`Expectation Failed`],[418,`I'm a Teapot`],[421,`Misdirected Request`],[422,`Unprocessable Content`],[423,`Locked`],[424,`Failed Dependency`],[425,`Too Early`],[426,`Upgrade Required`],[428,`Precondition Required`],[429,`Too Many Requests`],[431,`Request Header Fields Too Large`],[451,`Unavailable For Legal Reasons`],[499,`Client Closed Request`],[500,`Internal Server Error`],[501,`Not Implemented`],[502,`Bad Gateway`],[503,`Service Unavailable`],[504,`Gateway Timeout`],[505,`HTTP Version Not Supported`],[506,`Variant Also Negotiates`],[507,`Insufficient Storage`],[508,`Loop Detected`],[510,`Not Extended`],[511,`Network Authentication Required`],[520,`Web Server Returned an Unknown Error`],[521,`Web Server Is Down`],[522,`Connection Timed Out`],[523,`Origin Is Unreachable`],[524,`A Timeout Occurred`]];function qT(e){return KT.some(([t])=>t===e)}var JT=`pangular`;function YT(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}function XT(e,t){return typeof e==`boolean`?e:t}var ZT=100,QT=100;function $T(e){if(!Array.isArray(e))return[];let t=e.filter(e=>typeof e==`string`).map(e=>e.trim()).filter(e=>e&&e.length<=QT);return[...new Set(t)].slice(0,ZT)}function eE(e,t){let{default:n,min:r,max:i}=WT[t];return typeof e!=`number`||!Number.isFinite(e)?n:Math.min(i,Math.max(r,Math.round(e)))}function tE(e,t){return Object.fromEntries(e.map(e=>[e,t(e)]))}function nE(e){let t=YT(e),n=YT(t.agent),r=YT(t.inspectors),i=YT(n.tools),a=YT(t.actions),o=XT(t.actions,!0),s=YT(t.redaction),c=YT(t.limits),l=tE(BT,e=>XT(r[e],!0));return{inspectors:l,agent:{readOnly:XT(n.readOnly,!1),tools:tE(BT,e=>l[e]&&XT(i[e],!0))},actions:tE(UT,e=>l[e]&&XT(a[e],o)),redaction:{secretNames:$T(s.secretNames),unmask:$T(s.unmask)},limits:Object.fromEntries(Object.keys(WT).map(e=>[e,eE(c[e],e)]))}}function rE(e){let t=e?.configs;return nE(t?.[JT])}function iE(e){return`${{forms:`Writing to forms`,router:`Navigating and clearing navigations`,ngrx:`Restoring NgRx state and dispatching actions`,http:`Changing HTTP mock rules and clearing HTTP calls`,analog:`Calling API routes and clearing server calls`,components:`Editing component properties and signals`}[e]} is turned off in the devtools config (actions.${e}).`}var aE={components:`Components`,injectors:`Injectors`,signals:`Signals`,ngrx:`NgRx`,forms:`Forms`,router:`Router`,pipes:`Pipes`,http:`HTTP`,analog:`Analog`,capacitor:`Capacitor`},oE={forms:`Form writes`,router:`Navigation`,ngrx:`NgRx restore and dispatch`,http:`HTTP mocking`,analog:`Analog API calls`,components:`Component edits`},sE={refreshMs:e=>`poll every ${e} ms`,navigations:e=>`${e} navigations`,formTimeline:e=>`${e} form events`,httpCalls:e=>`${e} HTTP calls`,changeLog:e=>`${e} NgRx changes`,cdCycles:e=>`${e} change detection cycles`,capacitorCalls:e=>`${e} Capacitor plugin calls`};function cE(e){let t=[],n=(e,n)=>{n.length&&t.push({label:e,value:n.join(`, `)})},r=BT.filter(t=>e.inspectors[t]);return n(`Inspectors off`,BT.filter(t=>!e.inspectors[t]).map(e=>aE[e])),n(`Agent`,e.agent.readOnly?[`Read-only`]:[]),n(`Hidden from the agent`,r.filter(t=>!e.agent.tools[t]).map(e=>aE[e])),n(`Blocked actions`,UT.filter(t=>e.inspectors[t]&&!e.actions[t]).map(e=>oE[e])),n(`Extra secret names`,e.redaction.secretNames),n(`Unmasked names`,e.redaction.unmask),n(`Limits`,Object.keys(WT).filter(t=>e.limits[t]!==WT[t].default).map(t=>sE[t](e.limits[t]))),t}function lE(e){let t={tags:[],directives:[],text:``},n=e.toLowerCase();return n=n.replace(/<\s*([^<>\s]+)\s*>/g,(e,n)=>(t.tags.push({value:n,exact:!0}),` `)),n=n.replace(/\[\s*([^[\]\s]+)\s*\]/g,(e,n)=>(t.directives.push({value:n,exact:!0}),` `)),n=n.replace(/(^|\s)([<[])([^<>[\]\s]*)$/,(e,n,r,i)=>(i&&(r===`<`?t.tags:t.directives).push({value:i,exact:!1}),n)),t.text=n.replace(/\s+/g,` `).trim(),t}function uE(e){return!e.tags.length&&!e.directives.length&&!e.text}function dE(e,t){let n=e.tag.toLowerCase(),r=(e.directives??[]).map(e=>e.toLowerCase()),i=(e.attributes??[]).map(e=>e.toLowerCase()),a=[...r,...r.map(e=>e.replace(/directive$/,``)),...i];for(let{value:e,exact:r}of t.tags)if(r?n!==e:!n.startsWith(e))return!1;for(let{value:e,exact:n}of t.directives)if(!a.some(t=>n?t===e:t.includes(e)))return!1;if(t.text){let a=t.text;if(!(e.name.toLowerCase().includes(a)||n.includes(a)||r.some(e=>e.includes(a))||i.some(e=>e.includes(a))))return!1}return!0}var fE=`pangular-page-id`,pE=null;function mE(e){pE=e}function hE(){if(pE)return pE;try{return new URLSearchParams(location.search).get(`pageId`)||(window.top===window?null:sessionStorage.getItem(fE)||null)}catch{return null}}function gE(e,t){if(t.chosen&&e[t.chosen])return t.chosen;if(t.host)return t.host;if(t.previous&&e[t.previous])return t.previous;let n=null;for(let t of Object.values(e))(!n||t.reportedAt>n.reportedAt)&&(n=t);return n?.pageId??null}function _E(e,t){return e?t?e.pages?.[t]??null:e:null}function vE(e,t){return e?t?e.pages?.[t]??null:e.graph??null:null}function yE(e,t,n){return e?e.scope(`pangular`).rpc.call(t,...n===void 0?[]:[n]):Promise.resolve(null)}function bE(e,t,n){return yE(e,t,n).then(e=>e,()=>null)}function xE(e){return e?.connectionMeta.backend===`static`}function SE(e){let t=()=>{let t=e()?.scope(`pangular`).rpc;t&&(t.callEvent(`request-page-highlight`,null),t.callEvent(`request-form-highlight`,null))};return addEventListener(`pagehide`,t),()=>{removeEventListener(`pagehide`,t),t()}}function CE(e){return e.split(`@`)[1]??``}var wE={signal:`Signal Forms`,reactive:`Reactive`,template:`Template-driven`},TE={own:`validator`,directive:`template attribute`,tree:`cross-field rule`,async:`async`,parse:`parse`,submission:`server`,schema:`schema`,manual:`setErrors`},EE=bE,DE={key:`name looks secret`,"input-type":`password input`,autocomplete:`autocomplete is a secret kind`,marker:`marked as mask`,parent:`inside a secret group`,config:`listed in mask`};function OE(e){return DE[e]??e}var kE=`https://pangular-inspector.dev/security/#opt-fields-in-or-out`;async function AE(e,t){return await EE(e,`request-form-action`,t)??{ok:!1,error:`The devtools server did not answer.`}}function jE(e){return`${e.ok?e.message??`Done.`:e.error??`Failed.`}${e.skipped?.length?` Skipped: ${e.skipped.map(e=>`${e.path} (${e.reason})`).join(`, `)}.`:``}${e.status?` Status: ${e.status}.`:``}`}var ME=/"(?:[^"\\\n]|\\.)*"|`([^`\n]*)`|\*\*/g;function NE(e){return(e??``).replace(/^_Labels, paths.*_\n\n/,``).replace(ME,(e,t)=>t??(e===`**`?``:e))}function PE(e){return rE(e?.connectionMeta)}function FE(e,t){return PE(e).actions[t]}var IE={components:`components`,routes:`router`,signals:`signals`,injectors:`injectors`,store:`ngrx`,forms:`forms`,pipes:`pipes`,network:`http`,analog:`analog`,capacitor:`capacitor`};function LE(e){return IE[e]}var RE=`https://pangular-inspector.dev/getting-started/configuration/#inspectors-and-agent-tools`;function zE(e,t){let n=IE[e];return!n||t.inspectors[n]}function BE(e,t){e&1&&(O(),Vg(0,`rect`,4)(1,`rect`,5)(2,`rect`,6)(3,`rect`,7))}function VE(e,t){e&1&&(O(),Vg(0,`path`,8)(1,`path`,9)(2,`path`,10))}function HE(e,t){e&1&&(O(),Vg(0,`circle`,11)(1,`path`,12)(2,`circle`,13))}function UE(e,t){e&1&&(O(),Vg(0,`path`,1))}function WE(e,t){e&1&&(O(),Vg(0,`path`,14)(1,`path`,15)(2,`path`,16)(3,`path`,17))}function GE(e,t){e&1&&(O(),Vg(0,`ellipse`,18)(1,`path`,19)(2,`path`,20))}function KE(e,t){e&1&&(O(),Vg(0,`rect`,21)(1,`path`,22)(2,`path`,23)(3,`path`,24))}function qE(e,t){e&1&&(O(),Vg(0,`circle`,25)(1,`path`,26)(2,`path`,27))}function JE(e,t){e&1&&(O(),Vg(0,`path`,28)(1,`path`,29)(2,`path`,30)(3,`path`,31)(4,`circle`,32))}function YE(e,t){e&1&&(O(),Vg(0,`path`,2))}function XE(e,t){e&1&&(O(),Vg(0,`path`,3))}var ZE=class e{name=$.required();static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-tab-icon`]],inputs:{name:[1,`name`]},decls:12,vars:1,consts:[[`viewBox`,`0 0 24 24`,`width`,`16`,`height`,`16`,`fill`,`none`,`stroke`,`currentColor`,`stroke-width`,`1.8`,`stroke-linecap`,`round`,`stroke-linejoin`,`round`,`aria-hidden`,`true`],[`d`,`M22 12h-4l-3 9L9 3l-3 9H2`],[`d`,`m8 3 4 8 5-5 5 15H2L8 3z`],[`fill`,`currentColor`,`stroke`,`none`,`transform`,`translate(1.8 1.8) scale(0.85)`,`d`,`M24 3.7l-5.766 5.766 5.725 5.736-3.713 3.712L5.073 3.742 8.786.03l5.736 5.726L20.284 0 24 3.7zM.029 8.785l3.713-3.713 15.173 15.173-3.713 3.714-5.732-5.726L3.7 24 0 20.285l5.754-5.764L.029 8.785z`],[`x`,`3`,`y`,`3`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`14`,`y`,`3`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`x`,`14`,`y`,`12`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`3`,`y`,`16`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`d`,`M12 2 3 7l9 5 9-5-9-5Z`],[`d`,`m3 12 9 5 9-5`],[`d`,`m3 17 9 5 9-5`],[`cx`,`6`,`cy`,`19`,`r`,`3`],[`d`,`M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15`],[`cx`,`18`,`cy`,`5`,`r`,`3`],[`d`,`M12 22v-5`],[`d`,`M9 8V2`],[`d`,`M15 8V2`],[`d`,`M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z`],[`cx`,`12`,`cy`,`5`,`rx`,`9`,`ry`,`3`],[`d`,`M3 5v14a9 3 0 0 0 18 0V5`],[`d`,`M3 12a9 3 0 0 0 18 0`],[`x`,`3`,`y`,`4`,`width`,`18`,`height`,`16`,`rx`,`2`],[`d`,`M7 9h10`],[`d`,`M7 13h6`],[`d`,`M7 17h8`],[`cx`,`12`,`cy`,`12`,`r`,`9`],[`d`,`M3 12h18`],[`d`,`M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18Z`],[`d`,`M4 7h10`],[`d`,`M4 17h6`],[`d`,`m14 13 4 4-4 4`],[`d`,`M10 17h8`],[`cx`,`18`,`cy`,`7`,`r`,`3`]],template:function(e,t){if(e&1&&(O(),B(0,`svg`,0),M(1,BE,4,0)(2,VE,3,0)(3,HE,3,0)(4,UE,1,0,`:svg:path`,1)(5,WE,4,0)(6,GE,3,0)(7,KE,4,0)(8,qE,3,0)(9,JE,5,0)(10,YE,1,0,`:svg:path`,2)(11,XE,1,0,`:svg:path`,3),V()),e&2){let e;A(),N((e=t.name())===`dashboard`?1:e===`components`?2:e===`routes`?3:e===`signals`?4:e===`injectors`?5:e===`store`?6:e===`forms`?7:e===`network`?8:e===`pipes`?9:e===`analog`?10:e===`capacitor`?11:-1)}},styles:[`[_nghost-%COMP%] { +`))}}g()}return(async()=>{try{let e=await a(o,{headers:{accept:`text/event-stream`},signal:c.signal});if(!e.ok||!e.body)throw Error(`Devframe SSE stream request failed: ${e.status}`);await ee(e.body)}catch(e){if(c.signal.aborted){g();return}h(e instanceof Error?e:Error(String(e)))}})(),{close:()=>{l=!0,c.abort(),d?.cancel().catch(()=>{})},on:e=>{u=e},post:async e=>{let t;try{t=await m}catch{return}if(l){n(Error(`Devframe SSE channel is closed; message dropped`));return}try{let n=await a(o,{method:`POST`,headers:{"content-type":`text/plain; charset=utf-8`,[mw]:t},body:e});if(n.status===200){let e=await n.text();e&&u?.(e);return}if(!n.ok)throw Error(`Devframe SSE POST failed: ${n.status}`)}catch(e){n(e instanceof Error?e:Error(String(e)))}},serialize:s.serialize,deserialize:s.deserialize}}function iT(e,t){let{channel:n,rpcOptions:r={}}=t;return Dx(e,{...n,timeout:-1,...r,proxify:!1})}function aT(e){let{transport:t,authToken:n,connectionMeta:r,events:i,clientRpc:a,rpcOptions:o={},callTimeout:s=0}=e,c=!1,l=`connecting`,u=null,d=Promise.withResolvers();function f(e,t=null){if(t?u=t:e===`connected`&&(u=null),e===l)return;let n=l;l=e,i.emit(mx.client.connectionStatus,e,n)}let p=new Set;function m(e){for(let t of[...p])t.reject(e)}function h(){return l===`disconnected`||l===`error`?new Gw(`connection`,`[devframe] Not connected to the devframe server`,{cause:u??void 0}):l===`unauthorized`?new Gw(`auth`,`[devframe] Not authorized by the devframe server`,{cause:u??void 0}):null}function g(e,t){return new Promise((n,r)=>{let a=!1,o,c={reject(e){a||(l(),i.emit(mx.client.error,e,t),r(e))}};function l(){a=!0,p.delete(c),o&&clearTimeout(o)}p.add(c),s>0&&(o=setTimeout(()=>{c.reject(new Gw(`timeout`,`[devframe] RPC call "${t}" timed out after ${s}ms`))},s)),e.then(e=>{a||(l(),n(e))},e=>{if(a)return;l();let n=e instanceof Error?e:Error(String(e));i.emit(mx.client.error,n,t),r(n)})})}let _=new Map;for(let e of r.jsonSerializableMethods??[])_.set(e,{jsonSerializable:!0});let ee=e.createChannel({definitions:_,onError(e){f(`error`,e),i.emit(mx.client.connectionError,e),m(new Gw(`connection`,`[devframe] Connection to the devframe server failed`,{cause:e}))},onDisconnected(){l!==`error`&&f(`disconnected`),m(new Gw(`connection`,`[devframe] Disconnected from the devframe server`,{cause:u??void 0}))}}),te=iT(a.functions,{channel:ee,rpcOptions:o});a.register({name:mx.broadcast.authRevoked,type:`event`,handler:()=>{c=!1;let e=new Gw(`auth`,`[devframe] The devframe server revoked this client's trust`);f(`unauthorized`,e),i.emit(mx.client.connectionError,e),m(e),i.emit(mx.client.isTrustedUpdated,!1)}});let ne=n;async function re(e){ne=e;let t=await te.$call(`anonymous:devframe:auth`,{authToken:e,ua:navigator.userAgent,origin:location.origin});if(c=t.isTrusted,c)d.resolve(!0),f(`connected`);else{let e=new Gw(`auth`,`[devframe] The devframe server refused this client's credentials`);f(`unauthorized`,e),i.emit(mx.client.connectionError,e)}return i.emit(mx.client.isTrustedUpdated,c),t.isTrusted}async function ie(e){let t=(await te.$call(`anonymous:devframe:auth:exchange`,{code:e,ua:navigator.userAgent,origin:location.origin}))?.authToken??null;return t&&(ne=t,c=!0,d.resolve(!0),f(`connected`),i.emit(mx.client.isTrustedUpdated,!0)),t}async function ae(e={}){await te.$call(`anonymous:devframe:auth:request-code`,{ua:navigator.userAgent,origin:location.origin,...e.reissue?{reissue:!0}:{}})}async function oe(){return c?!0:re(ne??``)}async function se(e=6e4){if(c&&d.resolve(!0),e<=0)return d.promise;let t;try{return await Promise.race([d.promise,new Promise((n,r)=>{t=setTimeout(()=>{r(Error(`[devframe] Timeout waiting for rpc to be trusted`))},e)})]),c}finally{clearTimeout(t)}}return{transport:t,get isTrusted(){return c},get status(){return l},get connectionError(){return u},requestTrust:oe,requestTrustWithToken:re,requestTrustWithCode:ie,requestAuthCode:ae,ensureTrusted:se,call:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(mx.client.error,n,t),Promise.reject(n)):g(te.$call(...e),t)},callEvent:(...e)=>{let t=h();if(t){i.emit(mx.client.error,t,String(e[0]));return}return te.$callEvent(...e)},callOptional:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(mx.client.error,n,t),Promise.reject(n)):g(te.$callOptional(...e),t)},close:()=>{ee.close()}}}function oT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})();if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`;return new URL(e.path??`/`,`${r.protocol}//${t}`).href}return new URL(e.path??``,r).href}let i=e??``;return/^https?:\/\//i.test(i)?i:new URL(i,r).href}function sT(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},sseOptions:s={},callTimeout:c=0}=e,l=oT(n.sse,r??`./`,location);return aT({transport:`sse`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>rT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(){s.onConnected?.()},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(){e.onDisconnected(),s.onDisconnected?.()}})})}function cT(e){let{name:t,message:n,cause:r,...i}=e,a=r instanceof Error?r:lT(r)?cT(r):r,o=a===void 0?Error(n):Error(n,{cause:a});return o.name=t,Object.assign(o,i),o}function lT(e){return typeof e==`object`&&!!e&&typeof e.message==`string`&&typeof e.name==`string`}function uT(e){return typeof e==`object`&&!!e&&e.type===`static`&&typeof e.path==`string`}function dT(e){return typeof e==`object`&&!!e&&e.type===`query`&&typeof e.records==`object`&&e.records!==null}function fT(e){return typeof e==`object`&&!!e&&(`output`in e||`error`in e)}function pT(e){if(e.error)throw cT(e.error);return e.output}function mT(e){return e.some(e=>e!=null)}function hT(e){return typeof e==`object`&&e&&`serialization`in e&&`data`in e?e.data:e}function gT(e,t){let n=new Map,r=new Map;function i(e,t){return t===`structured-clone`&&Array.isArray(e)?QC(e):e}function a(e,t){return i(hT(e),t)}async function o(e){n.has(e.path)||n.set(e.path,t(e.path).then(t=>a(t,e.serialization)));let r=await n.get(e.path);return fT(r)?pT(r):r}async function s(e,n){return r.has(e)||r.set(e,t(e).then(e=>a(e,n))),await r.get(e)}async function c(t,n){if(!(t in e))throw Error(`[devframe-rpc] Function "${t}" not found in dump store`);let r=e[t];if(uT(r)){if(mT(n))throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`);return await o(r)}if(dT(r)){let e=qx(n),i=r.records[e];if(i)return pT(await s(i,r.serialization));if(r.fallback)return pT(await s(r.fallback,r.serialization));throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}if(!mT(n))return r;throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}return{call:async(e,t)=>await c(e,t),callOptional:async(t,n)=>{if(t in e)return await c(t,n)},callEvent:async(e,t)=>{}}}async function _T(e){let t=gT(await e.fetchJsonFromBases(hw),e.fetchJsonFromBases);return{transport:`static`,isTrusted:!0,status:`connected`,connectionError:null,requestTrust:async()=>!0,requestTrustWithToken:async()=>!0,requestTrustWithCode:async()=>null,requestAuthCode:async()=>{},ensureTrusted:async()=>!0,call:(...e)=>t.call(e[0],e.slice(1)),callEvent:(...e)=>t.callEvent(e[0],e.slice(1)),callOptional:(...e)=>t.callOptional(e[0],e.slice(1)),close:()=>{}}}var vT=``;function yT(e,t){return`${e}${vT}${t}`}function bT(e){let t=new Map,n=new Map;e.client.register({name:mx.broadcast.streamingChunk,type:`event`,handler(e,n,r,i){t.get(yT(e,n))?._push(r,i)}}),e.client.register({name:mx.broadcast.streamingEnd,type:`event`,handler(e,n,r){let i=yT(e,n),a=t.get(i);a&&(a._end(r),t.delete(i))}}),e.client.register({name:mx.broadcast.streamingUploadCancel,type:`event`,handler(e,t){let r=yT(e,t),i=n.get(r);i&&(i.abort(`server cancelled upload`),n.delete(r))}}),e.events.on(mx.client.isTrustedUpdated,n=>{if(n)for(let[n,r]of t){if(r.cancelled||r.done)continue;let t=n.indexOf(vT);if(t<0)continue;let i=n.slice(0,t),a=n.slice(t+1);e.callEvent(`devframe:streaming:subscribe`,i,a,{afterSeq:r.lastSeenSeq})}});function r(n,r,i={}){let a=yT(n,r),o=t.get(a);if(o)return o;let s=iw({id:r,highWaterMark:i.highWaterMark,onOverflow(e){console.warn(`[devframe] DF0029: Stream "${n}#${r}" dropped ${e} chunk(s) after exceeding the client high-water mark.`)},onCancel(){e.callEvent(`devframe:streaming:cancel`,n,r),t.delete(a)}});if(t.set(a,s),e.isTrusted)e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:0});else{let i=e.events.on(mx.client.isTrustedUpdated,o=>{o&&(i(),t.has(a)&&!s.cancelled&&!s.done&&e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:s.lastSeenSeq}))})}return s}function i(t,r){let i=yT(t,r),a=n.get(i);if(a)return a;let o=rw({id:r});return o.events.on(`chunk`,(n,i)=>{e.callEvent(`devframe:streaming:upload-chunk`,t,r,n,i)}),o.events.on(`end`,a=>{e.callEvent(`devframe:streaming:upload-end`,t,r,a),n.delete(i)}),n.set(i,o),o}return{subscribe:r,upload:i}}function xT(){}var ST=new Map;function CT(e){let t=e.url;e.authToken&&(t=`${t}?${vw}=${encodeURIComponent(e.authToken)}`);let n=new WebSocket(t),{onConnected:r=xT,onError:i=xT,onDisconnected:a=xT,definitions:o=ST}=e;n.addEventListener(`open`,e=>{r(e)}),n.addEventListener(`error`,e=>{let t=e instanceof Error?e:Error(e.type);i(t)}),n.addEventListener(`close`,e=>{a(e)});let s=$w(o);return{close:()=>{n.close()},on:e=>{n.addEventListener(`message`,t=>{e(t.data)})},post:e=>{if(n.readyState===WebSocket.OPEN){n.send(e);return}if(n.readyState===WebSocket.CONNECTING){let t=()=>{i(),n.readyState===WebSocket.OPEN&&n.send(e)},r=()=>i();function i(){n.removeEventListener(`open`,t),n.removeEventListener(`close`,r)}n.addEventListener(`open`,t),n.addEventListener(`close`,r);return}i(Error(`Devframe WebSocket is not open; message dropped`))},serialize:s.serialize,deserialize:s.deserialize}}function wT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})(),i=r.protocol===`https:`?`wss:`:`ws:`;if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`,n=new URL(e.path??`/`,`${i}//${t}`);return n.protocol=i,n.href}let t=new URL(e.path??``,r);return t.protocol=i,t.href}if(typeof e==`number`)return`${i}//${r.hostname}:${e}`;let a=e??``;if(/^wss?:\/\//i.test(a))return a;if(/^https?:\/\//i.test(a))return eS(a,/^https/i.test(a)?`wss://`:`ws://`);let o=new URL(a,r);return o.protocol=i,o.href}function TT(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},wsOptions:s={},callTimeout:c=0}=e,l=wT(n.websocket,r??`./`,location);return aT({transport:`websocket`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>CT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(e){s.onConnected?.(e)},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(t){e.onDisconnected(),s.onDisconnected?.(t)}})})}function ET(e){return e.includes(`:`)}function DT(e,t){return ET(t)?t:`${e}:${t}`}function OT(e){return{async get(t){return(await e()).value()[t]},async set(t,n){(await e()).mutate(e=>{e[t]=n})},async delete(t){(await e()).mutate(e=>{delete e[t]})},async all(){return(await e()).value()},async onChange(t){return(await e()).on(`updated`,e=>t(e))}}}function kT(e,t,n){let r=`devframe:settings:${n}:${t}`,i;function a(){return i||=e.sharedState.get(r,{initialValue:{}}),i}return OT(a)}function AT(e,t){return{global:kT(e,t,`global`),project:kT(e,t,`project`)}}function jT(e,t){return{namespace:t,base:e,rpc:{namespace:t,register(n){if(ET(n.name))throw Error(`[devframe] Scoped client RPC registration for namespace "${t}" received an already-namespaced function name "${n.name}". Pass a bare name without a ":" separator.`);e.client.register({...n,name:`${t}:${n.name}`})},call:((n,...r)=>e.call(DT(t,n),...r)),callEvent:((n,...r)=>e.callEvent(DT(t,n),...r)),callOptional:((n,...r)=>e.callOptional(DT(t,n),...r)),sharedState:((n,r)=>e.sharedState.get(DT(t,n),r)),streaming:{subscribe:(n,r,i)=>e.streaming.subscribe(DT(t,n),r,i),upload:(n,r)=>e.streaming.upload(DT(t,n),r)}},settings:AT(e,t),scope:e.scope}}function MT(){if(typeof document<`u`){let e=document.modelContext;if(e)return e}if(typeof navigator<`u`){let e=navigator.modelContext;if(e)return e}}function NT(e,t={}){let n=t.modelContext??MT();if(!n)return()=>{};let r=n,i=new Map,a=new Map;function o(t,n){let o=sw(t.name),s=a.get(o);if(s&&s!==t.name){console.warn(`[devframe] WebMCP tool name "${o}" (from "${t.name}") collides with "${s}"; keeping the first registration.`);return}let c=new AbortController,l=Ox(t.type,n),u=r.registerTool({name:o,description:n.description,inputSchema:jx(t.args),annotations:{title:n.title??t.name,readOnlyHint:l===`read`,destructiveHint:l===`destructive`},execute:n=>PT(t,e.context,n)},{signal:c.signal});u&&`then`in u&&u.then(()=>{},()=>{}),a.set(o,t.name),i.set(t.name,()=>{c.abort(),u&&`unregister`in u&&typeof u.unregister==`function`&&u.unregister(),a.delete(o)})}function s(t){let n=t?[t]:[...e.definitions.keys()];for(let t of n){i.get(t)?.(),i.delete(t);let n=e.definitions.get(t),r=n?.agent;n&&r&&o(n,r)}}s();let c=e.onChanged(e=>s(e));return()=>{c();for(let e of i.values())e();i.clear()}}async function PT(e,t,n){try{let r=Nx(n,e.args?.length);return{content:[{type:`text`,text:FT(await(await Dw(e,t))(...r))}]}}catch(e){return{isError:!0,content:[{type:`text`,text:IT(e)}]}}}function FT(e){return e===void 0?`undefined`:typeof e==`string`?e:JSON.stringify(e,null,2)}function IT(e){if(!(e instanceof Error))return String(e);let t=e.cause instanceof Error?` (cause: ${e.cause.message})`:``;return`${e.name}: ${e.message}${t}`}function LT(e,t){if(t.backend===`static`)return`static`;let n=t.websocket!==void 0,r=t.sse!==void 0;if(e===`websocket`){if(!n)throw Error(`[devframe] transport: 'websocket' was requested, but this server does not advertise a WebSocket endpoint`);return`websocket`}if(e===`sse`){if(!r)throw Error(`[devframe] transport: 'sse' was requested, but this server does not advertise an SSE endpoint`);return`sse`}if(t.backend===`sse`&&r)return`sse`;if(n)return`websocket`;if(r)return`sse`;throw Error(`[devframe] This server advertises no RPC transport (backend "none"), so there is nothing to connect to. Enable the WebSocket or SSE endpoint on the server, or use its static/MCP surfaces instead.`)}async function RT(e={}){let{baseURL:t=`./`,rpcOptions:n={},cacheOptions:r=!1}=e,i=Jx(),a=Array.isArray(t)?t:[t],o=await Ww(e),{connectionMeta:s,metaBaseUrl:c,authToken:l}=o,u=a[0]??`./`;try{u=new URL(`.`,c).href}catch{}let d=new yw({functions:[],...typeof e.cacheOptions==`object`?e.cacheOptions:{}}),f={rpc:void 0},p=new Ow(f),m=e.webmcp===!1?void 0:NT(p),h,g=!1;async function _(e){let t=[u,...a.filter(e=>e!==u)].filter(e=>e!=null),n=[];for(let r of t)try{return await fetch($x(e,r)).then(t=>{if(!t.ok)throw Error(`Failed to fetch ${e} from ${r}: ${t.status}`);return t.json()})}catch(e){n.push(e)}throw Error(`Failed to load ${e} from ${t.join(`, `)}`,{cause:n})}let ee={authToken:l,connectionMeta:s,metaBaseUrl:c,events:i,clientRpc:p,callTimeout:e.callTimeout,rpcOptions:{...n,async onRequest(e,t,i){if(await n.onRequest?.call(this,e,t,i),r&&d?.validate(e.m)){if(d.has(e.m,e.a))return i(d.cached(e.m,e.a));let n=await t(e);d.apply(e,n)}else await t(e)}}},te=LT(e.transport??`auto`,s),ne=te===`static`?await _T({fetchJsonFromBases:_}):te===`sse`?sT({...ee,sseOptions:e.sseOptions}):TT({...ee,wsOptions:e.wsOptions}),re;try{re=new BroadcastChannel(`devframe-auth`)}catch{}let ie,ae=!1;function oe(e){return((...t)=>ae||!ie?e(...t):ie.then(()=>e(...t)))}function se(){g=!0;try{h?.(),m?.()}finally{try{re?.close()}finally{ne.close?.()}}}let ce={events:i,get isTrusted(){return ne.isTrusted},get status(){return ne.status},get connectionError(){return ne.connectionError},get transport(){return ne.transport??te},get connection(){return o},connectionMeta:s,ensureTrusted:ne.ensureTrusted,requestTrust:ne.requestTrust,requestTrustWithToken:async e=>(Bw(e),o={...o,authToken:e},ne.requestTrustWithToken(e)),requestTrustWithCode:async e=>{let t=await ne.requestTrustWithCode(e);if(!t)return!1;Bw(t),o={...o,authToken:t};try{re?.postMessage({type:`auth-update`,authToken:t})}catch{}return!0},requestAuthCode:e=>ne.requestAuthCode(e),call:oe(ne.call),callEvent:oe(ne.callEvent),callOptional:oe(ne.callOptional),client:p,sharedState:void 0,services:void 0,streaming:void 0,cacheManager:d,scope:void 0,close:se};ce.sharedState=Zw(ce),ce.streaming=bT(ce),ce.services=Xw(ce);let le=new Map;ce.scope=(e=>{if(!e)return ce;let t=le.get(e);return t||(t=jT(ce,e),le.set(e,t)),t}),f.rpc=ce;function ue(){try{return typeof window<`u`&&window.self===window.top}catch{return!1}}async function de(){if(e.simpleAuth!==!1&&ue()&&typeof globalThis.prompt==`function`)for(await ce.requestAuthCode().catch(()=>{});!ce.isTrusted;){let e=globalThis.prompt(`devframe: enter the authentication code shown in your terminal`);if(e==null)return;let t=e.trim();if(t&&await ce.requestTrustWithCode(t))return}}async function fe(){let t=await ne.requestTrust(),n=e.otpParam??`devframe_otp`,r=n?await Yw(ce,{param:n}):!1;t||r||ce.isTrusted||await de()}return ie=fe().then(()=>{ae=!0},()=>{ae=!0}),s.mcp&&dw(async()=>{let{setupBrowserAgentRpcBridge:e}=await import(`./browser-agent-rpc-BXhoSh1z-DTULcebV.js`);return{setupBrowserAgentRpcBridge:e}},[],import.meta.url).then(({setupBrowserAgentRpcBridge:e})=>{g||(h=e(ce))}).catch(()=>{}),re&&(re.onmessage=e=>{e.data?.type===`auth-update`&&e.data.authToken&&ce.requestTrustWithToken(e.data.authToken)}),ce}var zT=RT,BT=[`components`,`injectors`,`signals`,`ngrx`,`forms`,`router`,`pipes`,`http`,`analog`,`capacitor`,`errors`],VT=[`angular`,`ngrx`,`analog`,`angular-native`,`nativescript`,`capacitor`];function HT(e){return`pangular:${e}`}var UT=[`forms`,`router`,`ngrx`,`http`,`analog`,`components`],WT={refreshMs:{default:3e3,min:500,max:8e3},navigations:{default:50,min:5,max:500},formTimeline:{default:200,min:10,max:2e3},httpCalls:{default:200,min:10,max:2e3},changeLog:{default:200,min:10,max:2e3},cdCycles:{default:200,min:10,max:2e3},capacitorCalls:{default:200,min:10,max:2e3}},GT={"opted-out":`the request sets transferCache: false`,post:`POST requests are left out unless includePostRequests is set`,method:`only GET, HEAD and POST requests are cached`,"auth-headers":`it sends an Authorization, Proxy-Authorization or Cookie header`,credentials:`it sends credentials (withCredentials or credentials: include/same-origin)`,"no-cache-request":`the request asks for no-store, no-cache or private`,"no-cache-response":`the response has Cache-Control no-store, no-cache or private`,"set-cookie":`the response sets a cookie`,error:`failed responses are not stored`,mocked:`a fault rule answered before the transfer cache ran`,"cache-off-or-filter":`the transfer cache is off, or its filter (or another withHttpTransferCacheOptions setting) left it out`},KT=[[200,`OK`],[201,`Created`],[202,`Accepted`],[203,`Non-Authoritative Information`],[204,`No Content`],[205,`Reset Content`],[206,`Partial Content`],[207,`Multi-Status`],[208,`Already Reported`],[226,`IM Used`],[300,`Multiple Choices`],[301,`Moved Permanently`],[302,`Found`],[303,`See Other`],[304,`Not Modified`],[307,`Temporary Redirect`],[308,`Permanent Redirect`],[400,`Bad Request`],[401,`Unauthorized`],[402,`Payment Required`],[403,`Forbidden`],[404,`Not Found`],[405,`Method Not Allowed`],[406,`Not Acceptable`],[407,`Proxy Authentication Required`],[408,`Request Timeout`],[409,`Conflict`],[410,`Gone`],[411,`Length Required`],[412,`Precondition Failed`],[413,`Content Too Large`],[414,`URI Too Long`],[415,`Unsupported Media Type`],[416,`Range Not Satisfiable`],[417,`Expectation Failed`],[418,`I'm a Teapot`],[421,`Misdirected Request`],[422,`Unprocessable Content`],[423,`Locked`],[424,`Failed Dependency`],[425,`Too Early`],[426,`Upgrade Required`],[428,`Precondition Required`],[429,`Too Many Requests`],[431,`Request Header Fields Too Large`],[451,`Unavailable For Legal Reasons`],[499,`Client Closed Request`],[500,`Internal Server Error`],[501,`Not Implemented`],[502,`Bad Gateway`],[503,`Service Unavailable`],[504,`Gateway Timeout`],[505,`HTTP Version Not Supported`],[506,`Variant Also Negotiates`],[507,`Insufficient Storage`],[508,`Loop Detected`],[510,`Not Extended`],[511,`Network Authentication Required`],[520,`Web Server Returned an Unknown Error`],[521,`Web Server Is Down`],[522,`Connection Timed Out`],[523,`Origin Is Unreachable`],[524,`A Timeout Occurred`]];function qT(e){return KT.some(([t])=>t===e)}var JT=`pangular`,YT={mod:`Mod`,ctrl:`Ctrl`,control:`Ctrl`,meta:`Meta`,cmd:`Meta`,command:`Meta`,alt:`Alt`,option:`Alt`,opt:`Alt`,shift:`Shift`},XT=[`Mod`,`Ctrl`,`Meta`,`Alt`,`Shift`];function ZT(e){if(typeof e!=`string`||e.length>40)return;let t=e.split(`+`).map(e=>e.trim());if(t.some(e=>!e))return;let n=new Set,r;for(let e of t){let t=YT[e.toLowerCase()];if(t){if(n.has(t))return;n.add(t);continue}if(r!==void 0)return;if(/^[a-z0-9]$/i.test(e))r=e.toUpperCase();else if(/^f([1-9]|1[0-2])$/i.test(e))r=e.toUpperCase();else return}if(r&&[...n].some(e=>e!==`Shift`)&&!(n.has(`Mod`)&&(n.has(`Ctrl`)||n.has(`Meta`))))return[...XT.filter(e=>n.has(e)),r].join(`+`)}function QT(e,t,n){let r=t.split(`+`),i=r.pop(),a=new Set(r),o=a.has(`Ctrl`)||a.has(`Mod`)&&!n,s=a.has(`Meta`)||a.has(`Mod`)&&n;if(e.ctrlKey!==o||e.metaKey!==s||e.altKey!==a.has(`Alt`)||e.shiftKey!==a.has(`Shift`))return!1;if(/^F\d+$/.test(i))return e.key.toUpperCase()===i;let c=/^\d$/.test(i)?`Digit${i}`:`Key${i}`;return e.code?e.code===c:e.key.toUpperCase()===i}function $T(e,t){if(!t)return e.replace(/^Mod\b/,`Ctrl`);let n={Mod:`⌘`,Meta:`⌘`,Ctrl:`⌃`,Alt:`⌥`,Shift:`⇧`};return e.split(`+`).map(e=>n[e]??e).join(``)}var eE=[{id:`dashboard`,label:`Dashboard`},{id:`analog`,label:`Analog`,inspector:`analog`},{id:`components`,label:`Components`,inspector:`components`},{id:`routes`,label:`Routes`,inspector:`router`},{id:`signals`,label:`Signals`,inspector:`signals`},{id:`injectors`,label:`Injectors`,inspector:`injectors`},{id:`store`,label:`Store`,inspector:`ngrx`},{id:`forms`,label:`Forms`,inspector:`forms`},{id:`pipes`,label:`Pipes`,inspector:`pipes`},{id:`network`,label:`SSR & HTTP`,inspector:`http`},{id:`errors`,label:`Errors`,inspector:`errors`},{id:`capacitor`,label:`Capacitor`,inspector:`capacitor`}];function tE(e){return eE.filter(t=>!(`inspector`in t)||e.inspectors[t.inspector])}var nE={components:`a component instance, by its id in the component tree`,injectors:`a component's element injector, by the component's id`,forms:`a form, by its id`},rE=200;function iE(e){let t=new URLSearchParams({tab:e.tab});return e.id&&t.set(`id`,e.id),e.page&&t.set(`page`,e.page),`#${t.toString()}`}function aE(e){let t=new URLSearchParams(e.replace(/^#/,``)),n=e=>{let n=t.get(e)?.trim();return n&&n.length<=rE?n:void 0},r=n(`tab`);if(!r)return null;let i=n(`id`),a=n(`page`);return{tab:r,...i?{id:i}:{},...a?{page:a}:{}}}var oE=[{id:`settings`,title:`Open settings`,group:`Go to`,keywords:`preferences tabs`},{id:`pick-component`,title:`Pick component on page`,group:`Actions`,keywords:`select inspect element`,inspector:`components`},{id:`cd-record-start`,title:`Start recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-record-stop`,title:`Stop recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-clear`,title:`Clear change detection recording`,group:`Actions`,keywords:`reset recordings cycles`,inspector:`components`},{id:`theme:system`,title:`Theme: follow the system`,group:`Theme`,keywords:`auto`},{id:`theme:light`,title:`Theme: light`,group:`Theme`},{id:`theme:dark`,title:`Theme: dark`,group:`Theme`},{id:`dock:float`,title:`Popup: float`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:bottom`,title:`Popup: dock to the bottom`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:right`,title:`Popup: dock to the right`,group:`Popup`,keywords:`dock`,popupOnly:!0}];function sE(e){let t=tE(e).map(e=>({id:`tab:${e.id}`,title:`Go to ${e.label}`,group:`Go to`,keywords:`tab open`})),n=oE.filter(t=>!t.inspector||e.inspectors[t.inspector]).map(({inspector:e,...t})=>t);return[...t,...n]}function cE(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}function lE(e,t){return typeof e==`boolean`?e:t}var uE=100,dE=100;function fE(e){if(!Array.isArray(e))return[];let t=e.filter(e=>typeof e==`string`).map(e=>e.trim()).filter(e=>e&&e.length<=dE);return[...new Set(t)].slice(0,uE)}function pE(e,t){let{default:n,min:r,max:i}=WT[t];return typeof e!=`number`||!Number.isFinite(e)?n:Math.min(i,Math.max(r,Math.round(e)))}function mE(e,t){return Object.fromEntries(e.map(e=>[e,t(e)]))}function hE(e){let t=cE(e),n=cE(t.agent),r=cE(t.inspectors),i=cE(n.tools),a=cE(t.actions),o=lE(t.actions,!0),s=cE(t.redaction),c=cE(t.limits),l=mE(BT,e=>lE(r[e],!0));return{inspectors:l,agent:{readOnly:lE(n.readOnly,!1),tools:mE(BT,e=>l[e]&&lE(i[e],!0))},actions:mE(UT,e=>l[e]&&lE(a[e],o)),redaction:{secretNames:fE(s.secretNames),unmask:fE(s.unmask)},limits:Object.fromEntries(Object.keys(WT).map(e=>[e,pE(c[e],e)])),popup:{hotkey:gE(cE(t.popup).hotkey)}}}function gE(e){return e===!1?!1:ZT(e)??`Alt+Shift+P`}function _E(e){let t=e?.configs;return hE(t?.[JT])}function vE(e){return`${{forms:`Writing to forms`,router:`Navigating and clearing navigations`,ngrx:`Restoring NgRx state and dispatching actions`,http:`Changing HTTP mock rules and clearing HTTP calls`,analog:`Calling API routes and clearing server calls`,components:`Editing component properties and signals`}[e]} is turned off in the devtools config (actions.${e}).`}var yE={components:`Components`,injectors:`Injectors`,signals:`Signals`,ngrx:`NgRx`,forms:`Forms`,router:`Router`,pipes:`Pipes`,http:`HTTP`,analog:`Analog`,capacitor:`Capacitor`,errors:`Errors`},bE={forms:`Form writes`,router:`Navigation`,ngrx:`NgRx restore and dispatch`,http:`HTTP mocking`,analog:`Analog API calls`,components:`Component edits`},xE={refreshMs:e=>`poll every ${e} ms`,navigations:e=>`${e} navigations`,formTimeline:e=>`${e} form events`,httpCalls:e=>`${e} HTTP calls`,changeLog:e=>`${e} NgRx changes`,cdCycles:e=>`${e} change detection cycles`,capacitorCalls:e=>`${e} Capacitor plugin calls`};function SE(e){let t=[],n=(e,n)=>{n.length&&t.push({label:e,value:n.join(`, `)})},r=BT.filter(t=>e.inspectors[t]);return n(`Inspectors off`,BT.filter(t=>!e.inspectors[t]).map(e=>yE[e])),n(`Agent`,e.agent.readOnly?[`Read-only`]:[]),n(`Hidden from the agent`,r.filter(t=>!e.agent.tools[t]).map(e=>yE[e])),n(`Blocked actions`,UT.filter(t=>e.inspectors[t]&&!e.actions[t]).map(e=>bE[e])),n(`Extra secret names`,e.redaction.secretNames),n(`Unmasked names`,e.redaction.unmask),n(`Limits`,Object.keys(WT).filter(t=>e.limits[t]!==WT[t].default).map(t=>xE[t](e.limits[t]))),e.popup.hotkey!==`Alt+Shift+P`&&n(`Popup shortcut`,[e.popup.hotkey===!1?`Off`:e.popup.hotkey]),t}function CE(e){let t={tags:[],directives:[],text:``},n=e.toLowerCase();return n=n.replace(/<\s*([^<>\s]+)\s*>/g,(e,n)=>(t.tags.push({value:n,exact:!0}),` `)),n=n.replace(/\[\s*([^[\]\s]+)\s*\]/g,(e,n)=>(t.directives.push({value:n,exact:!0}),` `)),n=n.replace(/(^|\s)([<[])([^<>[\]\s]*)$/,(e,n,r,i)=>(i&&(r===`<`?t.tags:t.directives).push({value:i,exact:!1}),n)),t.text=n.replace(/\s+/g,` `).trim(),t}function wE(e){return!e.tags.length&&!e.directives.length&&!e.text}function TE(e,t){let n=e.tag.toLowerCase(),r=(e.directives??[]).map(e=>e.toLowerCase()),i=(e.attributes??[]).map(e=>e.toLowerCase()),a=[...r,...r.map(e=>e.replace(/directive$/,``)),...i];for(let{value:e,exact:r}of t.tags)if(r?n!==e:!n.startsWith(e))return!1;for(let{value:e,exact:n}of t.directives)if(!a.some(t=>n?t===e:t.includes(e)))return!1;if(t.text){let a=t.text;if(!(e.name.toLowerCase().includes(a)||n.includes(a)||r.some(e=>e.includes(a))||i.some(e=>e.includes(a))))return!1}return!0}var EE=`pangular-page-id`,DE=null;function OE(e){DE=e}function kE(){if(DE)return DE;try{return new URLSearchParams(location.search).get(`pageId`)||(window.top===window?null:sessionStorage.getItem(EE)||null)}catch{return null}}function AE(e,t){if(t.chosen&&e[t.chosen])return t.chosen;if(t.host)return t.host;if(t.previous&&e[t.previous])return t.previous;let n=null;for(let t of Object.values(e))(!n||t.reportedAt>n.reportedAt)&&(n=t);return n?.pageId??null}function jE(e,t){return e?t?e.pages?.[t]??null:e:null}function ME(e,t){return e?t?e.pages?.[t]??null:e.graph??null:null}function NE(e,t,n){return e?e.scope(`pangular`).rpc.call(t,...n===void 0?[]:[n]):Promise.resolve(null)}function PE(e,t,n){return NE(e,t,n).then(e=>e,()=>null)}function FE(e){return e?.connectionMeta.backend===`static`}function IE(e){let t=()=>{let t=e()?.scope(`pangular`).rpc;t&&(t.callEvent(`request-page-highlight`,null),t.callEvent(`request-form-highlight`,null))};return addEventListener(`pagehide`,t),()=>{removeEventListener(`pagehide`,t),t()}}function LE(e){return e.split(`@`)[1]??``}var RE={signal:`Signal Forms`,reactive:`Reactive`,template:`Template-driven`},zE={own:`validator`,directive:`template attribute`,tree:`cross-field rule`,async:`async`,parse:`parse`,submission:`server`,schema:`schema`,manual:`setErrors`},BE=PE,VE={key:`name looks secret`,"input-type":`password input`,autocomplete:`autocomplete is a secret kind`,marker:`marked as mask`,parent:`inside a secret group`,config:`listed in mask`};function HE(e){return VE[e]??e}var UE=`https://pangular-inspector.dev/security/#opt-fields-in-or-out`;async function WE(e,t){return await BE(e,`request-form-action`,t)??{ok:!1,error:`The devtools server did not answer.`}}function GE(e){return`${e.ok?e.message??`Done.`:e.error??`Failed.`}${e.skipped?.length?` Skipped: ${e.skipped.map(e=>`${e.path} (${e.reason})`).join(`, `)}.`:``}${e.status?` Status: ${e.status}.`:``}`}var KE=/"(?:[^"\\\n]|\\.)*"|`([^`\n]*)`|\*\*/g;function qE(e){return(e??``).replace(/^_Labels, paths.*_\n\n/,``).replace(KE,(e,t)=>t??(e===`**`?``:e))}function JE(e){return _E(e?.connectionMeta)}function YE(e,t){return JE(e).actions[t]}var XE={components:`components`,routes:`router`,signals:`signals`,injectors:`injectors`,store:`ngrx`,forms:`forms`,pipes:`pipes`,network:`http`,analog:`analog`,capacitor:`capacitor`,errors:`errors`};function ZE(e){return XE[e]}var QE=`https://pangular-inspector.dev/getting-started/configuration/#inspectors-and-agent-tools`;function $E(e,t){let n=XE[e];return!n||t.inspectors[n]}function eD(e,t){e&1&&(O(),Vg(0,`rect`,4)(1,`rect`,5)(2,`rect`,6)(3,`rect`,7))}function tD(e,t){e&1&&(O(),Vg(0,`path`,8)(1,`path`,9)(2,`path`,10))}function nD(e,t){e&1&&(O(),Vg(0,`circle`,11)(1,`path`,12)(2,`circle`,13))}function rD(e,t){e&1&&(O(),Vg(0,`path`,1))}function iD(e,t){e&1&&(O(),Vg(0,`path`,14)(1,`path`,15)(2,`path`,16)(3,`path`,17))}function aD(e,t){e&1&&(O(),Vg(0,`ellipse`,18)(1,`path`,19)(2,`path`,20))}function oD(e,t){e&1&&(O(),Vg(0,`rect`,21)(1,`path`,22)(2,`path`,23)(3,`path`,24))}function sD(e,t){e&1&&(O(),Vg(0,`circle`,25)(1,`path`,26)(2,`path`,27))}function cD(e,t){e&1&&(O(),Vg(0,`path`,28)(1,`path`,29)(2,`path`,30)(3,`path`,31)(4,`circle`,32))}function lD(e,t){e&1&&(O(),Vg(0,`circle`,33)(1,`path`,34))}function uD(e,t){e&1&&(O(),Vg(0,`circle`,25)(1,`path`,35)(2,`path`,36))}function dD(e,t){e&1&&(O(),Vg(0,`path`,2))}function fD(e,t){e&1&&(O(),Vg(0,`path`,3))}var pD=class e{name=$.required();static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-tab-icon`]],inputs:{name:[1,`name`]},decls:14,vars:1,consts:[[`viewBox`,`0 0 24 24`,`width`,`16`,`height`,`16`,`fill`,`none`,`stroke`,`currentColor`,`stroke-width`,`1.8`,`stroke-linecap`,`round`,`stroke-linejoin`,`round`,`aria-hidden`,`true`],[`d`,`M22 12h-4l-3 9L9 3l-3 9H2`],[`d`,`m8 3 4 8 5-5 5 15H2L8 3z`],[`fill`,`currentColor`,`stroke`,`none`,`transform`,`translate(1.8 1.8) scale(0.85)`,`d`,`M24 3.7l-5.766 5.766 5.725 5.736-3.713 3.712L5.073 3.742 8.786.03l5.736 5.726L20.284 0 24 3.7zM.029 8.785l3.713-3.713 15.173 15.173-3.713 3.714-5.732-5.726L3.7 24 0 20.285l5.754-5.764L.029 8.785z`],[`x`,`3`,`y`,`3`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`14`,`y`,`3`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`x`,`14`,`y`,`12`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`3`,`y`,`16`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`d`,`M12 2 3 7l9 5 9-5-9-5Z`],[`d`,`m3 12 9 5 9-5`],[`d`,`m3 17 9 5 9-5`],[`cx`,`6`,`cy`,`19`,`r`,`3`],[`d`,`M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15`],[`cx`,`18`,`cy`,`5`,`r`,`3`],[`d`,`M12 22v-5`],[`d`,`M9 8V2`],[`d`,`M15 8V2`],[`d`,`M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z`],[`cx`,`12`,`cy`,`5`,`rx`,`9`,`ry`,`3`],[`d`,`M3 5v14a9 3 0 0 0 18 0V5`],[`d`,`M3 12a9 3 0 0 0 18 0`],[`x`,`3`,`y`,`4`,`width`,`18`,`height`,`16`,`rx`,`2`],[`d`,`M7 9h10`],[`d`,`M7 13h6`],[`d`,`M7 17h8`],[`cx`,`12`,`cy`,`12`,`r`,`9`],[`d`,`M3 12h18`],[`d`,`M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18Z`],[`d`,`M4 7h10`],[`d`,`M4 17h6`],[`d`,`m14 13 4 4-4 4`],[`d`,`M10 17h8`],[`cx`,`18`,`cy`,`7`,`r`,`3`],[`cx`,`12`,`cy`,`12`,`r`,`3`],[`d`,`M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1Z`],[`d`,`M12 7v6`],[`d`,`M12 16.5v.01`]],template:function(e,t){if(e&1&&(O(),B(0,`svg`,0),M(1,eD,4,0)(2,tD,3,0)(3,nD,3,0)(4,rD,1,0,`:svg:path`,1)(5,iD,4,0)(6,aD,3,0)(7,oD,4,0)(8,sD,3,0)(9,cD,5,0)(10,lD,2,0)(11,uD,3,0)(12,dD,1,0,`:svg:path`,2)(13,fD,1,0,`:svg:path`,3),V()),e&2){let e;A(),N((e=t.name())===`dashboard`?1:e===`components`?2:e===`routes`?3:e===`signals`?4:e===`injectors`?5:e===`store`?6:e===`forms`?7:e===`network`?8:e===`pipes`?9:e===`settings`?10:e===`errors`?11:e===`analog`?12:e===`capacitor`?13:-1)}},styles:[`[_nghost-%COMP%] { display: inline-flex; flex-shrink: 0; -}`]})},QE=(e,t)=>t.tab,$E=(e,t)=>t.label;function eD(e,t){e&1&&J(0),e&2&&X(` `,G().meta()?.projectName,` `)}function tD(e,t){e&1&&J(0,` Project details unavailable `)}function nD(e,t){e&1&&J(0,` Loading… `)}function rD(e,t){e&1&&(J(0,` Run `),L(1,`code`),J(2,`pangular build`),R(),J(3,` again to rebuild the report. `))}function iD(e,t){e&1&&J(0,` Check that the dev server is running. `)}function aD(e,t){if(e&1){let e=H();L(0,`button`,12),U(`click`,function(){return E(e),D(G(2).loadMeta())}),J(1,`Try again`),R()}}function oD(e,t){if(e&1&&(L(0,`p`,10),M(1,rD,4,0)(2,iD,1,0),R(),M(3,aD,2,0,`button`,11)),e&2){let e=G();A(),N(e.staticReport()?1:2),A(2),N(e.staticReport()?-1:3)}}function sD(e,t){e&1&&(L(0,`li`,5)(1,`span`),J(2,`Analog`),R(),J(3),R()),e&2&&(A(3),Y(t))}function cD(e,t){e&1&&(L(0,`li`)(1,`span`),J(2,`Change detection`),R(),J(3),R()),e&2&&(A(3),Y(t))}function lD(e,t){if(e&1&&(L(0,`span`,19),J(1),R(),L(2,`span`,20),J(3),R()),e&2){let e=G().$implicit,t=G();A(),Y(t.cards()[e.tab]?.value),A(2),Y(t.cards()[e.tab]?.sub)}}function uD(e,t){e&1&&(L(0,`span`,21),J(1,`–`),R(),L(2,`span`,20),J(3,`Count unavailable`),R())}function dD(e,t){e&1&&(z(0,`span`,22),L(1,`span`,20),J(2,`Counting…`),R())}function fD(e,t){if(e&1){let e=H();L(0,`button`,13),U(`click`,function(){let t=E(e).$implicit;return D(G().navigate.emit(t.tab))}),L(1,`span`,14)(2,`span`,15),z(3,`app-tab-icon`,16),R(),L(4,`span`,17),J(5,`→`),R()(),L(6,`span`,18),J(7),R(),M(8,lD,4,2)(9,uD,4,0)(10,dD,3,0),R()}if(e&2){let e,n=t.$implicit,r=t.$index,i=G().stateOf(n.tab);K(`animation-delay`,60*r,`ms`),j(`aria-busy`,i===`loading`),A(3),I(`name`,n.tab),A(4),Y(n.label),A(),N((e=i)===`ready`?8:e===`error`?9:10)}}function pD(e,t){e&1&&(L(0,`p`),J(1,`Loading…`),R())}function mD(e,t){if(e&1&&(L(0,`div`)(1,`dt`),J(2),R(),L(3,`dd`),J(4),R()()),e&2){let e=t.$implicit;A(2),Y(e.label),A(2),Y(e.value)}}function hD(e,t){if(e&1&&(L(0,`dl`),P(1,mD,5,2,`div`,null,$E),R()),e&2){let e=G();A(),F(e.configItems())}}function gD(e,t){e&1&&(L(0,`p`),J(1,`Defaults`),R())}var _D=[{tab:`components`,label:`Components`},{tab:`routes`,label:`Routes`},{tab:`signals`,label:`Signals`},{tab:`injectors`,label:`Injectors`},{tab:`store`,label:`NgRx declarations`},{tab:`pipes`,label:`Pipes`},{tab:`forms`,label:`Forms`},{tab:`network`,label:`SSR & HTTP`}];function vD(e){return _D.filter(t=>zE(t.tab,e))}var yD={zoneless:`Zoneless`,zone:`zone.js`,"zone-unused":`Zoneless, zone.js loaded`};function bD(e){return e&&Object.hasOwn(yD,e)?yD[e]:null}var xD=new Set([`signal`,`computed`,`linkedSignal`,`effect`]),SD={action:[`action`,`actions`],reducer:[`reducer`,`reducers`],effect:[`effect`,`effects`],selector:[`selector`,`selectors`],feature:[`feature`,`features`],"store-setup":[`setup call`,`setup calls`],"signal-store":[`signal store`,`signal stores`],"signal-state":[`signal state`,`signal states`],"signal-method":[`signal method`,`signal methods`]};function CD(e,t,n){return`${e} ${e===1?t:n}`}function wD(e,t){for(let n of e??[])t(n),wD(n.children,t)}function TD(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`discovered in source`};let t=e.filter(e=>e.kind===`directive`).length;return{value:e.length-t,sub:`components · ${CD(t,`directive`,`directives`)}`}}function ED(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`route entries in source`};let t=e.filter(e=>e.kind===`redirect`).length;return{value:new Set(e.filter(e=>e.kind===`page`).map(e=>e.fullPath??e.path??``)).size,sub:`navigable paths · ${CD(t,`redirect`,`redirects`)}`}}function DD(e){let t=new Map;for(let n of e)n.kind&&t.set(n.kind,(t.get(n.kind)??0)+1);if(!t.size)return{value:e.length,sub:`declarations in source`};let n=[...t].sort((e,t)=>t[1]-e[1]).map(([e,t])=>{let[n,r]=SD[e]??[e,e];return CD(t,n,r)});return{value:e.length,sub:n.join(` · `)}}function OD(e,t){let n=e?.forms??[],r=t?n.filter(e=>CE(e.id)===t):n;if(!r.length)return{value:0,sub:`no forms on the page yet`};let i=r.filter(e=>e.root?.status===`INVALID`).length;return{value:r.length,sub:`${r.length===1?`form`:`forms`} · ${i} invalid`}}function kD(e){return e.cancelled||e.status===void 0?!1:e.status===0||e.status>=400}function AD(e,t){let n=e?.pages??[],r=t?n.find(e=>e.pageId===t)??null:n.reduce((e,t)=>!e||t.reportedAt>e.reportedAt?t:e,null),i=t&&!r?[]:e?.serverCalls??[],a=r?.initialUrl,o=[...a?i.filter(e=>!e.pageUrl||e.pageUrl===a):i,...r?.calls??[]];if(!o.length)return{value:0,sub:`no calls recorded yet`};let s=o.filter(kD).length;return{value:o.length,sub:`${o.length===1?`call`:`calls`} · ${s} failed`}}var jD=class e{rpc=$(null);navigate=Rv();staticReport=Q(()=>xE(this.rpc()));meta=k(null);config=Q(()=>PE(this.rpc()));stats=Q(()=>this.rpc()?vD(this.config()):[]);configItems=Q(()=>cE(this.config()));metaState=k(`loading`);states=k({});rows=k({});injectorTree=k(null);signalGraph=k(null);formsState=k(null);httpState=k(null);pageId=hE();destroyRef=w(Es);stopLive=[];zone=Q(()=>bD(_E(this.injectorTree(),this.pageId)?.zone));liveInjectors=Q(()=>{let e=_E(this.injectorTree(),this.pageId);if(!e?.roots?.length)return null;let t=0,n=0,r=e=>{t++,n+=e.providers?.length??0};return wD(e.roots,r),wD(e.environment,r),{injectors:t,providers:n}});liveSignals=Q(()=>{let e=vE(this.signalGraph(),this.pageId);return e?.nodes?.length?e.nodes.filter(e=>xD.has(e.kind??``)).length:null});cards=Q(()=>{let e=this.rows(),t={};if(e.components&&(t.components=TD(e.components)),e.routes&&(t.routes=ED(e.routes)),e.store&&(t.store=DD(e.store)),e.pipes){let n=e.pipes.filter(e=>e.builtin).length;t.pipes={value:e.pipes.length-n,sub:n?`custom pipes · ${n} built-in in use`:`custom pipes in source`}}let n=this.liveSignals();n===null?e.signals&&(t.signals={value:e.signals.length,sub:`signal declarations in source`}):t.signals={value:n,sub:e.signals?`live on the page · ${e.signals.length} declared in source`:`live on the page`};let r=this.liveInjectors();r?t.injectors={value:r.injectors,sub:`live injectors · ${CD(r.providers,`provider`,`providers`)}`}:e.injectors&&(t.injectors={value:e.injectors.filter(e=>e.type!==`injection`).length,sub:`provider declarations in source`});let i=this.formsState();i&&(t.forms=OD(i,this.pageId));let a=this.httpState();return a&&(t.network=AD(a,this.pageId)),t});loadMeta(e=this.rpc()){e&&(this.metaState.set(`loading`),e.scope(`pangular`).rpc.call(`build-meta`).then(t=>{this.rpc()===e&&(this.meta.set(t),this.metaState.set(`ready`))}).catch(()=>{this.rpc()===e&&this.metaState.set(`error`)}))}constructor(){pc(()=>{let e=this.rpc();if(!e)return;let t=e.scope(`pangular`);this.states.set({}),this.rows.set({}),this.formsState.set(null),this.httpState.set(null),this.loadMeta(e);let n=PE(e),r=e=>zE(e,n);r(`components`)&&this.load(t.rpc.call(`get-components`),`components`),r(`routes`)&&this.load(t.rpc.call(`get-routes`),`routes`),r(`signals`)&&this.load(t.rpc.call(`get-signals`),`signals`),r(`injectors`)&&this.load(t.rpc.call(`get-providers`),`injectors`),r(`store`)&&this.load(t.rpc.call(`get-ngrx-store`),`store`),r(`pipes`)&&this.load(t.rpc.call(`get-pipes`),`pipes`),this.watchLive(e,n)}),this.destroyRef.onDestroy(()=>this.unwatch())}stateOf(e){return(e===`signals`?this.liveSignals():e===`injectors`?this.liveInjectors():null)===null?this.states()[e]??`loading`:`ready`}load(e,t){let n=e=>this.states.update(n=>({...n,[t]:e}));e.then(e=>{this.rows.update(n=>({...n,[t]:Array.isArray(e)?e:[]})),n(`ready`)}).catch(()=>n(`error`))}async watchLive(e,t){this.unwatch();let n=e.scope(`pangular`).rpc,r=async(t,r,i)=>{let a=e=>i&&this.states.update(t=>({...t,[i]:e}));try{let i=await n.sharedState(t);if(this.destroyRef.destroyed||this.rpc()!==e)return;r(i.value()),a(`ready`),this.stopLive.push(i.on(`updated`,e=>r(e)))}catch{if(this.destroyRef.destroyed||this.rpc()!==e)return;r(null),a(`error`)}};await Promise.all([t.inspectors.injectors&&r(`injector-tree`,e=>this.injectorTree.set(e)),t.inspectors.signals&&r(`signal-graph`,e=>this.signalGraph.set(e)),zE(`forms`,t)&&r(`forms`,e=>this.formsState.set(e??{}),`forms`),zE(`network`,t)&&r(`http`,e=>this.httpState.set(e??{}),`network`)])}unwatch(){for(let e of this.stopLive.splice(0))e()}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-dashboard`]],inputs:{rpc:[1,`rpc`]},outputs:{navigate:`navigate`},decls:33,vars:14,consts:[[`aria-labelledby`,`project-title`,1,`project`],[1,`project-head`],[1,`eyebrow`],[`id`,`project-title`],[1,`chips`],[1,`analog`],[1,`grid`],[`type`,`button`,1,`stat`,3,`animation-delay`],[`aria-labelledby`,`config-title`,1,`config`],[`id`,`config-title`],[1,`hint`],[`type`,`button`,1,`retry`],[`type`,`button`,1,`retry`,3,`click`],[`type`,`button`,1,`stat`,3,`click`],[1,`top`],[1,`icon`],[3,`name`],[`aria-hidden`,`true`,1,`go`],[1,`label`],[1,`big`],[1,`sub`],[1,`big`,`muted`],[`aria-hidden`,`true`,1,`big`,`skeleton`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`p`,2),J(3,`Project`),R(),L(4,`h2`,3),M(5,eD,1,1)(6,tD,1,0)(7,nD,1,0),R(),M(8,oD,4,2),R(),L(9,`ul`,4)(10,`li`)(11,`span`),J(12,`Angular`),R(),J(13),R(),L(14,`li`)(15,`span`),J(16,`TypeScript`),R(),J(17),R(),L(18,`li`)(19,`span`),J(20,`SSR`),R(),J(21),R(),M(22,sD,4,1,`li`,5),M(23,cD,4,1,`li`),R()(),L(24,`div`,6),P(25,fD,11,6,`button`,7,QE),R(),L(27,`section`,8)(28,`h2`,9),J(29,`Configuration`),R(),M(30,pD,2,0,`p`)(31,hD,3,0,`dl`)(32,gD,2,0,`p`),R()),e&2){let e,n,r;j(`aria-busy`,t.metaState()===`loading`),A(4),q(`muted`,t.metaState()!==`ready`),A(),N((e=t.metaState())===`ready`?5:e===`error`?6:7),A(3),N(t.metaState()===`error`?8:-1),A(),q(`pending`,t.metaState()===`loading`),A(4),Y(t.meta()?.angularVersion??`…`),A(4),Y(t.meta()?.typescript??`…`),A(4),Y(t.meta()?t.meta()?.ssr?`On`:`Off`:`…`),A(),N((n=t.meta()?.analog)?22:-1,n),A(),N((r=t.zone())?23:-1,r),A(2),F(t.stats()),A(2),j(`aria-busy`,!t.rpc()),A(3),N(t.rpc()?t.configItems().length?31:32:30)}},dependencies:[ZE],styles:[`[_nghost-%COMP%] { +}`]})},mD=(e,t)=>t.tab,hD=(e,t)=>t.label;function gD(e,t){e&1&&J(0),e&2&&X(` `,G().meta()?.projectName,` `)}function _D(e,t){e&1&&J(0,` Project details unavailable `)}function vD(e,t){e&1&&J(0,` Loading… `)}function yD(e,t){e&1&&(J(0,` Run `),L(1,`code`),J(2,`pangular build`),R(),J(3,` again to rebuild the report. `))}function bD(e,t){e&1&&J(0,` Check that the dev server is running. `)}function xD(e,t){if(e&1){let e=H();L(0,`button`,12),U(`click`,function(){return E(e),D(G(2).loadMeta())}),J(1,`Try again`),R()}}function SD(e,t){if(e&1&&(L(0,`p`,10),M(1,yD,4,0)(2,bD,1,0),R(),M(3,xD,2,0,`button`,11)),e&2){let e=G();A(),N(e.staticReport()?1:2),A(2),N(e.staticReport()?-1:3)}}function CD(e,t){e&1&&(L(0,`li`,5)(1,`span`),J(2,`Analog`),R(),J(3),R()),e&2&&(A(3),Y(t))}function wD(e,t){e&1&&(L(0,`li`)(1,`span`),J(2,`Change detection`),R(),J(3),R()),e&2&&(A(3),Y(t))}function TD(e,t){if(e&1&&(L(0,`span`,19),J(1),R(),L(2,`span`,20),J(3),R()),e&2){let e=G().$implicit,t=G();A(),Y(t.cards()[e.tab]?.value),A(2),Y(t.cards()[e.tab]?.sub)}}function ED(e,t){e&1&&(L(0,`span`,21),J(1,`–`),R(),L(2,`span`,20),J(3,`Count unavailable`),R())}function DD(e,t){e&1&&(z(0,`span`,22),L(1,`span`,20),J(2,`Counting…`),R())}function OD(e,t){if(e&1){let e=H();L(0,`button`,13),U(`click`,function(){let t=E(e).$implicit;return D(G().navigate.emit(t.tab))}),L(1,`span`,14)(2,`span`,15),z(3,`app-tab-icon`,16),R(),L(4,`span`,17),J(5,`→`),R()(),L(6,`span`,18),J(7),R(),M(8,TD,4,2)(9,ED,4,0)(10,DD,3,0),R()}if(e&2){let e,n=t.$implicit,r=t.$index,i=G().stateOf(n.tab);K(`animation-delay`,60*r,`ms`),j(`aria-busy`,i===`loading`),A(3),I(`name`,n.tab),A(4),Y(n.label),A(),N((e=i)===`ready`?8:e===`error`?9:10)}}function kD(e,t){e&1&&(L(0,`p`),J(1,`Loading…`),R())}function AD(e,t){if(e&1&&(L(0,`div`)(1,`dt`),J(2),R(),L(3,`dd`),J(4),R()()),e&2){let e=t.$implicit;A(2),Y(e.label),A(2),Y(e.value)}}function jD(e,t){if(e&1&&(L(0,`dl`),P(1,AD,5,2,`div`,null,hD),R()),e&2){let e=G();A(),F(e.configItems())}}function MD(e,t){e&1&&(L(0,`p`),J(1,`Defaults`),R())}var ND=[{tab:`components`,label:`Components`},{tab:`routes`,label:`Routes`},{tab:`signals`,label:`Signals`},{tab:`injectors`,label:`Injectors`},{tab:`store`,label:`NgRx declarations`},{tab:`pipes`,label:`Pipes`},{tab:`forms`,label:`Forms`},{tab:`network`,label:`SSR & HTTP`}];function PD(e){return ND.filter(t=>$E(t.tab,e))}var FD={zoneless:`Zoneless`,zone:`zone.js`,"zone-unused":`Zoneless, zone.js loaded`};function ID(e){return e&&Object.hasOwn(FD,e)?FD[e]:null}var LD=new Set([`signal`,`computed`,`linkedSignal`,`effect`]),RD={action:[`action`,`actions`],reducer:[`reducer`,`reducers`],effect:[`effect`,`effects`],selector:[`selector`,`selectors`],feature:[`feature`,`features`],"store-setup":[`setup call`,`setup calls`],"signal-store":[`signal store`,`signal stores`],"signal-state":[`signal state`,`signal states`],"signal-method":[`signal method`,`signal methods`]};function zD(e,t,n){return`${e} ${e===1?t:n}`}function BD(e,t){for(let n of e??[])t(n),BD(n.children,t)}function VD(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`discovered in source`};let t=e.filter(e=>e.kind===`directive`).length;return{value:e.length-t,sub:`components · ${zD(t,`directive`,`directives`)}`}}function HD(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`route entries in source`};let t=e.filter(e=>e.kind===`redirect`).length;return{value:new Set(e.filter(e=>e.kind===`page`).map(e=>e.fullPath??e.path??``)).size,sub:`navigable paths · ${zD(t,`redirect`,`redirects`)}`}}function UD(e){let t=new Map;for(let n of e)n.kind&&t.set(n.kind,(t.get(n.kind)??0)+1);if(!t.size)return{value:e.length,sub:`declarations in source`};let n=[...t].sort((e,t)=>t[1]-e[1]).map(([e,t])=>{let[n,r]=RD[e]??[e,e];return zD(t,n,r)});return{value:e.length,sub:n.join(` · `)}}function WD(e,t){let n=e?.forms??[],r=t?n.filter(e=>LE(e.id)===t):n;if(!r.length)return{value:0,sub:`no forms on the page yet`};let i=r.filter(e=>e.root?.status===`INVALID`).length;return{value:r.length,sub:`${r.length===1?`form`:`forms`} · ${i} invalid`}}function GD(e){return e.cancelled||e.status===void 0?!1:e.status===0||e.status>=400}function KD(e,t){let n=e?.pages??[],r=t?n.find(e=>e.pageId===t)??null:n.reduce((e,t)=>!e||t.reportedAt>e.reportedAt?t:e,null),i=t&&!r?[]:e?.serverCalls??[],a=r?.initialUrl,o=[...a?i.filter(e=>!e.pageUrl||e.pageUrl===a):i,...r?.calls??[]];if(!o.length)return{value:0,sub:`no calls recorded yet`};let s=o.filter(GD).length;return{value:o.length,sub:`${o.length===1?`call`:`calls`} · ${s} failed`}}var qD=class e{rpc=$(null);navigate=Rv();staticReport=Q(()=>FE(this.rpc()));meta=k(null);config=Q(()=>JE(this.rpc()));stats=Q(()=>this.rpc()?PD(this.config()):[]);configItems=Q(()=>SE(this.config()));metaState=k(`loading`);states=k({});rows=k({});injectorTree=k(null);signalGraph=k(null);formsState=k(null);httpState=k(null);pageId=kE();destroyRef=w(Es);stopLive=[];zone=Q(()=>ID(jE(this.injectorTree(),this.pageId)?.zone));liveInjectors=Q(()=>{let e=jE(this.injectorTree(),this.pageId);if(!e?.roots?.length)return null;let t=0,n=0,r=e=>{t++,n+=e.providers?.length??0};return BD(e.roots,r),BD(e.environment,r),{injectors:t,providers:n}});liveSignals=Q(()=>{let e=ME(this.signalGraph(),this.pageId);return e?.nodes?.length?e.nodes.filter(e=>LD.has(e.kind??``)).length:null});cards=Q(()=>{let e=this.rows(),t={};if(e.components&&(t.components=VD(e.components)),e.routes&&(t.routes=HD(e.routes)),e.store&&(t.store=UD(e.store)),e.pipes){let n=e.pipes.filter(e=>e.builtin).length;t.pipes={value:e.pipes.length-n,sub:n?`custom pipes · ${n} built-in in use`:`custom pipes in source`}}let n=this.liveSignals();n===null?e.signals&&(t.signals={value:e.signals.length,sub:`signal declarations in source`}):t.signals={value:n,sub:e.signals?`live on the page · ${e.signals.length} declared in source`:`live on the page`};let r=this.liveInjectors();r?t.injectors={value:r.injectors,sub:`live injectors · ${zD(r.providers,`provider`,`providers`)}`}:e.injectors&&(t.injectors={value:e.injectors.filter(e=>e.type!==`injection`).length,sub:`provider declarations in source`});let i=this.formsState();i&&(t.forms=WD(i,this.pageId));let a=this.httpState();return a&&(t.network=KD(a,this.pageId)),t});loadMeta(e=this.rpc()){e&&(this.metaState.set(`loading`),e.scope(`pangular`).rpc.call(`build-meta`).then(t=>{this.rpc()===e&&(this.meta.set(t),this.metaState.set(`ready`))}).catch(()=>{this.rpc()===e&&this.metaState.set(`error`)}))}constructor(){pc(()=>{let e=this.rpc();if(!e)return;let t=e.scope(`pangular`);this.states.set({}),this.rows.set({}),this.formsState.set(null),this.httpState.set(null),this.loadMeta(e);let n=JE(e),r=e=>$E(e,n);r(`components`)&&this.load(t.rpc.call(`get-components`),`components`),r(`routes`)&&this.load(t.rpc.call(`get-routes`),`routes`),r(`signals`)&&this.load(t.rpc.call(`get-signals`),`signals`),r(`injectors`)&&this.load(t.rpc.call(`get-providers`),`injectors`),r(`store`)&&this.load(t.rpc.call(`get-ngrx-store`),`store`),r(`pipes`)&&this.load(t.rpc.call(`get-pipes`),`pipes`),this.watchLive(e,n)}),this.destroyRef.onDestroy(()=>this.unwatch())}stateOf(e){return(e===`signals`?this.liveSignals():e===`injectors`?this.liveInjectors():null)===null?this.states()[e]??`loading`:`ready`}load(e,t){let n=e=>this.states.update(n=>({...n,[t]:e}));e.then(e=>{this.rows.update(n=>({...n,[t]:Array.isArray(e)?e:[]})),n(`ready`)}).catch(()=>n(`error`))}async watchLive(e,t){this.unwatch();let n=e.scope(`pangular`).rpc,r=async(t,r,i)=>{let a=e=>i&&this.states.update(t=>({...t,[i]:e}));try{let i=await n.sharedState(t);if(this.destroyRef.destroyed||this.rpc()!==e)return;r(i.value()),a(`ready`),this.stopLive.push(i.on(`updated`,e=>r(e)))}catch{if(this.destroyRef.destroyed||this.rpc()!==e)return;r(null),a(`error`)}};await Promise.all([t.inspectors.injectors&&r(`injector-tree`,e=>this.injectorTree.set(e)),t.inspectors.signals&&r(`signal-graph`,e=>this.signalGraph.set(e)),$E(`forms`,t)&&r(`forms`,e=>this.formsState.set(e??{}),`forms`),$E(`network`,t)&&r(`http`,e=>this.httpState.set(e??{}),`network`)])}unwatch(){for(let e of this.stopLive.splice(0))e()}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-dashboard`]],inputs:{rpc:[1,`rpc`]},outputs:{navigate:`navigate`},decls:33,vars:14,consts:[[`aria-labelledby`,`project-title`,1,`project`],[1,`project-head`],[1,`eyebrow`],[`id`,`project-title`],[1,`chips`],[1,`analog`],[1,`grid`],[`type`,`button`,1,`stat`,3,`animation-delay`],[`aria-labelledby`,`config-title`,1,`config`],[`id`,`config-title`],[1,`hint`],[`type`,`button`,1,`retry`],[`type`,`button`,1,`retry`,3,`click`],[`type`,`button`,1,`stat`,3,`click`],[1,`top`],[1,`icon`],[3,`name`],[`aria-hidden`,`true`,1,`go`],[1,`label`],[1,`big`],[1,`sub`],[1,`big`,`muted`],[`aria-hidden`,`true`,1,`big`,`skeleton`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`p`,2),J(3,`Project`),R(),L(4,`h2`,3),M(5,gD,1,1)(6,_D,1,0)(7,vD,1,0),R(),M(8,SD,4,2),R(),L(9,`ul`,4)(10,`li`)(11,`span`),J(12,`Angular`),R(),J(13),R(),L(14,`li`)(15,`span`),J(16,`TypeScript`),R(),J(17),R(),L(18,`li`)(19,`span`),J(20,`SSR`),R(),J(21),R(),M(22,CD,4,1,`li`,5),M(23,wD,4,1,`li`),R()(),L(24,`div`,6),P(25,OD,11,6,`button`,7,mD),R(),L(27,`section`,8)(28,`h2`,9),J(29,`Configuration`),R(),M(30,kD,2,0,`p`)(31,jD,3,0,`dl`)(32,MD,2,0,`p`),R()),e&2){let e,n,r;j(`aria-busy`,t.metaState()===`loading`),A(4),q(`muted`,t.metaState()!==`ready`),A(),N((e=t.metaState())===`ready`?5:e===`error`?6:7),A(3),N(t.metaState()===`error`?8:-1),A(),q(`pending`,t.metaState()===`loading`),A(4),Y(t.meta()?.angularVersion??`…`),A(4),Y(t.meta()?.typescript??`…`),A(4),Y(t.meta()?t.meta()?.ssr?`On`:`Off`:`…`),A(),N((n=t.meta()?.analog)?22:-1,n),A(),N((r=t.zone())?23:-1,r),A(2),F(t.stats()),A(2),j(`aria-busy`,!t.rpc()),A(3),N(t.rpc()?t.configItems().length?31:32:30)}},dependencies:[pD],styles:[`[_nghost-%COMP%] { display: block; max-width: 1200px; } @@ -325,7 +325,7 @@ h2.muted[_ngcontent-%COMP%] { .skeleton[_ngcontent-%COMP%] { animation: none; } -}`]})},MD=`pangular:panel-action-result`,ND=6e3,PD=0;function FD(e=window){return e.location.protocol===`chrome-extension:`&&e.parent!==e}function ID(e,t=window){let n=`pa-${Date.now().toString(36)}-${++PD}`;return new Promise(r=>{let i=e=>{t.clearTimeout(o),t.removeEventListener(`message`,a),r(e)},a=({source:e,origin:r,data:a})=>{if(e!==t.parent||r!==t.location.origin)return;let o=a;if(o?.type!==MD||o.requestId!==n)return;let{opened:s,error:c}=a;i({ok:o.ok===!0,...s===`file`||s===`class`?{opened:s}:{},...typeof c==`string`?{error:c}:{}})},o=t.setTimeout(()=>i({ok:!1,error:`timeout`}),ND);t.addEventListener(`message`,a),t.parent.postMessage({...e,requestId:n},t.location.origin)})}var LD=class e{available=FD();reveal(e,t){return ID({type:`pangular:reveal-element`,pageId:e,id:t})}openSource(e,t,n){return ID({type:`pangular:open-source`,pageId:e,id:t,...n?{file:n.file,line:n.line}:{}})}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})};function RD(e){return e?.platform===`angular-native`}function zD(e){return RD(e)||e?.platform===`nativescript`}function BD(e,t){let n=Object.values(e??{}).filter(RD);if(t&&n.some(e=>e.pageId===t))return t;let r=null;for(let e of n)(!r||e.reportedAt>r.reportedAt)&&(r=e);return r?.pageId??null}var VD=[`trigger`],HD=[`list`],UD=(e,t)=>t.value;function WD(e,t){if(e&1&&(B(0,`span`,4),J(1),V()),e&2){let e=G();A(),Y(e.current().hint)}}function GD(e,t){if(e&1&&(B(0,`span`,15),J(1),V()),e&2){let e=G().$implicit;A(),Y(e.hint)}}function KD(e,t){if(e&1){let e=H();B(0,`li`,11),W(`pointerenter`,function(){let t=E(e).$index;return D(G(2).active.set(t))})(`pointerdown`,function(e){return e.preventDefault()})(`click`,function(){let t=E(e).$index;return D(G(2).choose(t))}),O(),B(1,`svg`,12),Vg(2,`path`,13),V(),gs(),B(3,`span`,14),J(4),V(),M(5,GD,2,1,`span`,15),V()}if(e&2){let e=t.$implicit,n=t.$index,r=G(2);q(`active`,n===r.active())(`selected`,e.value===r.value()),j(`id`,r.uid+`-opt-`+n)(`aria-selected`,e.value===r.value())(`aria-disabled`,e.disabled||null),A(4),Y(e.label),A(),N(e.hint?5:-1)}}function qD(e,t){if(e&1&&(B(0,`li`,10),J(1),V()),e&2){let e=G(2);A(),Y(e.emptyText())}}function JD(e,t){if(e&1&&(B(0,`ul`,8,1),_g(`list-in`),W(`pointerdown`,function(e){return e.preventDefault()}),P(2,KD,6,9,`li`,9,UD,!1,qD,2,1,`li`,10),V()),e&2){let e=G();q(`up`,e.dropUp()),j(`id`,e.uid+`-list`)(`aria-labelledby`,e.labelledBy()||e.uid+`-trigger`),A(2),F(e.options())}}var YD=0,XD=class e{options=$.required();value=Gv(null);placeholder=$(`Select…`);ariaLabel=$(``);labelledBy=$(``);describedBy=$(``);disabled=$(!1);emptyText=$(`Nothing to choose`);uid=`app-select-${++YD}`;open=k(!1);active=k(-1);dropUp=k(!1);current=Q(()=>this.options().find(e=>e.value===this.value())??null);host=w(Fl);injector=w(ws);trigger=Jv.required(`trigger`);list=Jv(`list`);typed=``;typedAt=0;toggle(){this.open()?this.close():this.show()}choose(e){let t=this.options()[e];t&&!t.disabled&&(this.value.set(t.value),this.close(),this.trigger().nativeElement.focus())}onKey(e){let t=this.options(),n=this.open();switch(e.key){case`ArrowDown`:case`ArrowUp`:if(e.preventDefault(),!n){this.show();return}this.move(e.key===`ArrowDown`?1:-1);return;case`Home`:case`End`:if(!n)return;e.preventDefault(),this.setActive(e.key===`Home`?this.firstEnabled(0,1):this.firstEnabled(t.length-1,-1));return;case`Enter`:case` `:e.preventDefault(),n&&this.active()>=0?this.choose(this.active()):this.show();return;case`Escape`:if(!n)return;e.preventDefault(),e.stopPropagation(),this.close();return;case`Tab`:n&&this.close();return;default:e.key.length===1&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&this.typeAhead(e.key)}}onBlur(e){let t=e.relatedTarget;t&&this.host.nativeElement.contains(t)||this.close()}onOutside(e){this.open()&&!this.host.nativeElement.contains(e.target)&&this.close()}show(){if(this.disabled())return;let e=this.host.nativeElement.getBoundingClientRect(),t=window.innerHeight-e.bottom;this.dropUp.set(t<220&&e.top>t);let n=this.options().findIndex(e=>e.value===this.value());this.open.set(!0),this.setActive(n>=0?n:this.firstEnabled(0,1))}close(){this.open.set(!1),this.active.set(-1)}move(e){let t=this.firstEnabled(this.active()+e,e);t>=0&&this.setActive(t)}firstEnabled(e,t){let n=this.options();for(let r=e;r>=0&&r{(this.list()?.nativeElement.querySelector(`#${this.uid}-opt-${e}`))?.scrollIntoView({block:`nearest`})},{injector:this.injector})}typeAhead(e){let t=performance.now();this.typed=t-this.typedAt>600?e.toLowerCase():this.typed+e.toLowerCase(),this.typedAt=t;let n=this.options().findIndex(e=>!e.disabled&&e.label.toLowerCase().startsWith(this.typed));n<0||(this.open()?this.setActive(n):this.value.set(this.options()[n].value))}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-select`]],viewQuery:function(e,t){e&1&&l_(t.trigger,VD,5)(t.list,HD,5),e&2&&u_(2)},hostAttrs:[1,`app-select`],hostVars:2,hostBindings:function(e,t){e&1&&U(`pointerdown`,function(e){return t.onOutside(e)},Fu),e&2&&q(`open`,t.open())},inputs:{options:[1,`options`],value:[1,`value`],placeholder:[1,`placeholder`],ariaLabel:[1,`ariaLabel`],labelledBy:[1,`labelledBy`],describedBy:[1,`describedBy`],disabled:[1,`disabled`],emptyText:[1,`emptyText`]},outputs:{value:`valueChange`},decls:8,vars:13,consts:[[`trigger`,``],[`list`,``],[`type`,`button`,`role`,`combobox`,`aria-haspopup`,`listbox`,1,`trigger`,3,`click`,`keydown`,`blur`,`disabled`],[1,`value`],[1,`value-hint`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m6 9 6 6 6-6`],[`role`,`listbox`,`tabindex`,`-1`,1,`list`,3,`up`],[`role`,`listbox`,`tabindex`,`-1`,1,`list`,3,`pointerdown`],[`role`,`option`,3,`active`,`selected`],[`role`,`option`,`aria-disabled`,`true`,1,`empty`],[`role`,`option`,3,`pointerenter`,`pointerdown`,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`check`],[`d`,`m5 12 5 5 9-10`],[1,`label`],[1,`hint`]],template:function(e,t){e&1&&(B(0,`button`,2,0),W(`click`,function(){return t.toggle()})(`keydown`,function(e){return t.onKey(e)})(`blur`,function(e){return t.onBlur(e)}),B(2,`span`,3),J(3),V(),M(4,WD,2,1,`span`,4),O(),B(5,`svg`,5),Vg(6,`path`,6),V()(),M(7,JD,5,5,`ul`,7)),e&2&&(qg(`disabled`,t.disabled()),j(`id`,t.uid+`-trigger`)(`aria-controls`,t.uid+`-list`)(`aria-expanded`,t.open())(`aria-label`,t.ariaLabel()||null)(`aria-labelledby`,t.labelledBy()||null)(`aria-describedby`,t.describedBy()||null)(`aria-activedescendant`,t.open()&&t.active()>=0?t.uid+`-opt-`+t.active():null),A(2),q(`placeholder`,!t.current()),A(),X(` `,t.current()?.label??t.placeholder(),` `),A(),N(t.current()?.hint?4:-1),A(3),N(t.open()?7:-1))},styles:[`[_nghost-%COMP%] { +}`]})},JD=`pangular:panel-action-result`,YD=6e3,XD=0;function ZD(e=window){return e.location.protocol===`chrome-extension:`&&e.parent!==e}function QD(e,t=window){let n=`pa-${Date.now().toString(36)}-${++XD}`;return new Promise(r=>{let i=e=>{t.clearTimeout(o),t.removeEventListener(`message`,a),r(e)},a=({source:e,origin:r,data:a})=>{if(e!==t.parent||r!==t.location.origin)return;let o=a;if(o?.type!==JD||o.requestId!==n)return;let{opened:s,error:c}=a;i({ok:o.ok===!0,...s===`file`||s===`class`?{opened:s}:{},...typeof c==`string`?{error:c}:{}})},o=t.setTimeout(()=>i({ok:!1,error:`timeout`}),YD);t.addEventListener(`message`,a),t.parent.postMessage({...e,requestId:n},t.location.origin)})}var $D=class e{available=ZD();reveal(e,t){return QD({type:`pangular:reveal-element`,pageId:e,id:t})}openSource(e,t,n){return QD({type:`pangular:open-source`,pageId:e,id:t,...n?{file:n.file,line:n.line}:{}})}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})};function eO(e){return e?.platform===`angular-native`}function tO(e){return eO(e)||e?.platform===`nativescript`}function nO(e,t){let n=Object.values(e??{}).filter(eO);if(t&&n.some(e=>e.pageId===t))return t;let r=null;for(let e of n)(!r||e.reportedAt>r.reportedAt)&&(r=e);return r?.pageId??null}var rO=[`trigger`],iO=[`list`],aO=(e,t)=>t.value;function oO(e,t){if(e&1&&(B(0,`span`,4),J(1),V()),e&2){let e=G();A(),Y(e.current().hint)}}function sO(e,t){if(e&1&&(B(0,`span`,15),J(1),V()),e&2){let e=G().$implicit;A(),Y(e.hint)}}function cO(e,t){if(e&1){let e=H();B(0,`li`,11),W(`pointerenter`,function(){let t=E(e).$index;return D(G(2).active.set(t))})(`pointerdown`,function(e){return e.preventDefault()})(`click`,function(){let t=E(e).$index;return D(G(2).choose(t))}),O(),B(1,`svg`,12),Vg(2,`path`,13),V(),gs(),B(3,`span`,14),J(4),V(),M(5,sO,2,1,`span`,15),V()}if(e&2){let e=t.$implicit,n=t.$index,r=G(2);q(`active`,n===r.active())(`selected`,e.value===r.value()),j(`id`,r.uid+`-opt-`+n)(`aria-selected`,e.value===r.value())(`aria-disabled`,e.disabled||null),A(4),Y(e.label),A(),N(e.hint?5:-1)}}function lO(e,t){if(e&1&&(B(0,`li`,10),J(1),V()),e&2){let e=G(2);A(),Y(e.emptyText())}}function uO(e,t){if(e&1&&(B(0,`ul`,8,1),_g(`list-in`),W(`pointerdown`,function(e){return e.preventDefault()}),P(2,cO,6,9,`li`,9,aO,!1,lO,2,1,`li`,10),V()),e&2){let e=G();q(`up`,e.dropUp()),j(`id`,e.uid+`-list`)(`aria-labelledby`,e.labelledBy()||e.uid+`-trigger`),A(2),F(e.options())}}var dO=0,fO=class e{options=$.required();value=Gv(null);placeholder=$(`Select…`);ariaLabel=$(``);labelledBy=$(``);describedBy=$(``);disabled=$(!1);emptyText=$(`Nothing to choose`);uid=`app-select-${++dO}`;open=k(!1);active=k(-1);dropUp=k(!1);current=Q(()=>this.options().find(e=>e.value===this.value())??null);host=w(Fl);injector=w(ws);trigger=Jv.required(`trigger`);list=Jv(`list`);typed=``;typedAt=0;toggle(){this.open()?this.close():this.show()}choose(e){let t=this.options()[e];t&&!t.disabled&&(this.value.set(t.value),this.close(),this.trigger().nativeElement.focus())}onKey(e){let t=this.options(),n=this.open();switch(e.key){case`ArrowDown`:case`ArrowUp`:if(e.preventDefault(),!n){this.show();return}this.move(e.key===`ArrowDown`?1:-1);return;case`Home`:case`End`:if(!n)return;e.preventDefault(),this.setActive(e.key===`Home`?this.firstEnabled(0,1):this.firstEnabled(t.length-1,-1));return;case`Enter`:case` `:e.preventDefault(),n&&this.active()>=0?this.choose(this.active()):this.show();return;case`Escape`:if(!n)return;e.preventDefault(),e.stopPropagation(),this.close();return;case`Tab`:n&&this.close();return;default:e.key.length===1&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&this.typeAhead(e.key)}}onBlur(e){let t=e.relatedTarget;t&&this.host.nativeElement.contains(t)||this.close()}onOutside(e){this.open()&&!this.host.nativeElement.contains(e.target)&&this.close()}show(){if(this.disabled())return;let e=this.host.nativeElement.getBoundingClientRect(),t=window.innerHeight-e.bottom;this.dropUp.set(t<220&&e.top>t);let n=this.options().findIndex(e=>e.value===this.value());this.open.set(!0),this.setActive(n>=0?n:this.firstEnabled(0,1))}close(){this.open.set(!1),this.active.set(-1)}move(e){let t=this.firstEnabled(this.active()+e,e);t>=0&&this.setActive(t)}firstEnabled(e,t){let n=this.options();for(let r=e;r>=0&&r{(this.list()?.nativeElement.querySelector(`#${this.uid}-opt-${e}`))?.scrollIntoView({block:`nearest`})},{injector:this.injector})}typeAhead(e){let t=performance.now();this.typed=t-this.typedAt>600?e.toLowerCase():this.typed+e.toLowerCase(),this.typedAt=t;let n=this.options().findIndex(e=>!e.disabled&&e.label.toLowerCase().startsWith(this.typed));n<0||(this.open()?this.setActive(n):this.value.set(this.options()[n].value))}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-select`]],viewQuery:function(e,t){e&1&&l_(t.trigger,rO,5)(t.list,iO,5),e&2&&u_(2)},hostAttrs:[1,`app-select`],hostVars:2,hostBindings:function(e,t){e&1&&U(`pointerdown`,function(e){return t.onOutside(e)},Fu),e&2&&q(`open`,t.open())},inputs:{options:[1,`options`],value:[1,`value`],placeholder:[1,`placeholder`],ariaLabel:[1,`ariaLabel`],labelledBy:[1,`labelledBy`],describedBy:[1,`describedBy`],disabled:[1,`disabled`],emptyText:[1,`emptyText`]},outputs:{value:`valueChange`},decls:8,vars:13,consts:[[`trigger`,``],[`list`,``],[`type`,`button`,`role`,`combobox`,`aria-haspopup`,`listbox`,1,`trigger`,3,`click`,`keydown`,`blur`,`disabled`],[1,`value`],[1,`value-hint`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m6 9 6 6 6-6`],[`role`,`listbox`,`tabindex`,`-1`,1,`list`,3,`up`],[`role`,`listbox`,`tabindex`,`-1`,1,`list`,3,`pointerdown`],[`role`,`option`,3,`active`,`selected`],[`role`,`option`,`aria-disabled`,`true`,1,`empty`],[`role`,`option`,3,`pointerenter`,`pointerdown`,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`check`],[`d`,`m5 12 5 5 9-10`],[1,`label`],[1,`hint`]],template:function(e,t){e&1&&(B(0,`button`,2,0),W(`click`,function(){return t.toggle()})(`keydown`,function(e){return t.onKey(e)})(`blur`,function(e){return t.onBlur(e)}),B(2,`span`,3),J(3),V(),M(4,oO,2,1,`span`,4),O(),B(5,`svg`,5),Vg(6,`path`,6),V()(),M(7,uO,5,5,`ul`,7)),e&2&&(qg(`disabled`,t.disabled()),j(`id`,t.uid+`-trigger`)(`aria-controls`,t.uid+`-list`)(`aria-expanded`,t.open())(`aria-label`,t.ariaLabel()||null)(`aria-labelledby`,t.labelledBy()||null)(`aria-describedby`,t.describedBy()||null)(`aria-activedescendant`,t.open()&&t.active()>=0?t.uid+`-opt-`+t.active():null),A(2),q(`placeholder`,!t.current()),A(),X(` `,t.current()?.label??t.placeholder(),` `),A(),N(t.current()?.hint?4:-1),A(3),N(t.open()?7:-1))},styles:[`[_nghost-%COMP%] { position: relative; display: inline-flex; min-width: 0; @@ -520,7 +520,7 @@ li.selected[_ngcontent-%COMP%] .check[_ngcontent-%COMP%] { .chevron[_ngcontent-%COMP%] { transition: none; } -}`]})};function ZD(e,t){let n=lE(t);if(uE(n))return{nodes:e,matches:0};let r=0,i=e=>e.flatMap(e=>{let t=dE(e,n);t&&r++;let a=i(e.children);return t||a.length?[{...e,children:a}]:[]});return{nodes:i(e),matches:r}}function QD(e){return e.flatMap(e=>e.kind===`directive`?QD(e.children):[{...e,children:QD(e.children)}])}function $D(e){return(e.attributes?.length?e.attributes:e.directives??[e.name]).map(e=>`[${e}]`).join(` `)}var eO={hydrated:`Hydrated`,skipped:`Skipped`,mismatched:`Mismatch`,client:`Client`};function tO(e){return eO[e]}function nO(e,t,n,r=!1,i=0){let a=r?`${e}+`:`${e}`;if(n)return`${t} of ${r?`${e+i}+`:e+i}`;let o=i?` · ${i} directive ${i===1?`host`:`hosts`}`:``;return`${a} ${e===1&&!r?`instance`:`instances`}${o}`}function rO(e,t,n,r=!1,i=0){if(!n.trim())return``;if(!t)return`No components match.`;let a=e+i,o=r?`${a}+`:`${a}`,s=!r&&a===1;return`${t} of ${o} ${i?s?`row`:`rows`:s?`instance`:`instances`} match.`}function iO(e){let t=e?.components,n=e?.depth;return t&&n?`Showing the first ${t} component instances, and none nested more than ${n} elements deep. Others are not listed or searchable.`:t?`Showing the first ${t} component instances. Others are not listed or searchable.`:n?`Components nested more than ${n} elements deep are not listed or searchable.`:`The page has more components than the tree shows.`}function aO(e,t){let n=t?.detail?.id??null,r=t?.pageId??null;if(r!==e.pageId)return{pageId:r,selectedId:n,detailId:n,destroyed:null};let i=e.selectedId;return n&&n!==e.detailId&&n!==i&&(i=n),i&&t&&!t.truncated&&!oO(t.roots,i)?{pageId:r,selectedId:null,detailId:n,destroyed:i}:{pageId:r,selectedId:i,detailId:n,destroyed:null}}function oO(e,t){return e.some(e=>e.id===t||oO(e.children,t))}function sO(e,t,n){let r=e.indexOf(n);if(r<0)return null;for(let n=r+1;n=0;n--)if(t.has(e[n]))return e[n];return null}var cO=(e,t)=>t.key,lO=(e,t)=>t.id;function uO(e,t){e&1&&(B(0,`p`,2),J(1,` The HTML came from the server, but no component was hydrated, so the app rendered again on the client. Add `),B(2,`code`),J(3,`provideClientHydration()`),V(),J(4,` and use a development build to see each component's status. `),V())}function dO(e,t){if(e&1&&(B(0,`li`)(1,`span`,9),J(2),V(),J(3),V()),e&2){let e=t.$implicit;M_(`count count-`+e.key),A(2),Y(e.value),A(),X(` `,e.label,` `)}}function fO(e,t){if(e&1&&(B(0,`span`,15),J(1,`Expected `),B(2,`code`),J(3),V()()),e&2){let e=G().$implicit;A(3),Y(e.expected)}}function pO(e,t){if(e&1&&(B(0,`span`,15),J(1,`Found `),B(2,`code`),J(3),V()()),e&2){let e=G().$implicit;A(3),Y(e.actual)}}function mO(e,t){if(e&1){let e=H();B(0,`li`)(1,`button`,12),W(`click`,function(){let t=E(e).$implicit;return D(G(4).showNode.emit(t.id))})(`focus`,function(){let t=E(e).$implicit;return D(G(4).highlight.emit(t.id))})(`blur`,function(){return E(e),D(G(4).highlight.emit(null))})(`mouseenter`,function(){let t=E(e).$implicit;return D(G(4).highlight.emit(t.id))})(`mouseleave`,function(){return E(e),D(G(4).highlight.emit(null))}),B(2,`span`,13),J(3),V(),B(4,`span`,14),J(5),V(),M(6,fO,4,1,`span`,15),M(7,pO,4,1,`span`,15),V()()}if(e&2){let e=t.$implicit;A(3),Y(e.name),A(2),X(`<`,e.tag,`>`),A(),N(e.expected?6:-1),A(),N(e.actual?7:-1)}}function hO(e,t){if(e&1&&(B(0,`h3`,10),J(1,`Mismatches`),V(),B(2,`ul`,11),P(3,mO,8,4,`li`,null,lO),V()),e&2){let e=G(2);A(3),F(e.mismatches)}}function gO(e,t){if(e&1){let e=H();B(0,`div`,3)(1,`ul`,4),P(2,dO,4,4,`li`,5,cO),V(),B(4,`button`,6),W(`click`,function(){return E(e),D(G(2).toggleOverlay())}),O(),B(5,`svg`,7),Vg(6,`rect`,8),V(),J(7,` Outline on page `),V()(),M(8,hO,5,0)}if(e&2){let e=G(),t=G();A(2),F(t.counts()),A(2),j(`aria-pressed`,t.overlayOn()),A(4),N(e.mismatches.length?8:-1)}}function _O(e,t){e&1&&M(0,uO,5,0,`p`,2)(1,gO,9,2),e&2&&N(+!!t.hydrated)}function vO(e,t){e&1&&(B(0,`p`,2),J(1,` This page was not rendered on the server, so there is nothing to hydrate. With server-side rendering and `),B(2,`code`),J(3,`provideClientHydration()`),V(),J(4,`, each component shows whether it was hydrated, skipped or mismatched. `),V())}var yO=class e{report=$(void 0);overlay=Rv();showNode=Rv();highlight=Rv();overlayOn=Fv(()=>this.report()?.overlay===!0);counts=Q(()=>{let e=this.report()?.counts;return e?[{key:`hydrated`,label:`hydrated`,value:e.hydrated},{key:`skipped`,label:`skipped`,value:e.skipped},{key:`mismatched`,label:`mismatched`,value:e.mismatched},{key:`client`,label:`created on the client`,value:e.client},{key:`dehydratedBlocks`,label:e.dehydratedBlocks===1?`dehydrated @defer block`:`dehydrated @defer blocks`,value:e.dehydratedBlocks}]:[]});toggleOverlay(){let e=!this.overlayOn();this.overlayOn.set(e),this.overlay.emit(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-hydration-section`]],inputs:{report:[1,`report`]},outputs:{overlay:`overlay`,showNode:`showNode`,highlight:`highlight`},decls:5,vars:1,consts:[[`aria-labelledby`,`ct-hydration-title`,1,`hydration`],[`id`,`ct-hydration-title`,1,`title`],[1,`empty`],[1,`summary`],[`aria-label`,`Hydration summary`,1,`counts`],[3,`class`],[`type`,`button`,1,`outline`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`],[`x`,`3`,`y`,`3`,`width`,`18`,`height`,`18`,`rx`,`2`,`stroke-dasharray`,`4 3`],[1,`num`],[1,`label`],[1,`mismatches`],[`type`,`button`,1,`mismatch`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`mono`,`muted`],[1,`detail-line`]],template:function(e,t){if(e&1&&(B(0,`section`,0)(1,`h2`,1),J(2,`Hydration`),V(),M(3,_O,2,1)(4,vO,5,0,`p`,2),V()),e&2){let e;A(3),N((e=t.report())?3:4,e)}},styles:[`.hydration[_ngcontent-%COMP%] { +}`]})};function pO(e,t){let n=CE(t);if(wE(n))return{nodes:e,matches:0};let r=0,i=e=>e.flatMap(e=>{let t=TE(e,n);t&&r++;let a=i(e.children);return t||a.length?[{...e,children:a}]:[]});return{nodes:i(e),matches:r}}function mO(e){return e.flatMap(e=>e.kind===`directive`?mO(e.children):[{...e,children:mO(e.children)}])}function hO(e){return(e.attributes?.length?e.attributes:e.directives??[e.name]).map(e=>`[${e}]`).join(` `)}var gO={hydrated:`Hydrated`,skipped:`Skipped`,mismatched:`Mismatch`,client:`Client`};function _O(e){return gO[e]}function vO(e,t,n,r=!1,i=0){let a=r?`${e}+`:`${e}`;if(n)return`${t} of ${r?`${e+i}+`:e+i}`;let o=i?` · ${i} directive ${i===1?`host`:`hosts`}`:``;return`${a} ${e===1&&!r?`instance`:`instances`}${o}`}function yO(e,t,n,r=!1,i=0){if(!n.trim())return``;if(!t)return`No components match.`;let a=e+i,o=r?`${a}+`:`${a}`,s=!r&&a===1;return`${t} of ${o} ${i?s?`row`:`rows`:s?`instance`:`instances`} match.`}function bO(e){let t=e?.components,n=e?.depth;return t&&n?`Showing the first ${t} component instances, and none nested more than ${n} elements deep. Others are not listed or searchable.`:t?`Showing the first ${t} component instances. Others are not listed or searchable.`:n?`Components nested more than ${n} elements deep are not listed or searchable.`:`The page has more components than the tree shows.`}function xO(e,t){let n=t?.detail?.id??null,r=t?.pageId??null;if(r!==e.pageId)return{pageId:r,selectedId:n,detailId:n,destroyed:null};let i=e.selectedId;return n&&n!==e.detailId&&n!==i&&(i=n),i&&t&&!t.truncated&&!SO(t.roots,i)?{pageId:r,selectedId:null,detailId:n,destroyed:i}:{pageId:r,selectedId:i,detailId:n,destroyed:null}}function SO(e,t){return e.some(e=>e.id===t||SO(e.children,t))}function CO(e,t,n){let r=e.indexOf(n);if(r<0)return null;for(let n=r+1;n=0;n--)if(t.has(e[n]))return e[n];return null}var wO=(e,t)=>t.key,TO=(e,t)=>t.id;function EO(e,t){e&1&&(B(0,`p`,2),J(1,` The HTML came from the server, but no component was hydrated, so the app rendered again on the client. Add `),B(2,`code`),J(3,`provideClientHydration()`),V(),J(4,` and use a development build to see each component's status. `),V())}function DO(e,t){if(e&1&&(B(0,`li`)(1,`span`,9),J(2),V(),J(3),V()),e&2){let e=t.$implicit;M_(`count count-`+e.key),A(2),Y(e.value),A(),X(` `,e.label,` `)}}function OO(e,t){if(e&1&&(B(0,`span`,15),J(1,`Expected `),B(2,`code`),J(3),V()()),e&2){let e=G().$implicit;A(3),Y(e.expected)}}function kO(e,t){if(e&1&&(B(0,`span`,15),J(1,`Found `),B(2,`code`),J(3),V()()),e&2){let e=G().$implicit;A(3),Y(e.actual)}}function AO(e,t){if(e&1){let e=H();B(0,`li`)(1,`button`,12),W(`click`,function(){let t=E(e).$implicit;return D(G(4).showNode.emit(t.id))})(`focus`,function(){let t=E(e).$implicit;return D(G(4).highlight.emit(t.id))})(`blur`,function(){return E(e),D(G(4).highlight.emit(null))})(`mouseenter`,function(){let t=E(e).$implicit;return D(G(4).highlight.emit(t.id))})(`mouseleave`,function(){return E(e),D(G(4).highlight.emit(null))}),B(2,`span`,13),J(3),V(),B(4,`span`,14),J(5),V(),M(6,OO,4,1,`span`,15),M(7,kO,4,1,`span`,15),V()()}if(e&2){let e=t.$implicit;A(3),Y(e.name),A(2),X(`<`,e.tag,`>`),A(),N(e.expected?6:-1),A(),N(e.actual?7:-1)}}function jO(e,t){if(e&1&&(B(0,`h3`,10),J(1,`Mismatches`),V(),B(2,`ul`,11),P(3,AO,8,4,`li`,null,TO),V()),e&2){let e=G(2);A(3),F(e.mismatches)}}function MO(e,t){if(e&1){let e=H();B(0,`div`,3)(1,`ul`,4),P(2,DO,4,4,`li`,5,wO),V(),B(4,`button`,6),W(`click`,function(){return E(e),D(G(2).toggleOverlay())}),O(),B(5,`svg`,7),Vg(6,`rect`,8),V(),J(7,` Outline on page `),V()(),M(8,jO,5,0)}if(e&2){let e=G(),t=G();A(2),F(t.counts()),A(2),j(`aria-pressed`,t.overlayOn()),A(4),N(e.mismatches.length?8:-1)}}function NO(e,t){e&1&&M(0,EO,5,0,`p`,2)(1,MO,9,2),e&2&&N(+!!t.hydrated)}function PO(e,t){e&1&&(B(0,`p`,2),J(1,` This page was not rendered on the server, so there is nothing to hydrate. With server-side rendering and `),B(2,`code`),J(3,`provideClientHydration()`),V(),J(4,`, each component shows whether it was hydrated, skipped or mismatched. `),V())}var FO=class e{report=$(void 0);overlay=Rv();showNode=Rv();highlight=Rv();overlayOn=Fv(()=>this.report()?.overlay===!0);counts=Q(()=>{let e=this.report()?.counts;return e?[{key:`hydrated`,label:`hydrated`,value:e.hydrated},{key:`skipped`,label:`skipped`,value:e.skipped},{key:`mismatched`,label:`mismatched`,value:e.mismatched},{key:`client`,label:`created on the client`,value:e.client},{key:`dehydratedBlocks`,label:e.dehydratedBlocks===1?`dehydrated @defer block`:`dehydrated @defer blocks`,value:e.dehydratedBlocks}]:[]});toggleOverlay(){let e=!this.overlayOn();this.overlayOn.set(e),this.overlay.emit(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-hydration-section`]],inputs:{report:[1,`report`]},outputs:{overlay:`overlay`,showNode:`showNode`,highlight:`highlight`},decls:5,vars:1,consts:[[`aria-labelledby`,`ct-hydration-title`,1,`hydration`],[`id`,`ct-hydration-title`,1,`title`],[1,`empty`],[1,`summary`],[`aria-label`,`Hydration summary`,1,`counts`],[3,`class`],[`type`,`button`,1,`outline`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`],[`x`,`3`,`y`,`3`,`width`,`18`,`height`,`18`,`rx`,`2`,`stroke-dasharray`,`4 3`],[1,`num`],[1,`label`],[1,`mismatches`],[`type`,`button`,1,`mismatch`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`mono`,`muted`],[1,`detail-line`]],template:function(e,t){if(e&1&&(B(0,`section`,0)(1,`h2`,1),J(2,`Hydration`),V(),M(3,NO,2,1)(4,PO,5,0,`p`,2),V()),e&2){let e;A(3),N((e=t.report())?3:4,e)}},styles:[`.hydration[_ngcontent-%COMP%] { margin-top: 16px; } @@ -691,7 +691,7 @@ svg[_ngcontent-%COMP%] { button[_ngcontent-%COMP%] { transition: none; } -}`]})};function bO(e){return new Date(e).toLocaleTimeString()}var xO=/[ \t\n\r]/;function SO(e){let t=e.trim(),n;try{n=JSON.parse(t)}catch{return null}if(typeof n!=`object`||!n)return null;let r=``,i=0,a=()=>`\n${` `.repeat(i)}`;for(let e=0;e0?0:-1)},styles:[`[_nghost-%COMP%] { +}`]})};function IO(e){return new Date(e).toLocaleTimeString()}var LO=/[ \t\n\r]/;function RO(e){let t=e.trim(),n;try{n=JSON.parse(t)}catch{return null}if(typeof n!=`object`||!n)return null;let r=``,i=0,a=()=>`\n${` `.repeat(i)}`;for(let e=0;e0?0:-1)},styles:[`[_nghost-%COMP%] { display: block; } @@ -718,7 +718,7 @@ a[_ngcontent-%COMP%] { a[_ngcontent-%COMP%]:focus-visible { outline: 2px solid var(--%NS%accent); outline-offset: 2px; -}`]})},EO=16.6;function DO(e){return e.ms>EO}function OO(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}function kO(e,t){if(!t)return[...e];let n=Math.min(t.from,t.to),r=Math.max(t.from,t.to),i=e.filter(e=>e.id>=n&&e.id<=r);return i.length?i:[...e]}function AO(e){let t=new Map;for(let n of e)for(let e of n.components){let n=t.get(e.name);n?(n.checks+=e.checks,n.ms+=e.ms,n.maxMs=Math.max(n.maxMs,e.ms),n.cycles+=1):t.set(e.name,{name:e.name,checks:e.checks,ms:e.ms,maxMs:e.ms,cycles:1})}return[...t.values()].sort((e,t)=>t.ms-e.ms||e.name.localeCompare(t.name))}function jO(e){let t=e.reduce((e,t)=>Math.max(e,t.ms),0);return Math.max(t,EO*1.25)}function MO(e,t,n=3){let r=e.map(e=>({item:e,value:t(e)})).filter(e=>e.value>0).sort((e,t)=>t.value-e.value),i=r.reduce((e,t)=>e+t.value,0);if(!i)return[];let a=n/i,o=[],s=0,c=0,l=n,u=1,d=[],f=(e,t)=>{let n=e.reduce((e,t)=>e+t,0),r=Math.max(...e),i=Math.min(...e);return Math.max(t*t*r/(n*n),n*n/(t*t*i))},p=()=>{let e=d.reduce((e,t)=>e+t.area,0);if(l>=u){let t=e/u,n=c;for(let e of d){let r=e.area/t;o.push({item:e.item,x:s,y:n,w:t,h:r}),n+=r}s+=t,l-=t}else{let t=e/l,n=s;for(let e of d){let r=e.area/t;o.push({item:e.item,x:n,y:c,w:r,h:t}),n+=r}c+=t,u-=t}d=[]};for(let e of r){let t=e.value*a,n=Math.min(l,u),r=d.map(e=>e.area);d.length&&f([...r,t],n)>f(r,n)&&p(),d.push({item:e.item,area:t})}return d.length&&p(),o.map(e=>({item:e.item,x:e.x/n*100,y:e.y*100,w:e.w/n*100,h:e.h*100}))}var NO={c:`component`,h:`hook`,r:`afterRender`,o:`output`};function PO(e,t){if(t===`c`)return e||null;if(t===`h`){let t=e.lastIndexOf(`.`);return t>0?e.slice(0,t):null}if(t===`o`){let t=e.indexOf(` (`),n=t>0?e.slice(0,t):e;return n&&n!==`?`?n:null}return null}function FO(e,t){let n=e.filter(e=>e.spans?.length);if(!n.length)return null;let r=n.map(e=>{let t=e.spans,n=Math.min(0,...t.map(e=>e[1])),r=Math.max(e.ms,...t.map(e=>e[1]+e[2]));return{cycle:e,spans:t,from:n,width:Math.max(r-n,.001)}}),i=r.reduce((e,t)=>e+t.width,0),a=[],o=[],s=0,c=0;for(let{cycle:e,spans:n,from:l,width:u}of r){o.push({id:e.id,x:s/i*100,w:u/i*100,droppedSpans:e.droppedSpans??0});let r=[...n].sort((e,t)=>e[1]-t[1]||e[3]-t[3]),d=[];for(let[n,o,u,f,p]of r){let r=t[n]??`unknown`,m=d[f-1],h=f>0&&m!==void 0&&ot.cycle.id,LO=(e,t)=>t.id;function RO(e,t){if(e&1){let e=H();B(0,`button`,27),W(`click`,function(){return E(e),D(G().showAll())}),J(1,`Show all cycles`),V()}}function zO(e,t){if(e&1&&Vg(0,`div`,28),e&2){let e=t;K(`left`,e.left,`%`)(`width`,e.width,`%`)}}function BO(e,t){if(e&1&&(B(0,`div`,29),Vg(1,`span`,30),V()),e&2){let e=t.$implicit,n=G();q(`over`,e.over)(`out`,!n.inRange(e.index)&&!!n.range())(`active`,n.focused()&&n.active()===e.index),qg(`id`,n.optionId(e.index)),j(`data-index`,e.index)(`aria-selected`,n.inRange(e.index))(`aria-label`,e.label),A(),K(`height`,e.height,`%`)}}function VO(e,t){e&1&&(B(0,`span`,33),J(1,`over budget`),V())}function HO(e,t){if(e&1&&(B(0,`p`),J(1,` after `),B(2,`span`,35),J(3),V()()),e&2){let e=G();A(3),Y(e.cycle.trigger)}}function UO(e,t){if(e&1&&(B(0,`p`,34)(1,`span`,36),J(2),V(),B(3,`span`),J(4),V()()),e&2){let e=t.$implicit,n=G(2);A(2),Y(e.name),A(2),Y(n.fmt(e.ms))}}function WO(e,t){if(e&1&&(B(0,`div`,31)(1,`p`,32)(2,`strong`),J(3),V(),B(4,`span`),J(5),V(),M(6,VO,2,0,`span`,33),V(),M(7,HO,4,1,`p`),B(8,`p`),J(9),V(),P(10,UO,5,2,`p`,34,kg),V()),e&2){let e=t,n=G();K(`left`,e.left)(`right`,e.right),A(3),Y(n.fmt(e.cycle.ms)),A(2),X(`cycle `,e.cycle.id),A(),N(e.over?6:-1),A(),N(e.cycle.trigger?7:-1),A(2),iv(` `,e.cycle.checks,` `,e.cycle.checks===1?`check`:`checks`,`, `,e.cycle.passes,` `,e.cycle.passes===1?`pass`:`passes`,` `),A(),F(e.top)}}function GO(e,t){if(e&1&&Vg(0,`span`),e&2){let e=t.$implicit;q(`over`,e.over)}}function KO(e,t){if(e&1&&J(0),e&2){let e=t,n=G(2);Z(` `,e.name,` (`,n.fmt(e.ms),`) `)}}function qO(e,t){if(e&1&&(B(0,`tr`)(1,`td`,37),J(2),V(),B(3,`td`,37),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,37),J(8),V(),B(9,`td`,37),J(10),V(),B(11,`td`,35),J(12),V(),B(13,`td`,35),M(14,KO,1,2),V()()),e&2){let e,n=t.$implicit,r=G();A(2),Y(n.id),A(2),Y(r.fmt(n.ms)),A(2),Y(r.isOver(n)?`Over`:`Within`),A(2),Y(n.checks),A(2),Y(n.passes),A(2),Y(n.trigger??``),A(2),N((e=n.components[0])?14:-1,e)}}var JO=0,YO=80,XO=10,ZO=class e{cycles=$([]);range=Gv(null);gapUntil=YO;budgetLabel=`${EO} ms budget`;uid=`cd-chart-${JO++}`;hintId=`${this.uid}-hint`;active=k(null);anchor=null;dragging=!1;hover=k(null);focused=k(!1);max=Q(()=>jO(this.cycles()));budgetAt=Q(()=>EO/this.max()*100);bars=Q(()=>{let e=this.max();return this.cycles().map((t,n)=>({cycle:t,index:n,height:t.ms/e*100,over:DO(t),label:this.describe(t)}))});firstId=Q(()=>this.cycles()[0]?.id??0);lastId=Q(()=>this.cycles().at(-1)?.id??0);span=Q(()=>{let e=this.range();if(!e)return null;let t=this.cycles(),n=Math.min(e.from,e.to),r=Math.max(e.from,e.to),i=t.findIndex(e=>e.id>=n),a=-1;for(let e=t.length-1;e>=0;e--)if(t[e].id<=r){a=e;break}return i<0||akO(this.cycles(),this.range()));startId=Q(()=>this.selected()[0]?.id??``);endId=Q(()=>this.selected().at(-1)?.id??``);band=Q(()=>{let e=this.span(),t=this.cycles().length;return!e||!t?null:{left:e.start/t*100,width:(e.end-e.start+1)/t*100}});summary=Q(()=>{let e=this.selected(),t=e.filter(DO).length;return`${this.span()?e.length===1?`Cycle ${e[0].id}`:`Cycles ${e[0].id} to ${e.at(-1).id} (${e.length})`:`All ${e.length} ${e.length===1?`cycle`:`cycles`}`}. ${t} over the ${EO} ms budget.`});tableLabel=Q(()=>this.span()?`Picked cycles, ${this.summary()}`:`All recorded cycles`);activeOptionId=Q(()=>{let e=this.active();return this.focused()&&e!==null&&e{let e=this.hover()??(this.focused()?this.active():null),t=e===null?void 0:this.cycles()[e];return!t||e===null?null:{cycle:t,over:DO(t),top:t.components.slice(0,3),...this.tipSide(e)}});tipSide(e){let t=this.cycles().length;return e+.5=t.start&&e<=t.end}describe(e){let t=[`Cycle ${e.id}`,OO(e.ms)];DO(e)&&t.push(`over budget`),e.trigger&&t.push(`after ${e.trigger}`),t.push(`${e.checks} ${e.checks===1?`check`:`checks`}`);let n=e.components[0];return n&&t.push(`slowest ${n.name} ${OO(n.ms)}`),t.join(`, `)}select(e,t){let n=this.cycles(),r=n[Math.min(e,t)],i=n[Math.max(e,t)];r&&i&&this.range.set({from:r.id,to:i.id})}showAll(){this.range.set(null),this.anchor=null}setEnd(e,t){if(!this.cycles().length)return;let n=t.target,r=Number.parseInt(n.value,10);if(Number.isNaN(r)){n.value=String(e===`from`?this.startId():this.endId());return}let i=Math.min(Math.max(r,this.firstId()),this.lastId()),a=this.selected(),o=e===`from`?i:a[0]?.id??this.firstId(),s=e===`to`?i:a.at(-1)?.id??this.lastId();this.range.set({from:Math.min(o,s),to:Math.max(o,s)}),n.value=String(e===`from`?Math.min(o,s):Math.max(o,s))}onFocus(){this.focused.set(!0),(this.active()===null||this.active()>=this.cycles().length)&&this.active.set(this.span()?.start??Math.max(this.cycles().length-1,0)),this.anchor??=this.active()}onKey(e){let t=this.cycles().length;if(!t)return;let n=Math.min(this.active()??t-1,t-1),r=null;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=n+1;break;case`ArrowLeft`:case`ArrowUp`:r=n-1;break;case`PageDown`:r=n+XO;break;case`PageUp`:r=n-XO;break;case`Home`:r=0;break;case`End`:r=t-1;break;case`Enter`:case` `:e.preventDefault(),this.anchor=n,this.select(n,n);return;case`Escape`:this.range()&&(e.preventDefault(),this.showAll());return;default:return}e.preventDefault(),r=Math.min(Math.max(r,0),t-1),this.active.set(r),this.hover.set(null),e.shiftKey?(this.anchor??=n,this.select(this.anchor,r)):this.anchor=r}indexAt(e){let t=e.target?.closest?.(`[data-index]`);if(t)return Number(t.getAttribute(`data-index`));let n=e.currentTarget?.getBoundingClientRect(),r=this.cycles().length;if(!n?.width||!r)return null;let i=(e.clientX-n.left)/n.width;return Math.min(Math.max(Math.floor(i*r),0),r-1)}startDrag(e){if(e.button!==0)return;let t=this.indexAt(e);t!==null&&(this.dragging=!0,this.anchor=t,this.active.set(t),this.select(t,t))}onPointerMove(e){let t=this.indexAt(e);this.hover.set(t),this.dragging&&t!==null&&this.anchor!==null&&(this.active.set(t),this.select(this.anchor,t))}endDrag(){this.dragging=!1}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-cycle-chart`]],hostBindings:function(e,t){e&1&&U(`pointerup`,function(){return t.endDrag()},Pu)(`pointercancel`,function(){return t.endDrag()},Pu)},inputs:{cycles:[1,`cycles`],range:[1,`range`]},outputs:{range:`rangeChange`},decls:69,vars:25,consts:[[1,`range`],[`type`,`number`,`inputmode`,`numeric`,3,`change`,`min`,`max`,`value`],[`type`,`button`],[1,`summary`],[1,`hint`,3,`id`],[1,`plot`],[`aria-hidden`,`true`,1,`axis`],[1,`tick`,`top`],[1,`tick`,`zero`],[1,`area`],[`aria-hidden`,`true`,1,`band`,3,`left`,`width`],[`aria-hidden`,`true`,1,`budget`],[`role`,`listbox`,`aria-multiselectable`,`true`,`aria-orientation`,`horizontal`,`tabindex`,`0`,1,`bars`,3,`keydown`,`focus`,`blur`,`pointerdown`,`pointermove`,`pointerleave`],[`role`,`option`,1,`col`,3,`id`,`over`,`out`,`active`],[`aria-hidden`,`true`,1,`tip`,3,`left`,`right`],[`aria-hidden`,`true`,1,`markers`],[3,`over`],[`aria-label`,`Chart key`,1,`legend`],[`aria-hidden`,`true`,1,`key`,`ok`],[`aria-hidden`,`true`,1,`key`,`over`],[`aria-hidden`,`true`,1,`key-marker`],[`aria-hidden`,`true`,1,`key`,`line`],[1,`table`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[`type`,`button`,3,`click`],[`aria-hidden`,`true`,1,`band`],[`role`,`option`,1,`col`,3,`id`],[1,`bar`],[`aria-hidden`,`true`,1,`tip`],[1,`tip-head`],[1,`flag`],[1,`tip-row`],[1,`mono`],[1,`mono`,`name`],[1,`num`]],template:function(e,t){if(e&1&&(B(0,`div`,0)(1,`label`)(2,`span`),J(3,`Start`),V(),B(4,`input`,1),W(`change`,function(e){return t.setEnd(`from`,e)}),V()(),B(5,`label`)(6,`span`),J(7,`End`),V(),B(8,`input`,1),W(`change`,function(e){return t.setEnd(`to`,e)}),V()(),M(9,RO,2,0,`button`,2),B(10,`p`,3),J(11),V()(),B(12,`p`,4),J(13,` Drag across the bars to pick a range of cycles. With the chart focused, the arrow keys move between cycles, Shift with an arrow key extends the range, Enter picks one cycle and Escape shows all cycles again. `),V(),B(14,`div`,5)(15,`div`,6)(16,`span`,7),J(17),V(),B(18,`span`,8),J(19,`0 ms`),V()(),B(20,`div`,9),M(21,zO,1,4,`div`,10),B(22,`div`,11)(23,`span`),J(24),V()(),B(25,`div`,12),W(`keydown`,function(e){return t.onKey(e)})(`focus`,function(){return t.onFocus()})(`blur`,function(){return t.focused.set(!1)})(`pointerdown`,function(e){return t.startDrag(e)})(`pointermove`,function(e){return t.onPointerMove(e)})(`pointerleave`,function(){return t.hover.set(null)}),P(26,BO,2,12,`div`,13,IO),V(),M(28,WO,12,12,`div`,14),V()(),B(29,`div`,15),P(30,GO,1,2,`span`,16,IO),V(),B(32,`ul`,17)(33,`li`),Vg(34,`span`,18),J(35,`Within budget`),V(),B(36,`li`),Vg(37,`span`,19)(38,`span`,20),J(39,`Over budget `),V(),B(40,`li`),Vg(41,`span`,21),J(42),V()(),B(43,`details`,22)(44,`summary`),J(45,`Show the cycles as a table`),V(),B(46,`div`,23)(47,`table`)(48,`caption`,24),J(49),V(),B(50,`thead`)(51,`tr`)(52,`th`,25),J(53,`Cycle`),V(),B(54,`th`,25),J(55,`Duration`),V(),B(56,`th`,26),J(57,`Budget`),V(),B(58,`th`,25),J(59,`Checks`),V(),B(60,`th`,25),J(61,`Passes`),V(),B(62,`th`,26),J(63,`After`),V(),B(64,`th`,26),J(65,`Slowest component`),V()()(),B(66,`tbody`),P(67,qO,15,7,`tr`,null,LO),V()()()()),e&2){let e,n;A(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.startId()),A(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.endId()),A(),N(t.range()?9:-1),A(2),Y(t.summary()),A(),qg(`id`,t.hintId),A(2),q(`flush`,t.bars().length>t.gapUntil),A(3),Y(t.fmt(t.max())),A(4),N((e=t.band())?21:-1,e),A(),K(`bottom`,t.budgetAt(),`%`),A(2),Y(t.budgetLabel),A(),j(`aria-label`,`Change detection cycles, `+t.summary())(`aria-describedby`,t.hintId)(`aria-activedescendant`,t.activeOptionId()),A(),F(t.bars()),A(2),N((n=t.tip())?28:-1,n),A(),q(`flush`,t.bars().length>t.gapUntil),A(),F(t.bars()),A(12),Y(t.budgetLabel),A(4),j(`aria-label`,t.tableLabel()),A(3),X(` `,t.tableLabel(),` `),A(18),F(t.selected())}},styles:[`[_nghost-%COMP%] { +}`]})},HO=16.6;function UO(e){return e.ms>HO}function WO(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}function GO(e,t){if(!t)return[...e];let n=Math.min(t.from,t.to),r=Math.max(t.from,t.to),i=e.filter(e=>e.id>=n&&e.id<=r);return i.length?i:[...e]}function KO(e){let t=new Map;for(let n of e)for(let e of n.components){let n=t.get(e.name);n?(n.checks+=e.checks,n.ms+=e.ms,n.maxMs=Math.max(n.maxMs,e.ms),n.cycles+=1):t.set(e.name,{name:e.name,checks:e.checks,ms:e.ms,maxMs:e.ms,cycles:1})}return[...t.values()].sort((e,t)=>t.ms-e.ms||e.name.localeCompare(t.name))}function qO(e){let t=e.reduce((e,t)=>Math.max(e,t.ms),0);return Math.max(t,HO*1.25)}function JO(e,t,n=3){let r=e.map(e=>({item:e,value:t(e)})).filter(e=>e.value>0).sort((e,t)=>t.value-e.value),i=r.reduce((e,t)=>e+t.value,0);if(!i)return[];let a=n/i,o=[],s=0,c=0,l=n,u=1,d=[],f=(e,t)=>{let n=e.reduce((e,t)=>e+t,0),r=Math.max(...e),i=Math.min(...e);return Math.max(t*t*r/(n*n),n*n/(t*t*i))},p=()=>{let e=d.reduce((e,t)=>e+t.area,0);if(l>=u){let t=e/u,n=c;for(let e of d){let r=e.area/t;o.push({item:e.item,x:s,y:n,w:t,h:r}),n+=r}s+=t,l-=t}else{let t=e/l,n=s;for(let e of d){let r=e.area/t;o.push({item:e.item,x:n,y:c,w:r,h:t}),n+=r}c+=t,u-=t}d=[]};for(let e of r){let t=e.value*a,n=Math.min(l,u),r=d.map(e=>e.area);d.length&&f([...r,t],n)>f(r,n)&&p(),d.push({item:e.item,area:t})}return d.length&&p(),o.map(e=>({item:e.item,x:e.x/n*100,y:e.y*100,w:e.w/n*100,h:e.h*100}))}var YO={c:`component`,h:`hook`,r:`afterRender`,o:`output`};function XO(e,t){if(t===`c`)return e||null;if(t===`h`){let t=e.lastIndexOf(`.`);return t>0?e.slice(0,t):null}if(t===`o`){let t=e.indexOf(` (`),n=t>0?e.slice(0,t):e;return n&&n!==`?`?n:null}return null}function ZO(e,t){let n=e.filter(e=>e.spans?.length);if(!n.length)return null;let r=n.map(e=>{let t=e.spans,n=Math.min(0,...t.map(e=>e[1])),r=Math.max(e.ms,...t.map(e=>e[1]+e[2]));return{cycle:e,spans:t,from:n,width:Math.max(r-n,.001)}}),i=r.reduce((e,t)=>e+t.width,0),a=[],o=[],s=0,c=0;for(let{cycle:e,spans:n,from:l,width:u}of r){o.push({id:e.id,x:s/i*100,w:u/i*100,droppedSpans:e.droppedSpans??0});let r=[...n].sort((e,t)=>e[1]-t[1]||e[3]-t[3]),d=[];for(let[n,o,u,f,p]of r){let r=t[n]??`unknown`,m=d[f-1],h=f>0&&m!==void 0&&ot.cycle.id,$O=(e,t)=>t.id;function ek(e,t){if(e&1){let e=H();B(0,`button`,27),W(`click`,function(){return E(e),D(G().showAll())}),J(1,`Show all cycles`),V()}}function tk(e,t){if(e&1&&Vg(0,`div`,28),e&2){let e=t;K(`left`,e.left,`%`)(`width`,e.width,`%`)}}function nk(e,t){if(e&1&&(B(0,`div`,29),Vg(1,`span`,30),V()),e&2){let e=t.$implicit,n=G();q(`over`,e.over)(`out`,!n.inRange(e.index)&&!!n.range())(`active`,n.focused()&&n.active()===e.index),qg(`id`,n.optionId(e.index)),j(`data-index`,e.index)(`aria-selected`,n.inRange(e.index))(`aria-label`,e.label),A(),K(`height`,e.height,`%`)}}function rk(e,t){e&1&&(B(0,`span`,33),J(1,`over budget`),V())}function ik(e,t){if(e&1&&(B(0,`p`),J(1,` after `),B(2,`span`,35),J(3),V()()),e&2){let e=G();A(3),Y(e.cycle.trigger)}}function ak(e,t){if(e&1&&(B(0,`p`,34)(1,`span`,36),J(2),V(),B(3,`span`),J(4),V()()),e&2){let e=t.$implicit,n=G(2);A(2),Y(e.name),A(2),Y(n.fmt(e.ms))}}function ok(e,t){if(e&1&&(B(0,`div`,31)(1,`p`,32)(2,`strong`),J(3),V(),B(4,`span`),J(5),V(),M(6,rk,2,0,`span`,33),V(),M(7,ik,4,1,`p`),B(8,`p`),J(9),V(),P(10,ak,5,2,`p`,34,kg),V()),e&2){let e=t,n=G();K(`left`,e.left)(`right`,e.right),A(3),Y(n.fmt(e.cycle.ms)),A(2),X(`cycle `,e.cycle.id),A(),N(e.over?6:-1),A(),N(e.cycle.trigger?7:-1),A(2),iv(` `,e.cycle.checks,` `,e.cycle.checks===1?`check`:`checks`,`, `,e.cycle.passes,` `,e.cycle.passes===1?`pass`:`passes`,` `),A(),F(e.top)}}function sk(e,t){if(e&1&&Vg(0,`span`),e&2){let e=t.$implicit;q(`over`,e.over)}}function ck(e,t){if(e&1&&J(0),e&2){let e=t,n=G(2);Z(` `,e.name,` (`,n.fmt(e.ms),`) `)}}function lk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,37),J(2),V(),B(3,`td`,37),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,37),J(8),V(),B(9,`td`,37),J(10),V(),B(11,`td`,35),J(12),V(),B(13,`td`,35),M(14,ck,1,2),V()()),e&2){let e,n=t.$implicit,r=G();A(2),Y(n.id),A(2),Y(r.fmt(n.ms)),A(2),Y(r.isOver(n)?`Over`:`Within`),A(2),Y(n.checks),A(2),Y(n.passes),A(2),Y(n.trigger??``),A(2),N((e=n.components[0])?14:-1,e)}}var uk=0,dk=80,fk=10,pk=class e{cycles=$([]);range=Gv(null);gapUntil=dk;budgetLabel=`${HO} ms budget`;uid=`cd-chart-${uk++}`;hintId=`${this.uid}-hint`;active=k(null);anchor=null;dragging=!1;hover=k(null);focused=k(!1);max=Q(()=>qO(this.cycles()));budgetAt=Q(()=>HO/this.max()*100);bars=Q(()=>{let e=this.max();return this.cycles().map((t,n)=>({cycle:t,index:n,height:t.ms/e*100,over:UO(t),label:this.describe(t)}))});firstId=Q(()=>this.cycles()[0]?.id??0);lastId=Q(()=>this.cycles().at(-1)?.id??0);span=Q(()=>{let e=this.range();if(!e)return null;let t=this.cycles(),n=Math.min(e.from,e.to),r=Math.max(e.from,e.to),i=t.findIndex(e=>e.id>=n),a=-1;for(let e=t.length-1;e>=0;e--)if(t[e].id<=r){a=e;break}return i<0||aGO(this.cycles(),this.range()));startId=Q(()=>this.selected()[0]?.id??``);endId=Q(()=>this.selected().at(-1)?.id??``);band=Q(()=>{let e=this.span(),t=this.cycles().length;return!e||!t?null:{left:e.start/t*100,width:(e.end-e.start+1)/t*100}});summary=Q(()=>{let e=this.selected(),t=e.filter(UO).length;return`${this.span()?e.length===1?`Cycle ${e[0].id}`:`Cycles ${e[0].id} to ${e.at(-1).id} (${e.length})`:`All ${e.length} ${e.length===1?`cycle`:`cycles`}`}. ${t} over the ${HO} ms budget.`});tableLabel=Q(()=>this.span()?`Picked cycles, ${this.summary()}`:`All recorded cycles`);activeOptionId=Q(()=>{let e=this.active();return this.focused()&&e!==null&&e{let e=this.hover()??(this.focused()?this.active():null),t=e===null?void 0:this.cycles()[e];return!t||e===null?null:{cycle:t,over:UO(t),top:t.components.slice(0,3),...this.tipSide(e)}});tipSide(e){let t=this.cycles().length;return e+.5=t.start&&e<=t.end}describe(e){let t=[`Cycle ${e.id}`,WO(e.ms)];UO(e)&&t.push(`over budget`),e.trigger&&t.push(`after ${e.trigger}`),t.push(`${e.checks} ${e.checks===1?`check`:`checks`}`);let n=e.components[0];return n&&t.push(`slowest ${n.name} ${WO(n.ms)}`),t.join(`, `)}select(e,t){let n=this.cycles(),r=n[Math.min(e,t)],i=n[Math.max(e,t)];r&&i&&this.range.set({from:r.id,to:i.id})}showAll(){this.range.set(null),this.anchor=null}setEnd(e,t){if(!this.cycles().length)return;let n=t.target,r=Number.parseInt(n.value,10);if(Number.isNaN(r)){n.value=String(e===`from`?this.startId():this.endId());return}let i=Math.min(Math.max(r,this.firstId()),this.lastId()),a=this.selected(),o=e===`from`?i:a[0]?.id??this.firstId(),s=e===`to`?i:a.at(-1)?.id??this.lastId();this.range.set({from:Math.min(o,s),to:Math.max(o,s)}),n.value=String(e===`from`?Math.min(o,s):Math.max(o,s))}onFocus(){this.focused.set(!0),(this.active()===null||this.active()>=this.cycles().length)&&this.active.set(this.span()?.start??Math.max(this.cycles().length-1,0)),this.anchor??=this.active()}onKey(e){let t=this.cycles().length;if(!t)return;let n=Math.min(this.active()??t-1,t-1),r=null;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=n+1;break;case`ArrowLeft`:case`ArrowUp`:r=n-1;break;case`PageDown`:r=n+fk;break;case`PageUp`:r=n-fk;break;case`Home`:r=0;break;case`End`:r=t-1;break;case`Enter`:case` `:e.preventDefault(),this.anchor=n,this.select(n,n);return;case`Escape`:this.range()&&(e.preventDefault(),this.showAll());return;default:return}e.preventDefault(),r=Math.min(Math.max(r,0),t-1),this.active.set(r),this.hover.set(null),e.shiftKey?(this.anchor??=n,this.select(this.anchor,r)):this.anchor=r}indexAt(e){let t=e.target?.closest?.(`[data-index]`);if(t)return Number(t.getAttribute(`data-index`));let n=e.currentTarget?.getBoundingClientRect(),r=this.cycles().length;if(!n?.width||!r)return null;let i=(e.clientX-n.left)/n.width;return Math.min(Math.max(Math.floor(i*r),0),r-1)}startDrag(e){if(e.button!==0)return;let t=this.indexAt(e);t!==null&&(this.dragging=!0,this.anchor=t,this.active.set(t),this.select(t,t))}onPointerMove(e){let t=this.indexAt(e);this.hover.set(t),this.dragging&&t!==null&&this.anchor!==null&&(this.active.set(t),this.select(this.anchor,t))}endDrag(){this.dragging=!1}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-cycle-chart`]],hostBindings:function(e,t){e&1&&U(`pointerup`,function(){return t.endDrag()},Pu)(`pointercancel`,function(){return t.endDrag()},Pu)},inputs:{cycles:[1,`cycles`],range:[1,`range`]},outputs:{range:`rangeChange`},decls:69,vars:25,consts:[[1,`range`],[`type`,`number`,`inputmode`,`numeric`,3,`change`,`min`,`max`,`value`],[`type`,`button`],[1,`summary`],[1,`hint`,3,`id`],[1,`plot`],[`aria-hidden`,`true`,1,`axis`],[1,`tick`,`top`],[1,`tick`,`zero`],[1,`area`],[`aria-hidden`,`true`,1,`band`,3,`left`,`width`],[`aria-hidden`,`true`,1,`budget`],[`role`,`listbox`,`aria-multiselectable`,`true`,`aria-orientation`,`horizontal`,`tabindex`,`0`,1,`bars`,3,`keydown`,`focus`,`blur`,`pointerdown`,`pointermove`,`pointerleave`],[`role`,`option`,1,`col`,3,`id`,`over`,`out`,`active`],[`aria-hidden`,`true`,1,`tip`,3,`left`,`right`],[`aria-hidden`,`true`,1,`markers`],[3,`over`],[`aria-label`,`Chart key`,1,`legend`],[`aria-hidden`,`true`,1,`key`,`ok`],[`aria-hidden`,`true`,1,`key`,`over`],[`aria-hidden`,`true`,1,`key-marker`],[`aria-hidden`,`true`,1,`key`,`line`],[1,`table`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[`type`,`button`,3,`click`],[`aria-hidden`,`true`,1,`band`],[`role`,`option`,1,`col`,3,`id`],[1,`bar`],[`aria-hidden`,`true`,1,`tip`],[1,`tip-head`],[1,`flag`],[1,`tip-row`],[1,`mono`],[1,`mono`,`name`],[1,`num`]],template:function(e,t){if(e&1&&(B(0,`div`,0)(1,`label`)(2,`span`),J(3,`Start`),V(),B(4,`input`,1),W(`change`,function(e){return t.setEnd(`from`,e)}),V()(),B(5,`label`)(6,`span`),J(7,`End`),V(),B(8,`input`,1),W(`change`,function(e){return t.setEnd(`to`,e)}),V()(),M(9,ek,2,0,`button`,2),B(10,`p`,3),J(11),V()(),B(12,`p`,4),J(13,` Drag across the bars to pick a range of cycles. With the chart focused, the arrow keys move between cycles, Shift with an arrow key extends the range, Enter picks one cycle and Escape shows all cycles again. `),V(),B(14,`div`,5)(15,`div`,6)(16,`span`,7),J(17),V(),B(18,`span`,8),J(19,`0 ms`),V()(),B(20,`div`,9),M(21,tk,1,4,`div`,10),B(22,`div`,11)(23,`span`),J(24),V()(),B(25,`div`,12),W(`keydown`,function(e){return t.onKey(e)})(`focus`,function(){return t.onFocus()})(`blur`,function(){return t.focused.set(!1)})(`pointerdown`,function(e){return t.startDrag(e)})(`pointermove`,function(e){return t.onPointerMove(e)})(`pointerleave`,function(){return t.hover.set(null)}),P(26,nk,2,12,`div`,13,QO),V(),M(28,ok,12,12,`div`,14),V()(),B(29,`div`,15),P(30,sk,1,2,`span`,16,QO),V(),B(32,`ul`,17)(33,`li`),Vg(34,`span`,18),J(35,`Within budget`),V(),B(36,`li`),Vg(37,`span`,19)(38,`span`,20),J(39,`Over budget `),V(),B(40,`li`),Vg(41,`span`,21),J(42),V()(),B(43,`details`,22)(44,`summary`),J(45,`Show the cycles as a table`),V(),B(46,`div`,23)(47,`table`)(48,`caption`,24),J(49),V(),B(50,`thead`)(51,`tr`)(52,`th`,25),J(53,`Cycle`),V(),B(54,`th`,25),J(55,`Duration`),V(),B(56,`th`,26),J(57,`Budget`),V(),B(58,`th`,25),J(59,`Checks`),V(),B(60,`th`,25),J(61,`Passes`),V(),B(62,`th`,26),J(63,`After`),V(),B(64,`th`,26),J(65,`Slowest component`),V()()(),B(66,`tbody`),P(67,lk,15,7,`tr`,null,$O),V()()()()),e&2){let e,n;A(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.startId()),A(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.endId()),A(),N(t.range()?9:-1),A(2),Y(t.summary()),A(),qg(`id`,t.hintId),A(2),q(`flush`,t.bars().length>t.gapUntil),A(3),Y(t.fmt(t.max())),A(4),N((e=t.band())?21:-1,e),A(),K(`bottom`,t.budgetAt(),`%`),A(2),Y(t.budgetLabel),A(),j(`aria-label`,`Change detection cycles, `+t.summary())(`aria-describedby`,t.hintId)(`aria-activedescendant`,t.activeOptionId()),A(),F(t.bars()),A(2),N((n=t.tip())?28:-1,n),A(),q(`flush`,t.bars().length>t.gapUntil),A(),F(t.bars()),A(12),Y(t.budgetLabel),A(4),j(`aria-label`,t.tableLabel()),A(3),X(` `,t.tableLabel(),` `),A(18),F(t.selected())}},styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1098,7 +1098,7 @@ td.mono[_ngcontent-%COMP%] { .bar[_ngcontent-%COMP%] { transition: none; } -}`]})},QO=(e,t)=>t.id,$O=(e,t)=>t.index,ek=(e,t)=>t.kind;function tk(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(2);A(),Z(` Pick `,e.max,` cycles or fewer to see their spans. `,e.count(),` are picked. `)}}function nk(e,t){if(e&1&&(B(0,`span`),J(1),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`width`,e.w,`%`),A(),X(`cycle `,e.id)}}function rk(e,t){if(e&1){let e=H();B(0,`button`,11),W(`focus`,function(){let t=E(e).$implicit;return D(G(3).current.set(t.index))})(`mouseenter`,function(){let t=E(e).$implicit;return D(G(3).hover.set(t.index))})(`mouseleave`,function(){return E(e),D(G(3).hover.set(null))})(`click`,function(){let t=E(e).$implicit;return D(G(3).choose(t))}),B(1,`span`,12),J(2),V()()}if(e&2){let e=t.$implicit,n=G(3);M_(pv(`block kind-`,e.kind)),K(`left`,e.x,`%`)(`width`,e.w,`%`)(`top`,e.depth*n.row,`px`),q(`narrow`,e.w<4),j(`tabindex`,e.index===n.tabStop()?0:-1)(`data-index`,e.index)(`aria-label`,n.describe(e))(`aria-disabled`,e.component?null:`true`),A(2),Y(e.name)}}function ik(e,t){if(e&1&&(B(0,`li`),Vg(1,`span`,13),J(2),V()),e&2){let e=t.$implicit;A(),M_(pv(`key kind-`,e.kind)),A(),Y(e.label)}}function ak(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(3);A(),Z(` Each cycle keeps its longest spans. `,e.dropped(),` shorter `,e.dropped()===1?`span was`:`spans were`,` left out. `)}}function ok(e,t){if(e&1&&(B(0,`tr`)(1,`td`,17),J(2),V(),B(3,`td`,18),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,17),J(8),V(),B(9,`td`,17),J(10),V(),B(11,`td`,17),J(12),V(),B(13,`td`,17),J(14),V()()),e&2){let e=t.$implicit,n=G(4);A(2),Y(e.cycleId),A(),K(`padding-left`,6+e.depth*8,`px`),A(),Y(e.name),A(2),Y(n.kindLabel(e)),A(2),Y(e.depth),A(2),Y(n.fmt(e.start)),A(2),Y(n.fmt(e.ms)),A(2),Y(n.fmt(e.selfMs))}}function sk(e,t){if(e&1&&(B(0,`div`,10)(1,`table`)(2,`caption`,14),J(3),V(),B(4,`thead`)(5,`tr`)(6,`th`,15),J(7,`Cycle`),V(),B(8,`th`,16),J(9,`Span`),V(),B(10,`th`,16),J(11,`Kind`),V(),B(12,`th`,15),J(13,`Depth`),V(),B(14,`th`,15),J(15,`Start`),V(),B(16,`th`,15),J(17,`Total`),V(),B(18,`th`,15),J(19,`Self`),V()()(),B(20,`tbody`),P(21,ok,15,9,`tr`,null,$O),V()()()),e&2){let e=G(),t=G(2);j(`aria-label`,t.tableLabel()),A(3),X(` `,t.tableLabel(),` `),A(18),F(e.blocks)}}function ck(e,t){if(e&1){let e=H();B(0,`div`,1),W(`keydown`,function(t){return E(e),D(G(2).onKey(t))}),B(1,`div`,2),P(2,nk,2,5,`span`,3,QO),V(),B(4,`div`,4),P(5,rk,3,16,`button`,5,$O),V()(),B(7,`p`,6),J(8),V(),B(9,`ul`,7),P(10,ik,3,4,`li`,null,ek),V(),B(12,`p`,8),J(13,` Arrow keys move along a row, Up goes to the enclosing span and Down to the first nested one. Enter on a component shows it in the tree. `),V(),M(14,ak,2,2,`p`,0),B(15,`details`,9),W(`toggle`,function(t){return E(e),D(G(2).onToggle(t))}),B(16,`summary`),J(17,`Show the spans as a table`),V(),M(18,sk,23,2,`div`,10),V()}if(e&2){let e=t,n=G(2);j(`aria-label`,n.label()),A(2),F(e.cycles),A(2),K(`height`,e.depth*n.row,`px`),A(),F(e.blocks),A(3),Y(n.readout()),A(2),F(n.kinds),A(4),N(n.dropped()?14:-1),A(4),N(n.tableOpen()?18:-1)}}function lk(e,t){if(e&1&&(B(0,`h3`),J(1,`Spans in the picked cycles`),V(),M(2,tk,2,2,`p`,0)(3,ck,19,6)),e&2){let e,t=G();A(2),N(t.tooMany()?2:(e=t.graph())?3:-1,e)}}var uk=22;function dk(e,t){for(let n=e.length-1;n>=0;n--)if(t(e[n]))return e[n]}var fk=class e{cycles=$([]);names=$([]);scope=$(`the recording`);pick=Rv();row=uk;max=30;kinds=[`c`,`h`,`r`,`o`].map(e=>({kind:e,label:NO[e]}));current=k(0);tableOpen=k(!1);hover=k(null);hasSpans=Q(()=>this.cycles().some(e=>e.spans?.length));count=Q(()=>this.cycles().length);tooMany=Q(()=>this.count()>30);graph=Q(()=>this.tooMany()?null:FO(this.cycles(),this.names()));tabStop=Q(()=>Math.min(this.current(),Math.max((this.graph()?.blocks.length??1)-1,0)));dropped=Q(()=>this.graph()?.cycles.reduce((e,t)=>e+t.droppedSpans,0)??0);label=Q(()=>`Spans in ${this.scope()} over time, nested by depth. Pick a component to show it in the tree.`);readout=Q(()=>{let e=(this.graph()?.blocks??[])[this.hover()??this.tabStop()];return e?this.describe(e):``});tableLabel=Q(()=>`Timed spans in ${this.scope()}`);fmt(e){return OO(e)}kindLabel(e){return NO[e.kind]}onToggle(e){this.tableOpen.set(e.target.open)}describe(e){let t=[e.name,NO[e.kind],`${OO(e.ms)} total`];return e.selfMs!==e.ms&&t.push(`${OO(e.selfMs)} self`),t.push(e.start<0?`cycle ${e.cycleId}, ${OO(-e.start)} before it started`:`cycle ${e.cycleId} at ${OO(e.start)}`),t.join(`, `)}choose(e){this.current.set(e.index),e.component&&this.pick.emit(e.component)}onKey(e){let t=this.graph()?.blocks??[];if(!t.length)return;let n=t[this.tabStop()],r;switch(e.key){case`ArrowRight`:r=t.find(e=>e.index>n.index&&e.depth===n.depth);break;case`ArrowLeft`:r=dk(t,e=>e.indexe.indexe.parent===n.index)??t.find(e=>e.index>n.index&&e.depth===n.depth+1);break;case`Home`:r=t[0];break;case`End`:r=t.at(-1);break;default:return}e.preventDefault(),this.hover.set(null),r&&(this.current.set(r.index),e.currentTarget.querySelector(`button[data-index="${r.index}"]`)?.focus())}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-flame-graph`]],inputs:{cycles:[1,`cycles`],names:[1,`names`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:1,vars:1,consts:[[1,`note`],[`role`,`group`,1,`flame`,3,`keydown`],[`aria-hidden`,`true`,1,`cycles`],[3,`left`,`width`],[1,`rows`],[`type`,`button`,3,`class`,`narrow`,`left`,`width`,`top`],[`aria-hidden`,`true`,1,`readout`],[`aria-label`,`Span kinds`,1,`legend`],[1,`hint`],[1,`table`,3,`toggle`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[`type`,`button`,3,`focus`,`mouseenter`,`mouseleave`,`click`],[1,`text`],[`aria-hidden`,`true`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[1,`num`],[1,`mono`]],template:function(e,t){e&1&&M(0,lk,4,1),e&2&&N(t.hasSpans()?0:-1)},styles:[`[_nghost-%COMP%] { +}`]})},mk=(e,t)=>t.id,hk=(e,t)=>t.index,gk=(e,t)=>t.kind;function _k(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(2);A(),Z(` Pick `,e.max,` cycles or fewer to see their spans. `,e.count(),` are picked. `)}}function vk(e,t){if(e&1&&(B(0,`span`),J(1),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`width`,e.w,`%`),A(),X(`cycle `,e.id)}}function yk(e,t){if(e&1){let e=H();B(0,`button`,11),W(`focus`,function(){let t=E(e).$implicit;return D(G(3).current.set(t.index))})(`mouseenter`,function(){let t=E(e).$implicit;return D(G(3).hover.set(t.index))})(`mouseleave`,function(){return E(e),D(G(3).hover.set(null))})(`click`,function(){let t=E(e).$implicit;return D(G(3).choose(t))}),B(1,`span`,12),J(2),V()()}if(e&2){let e=t.$implicit,n=G(3);M_(pv(`block kind-`,e.kind)),K(`left`,e.x,`%`)(`width`,e.w,`%`)(`top`,e.depth*n.row,`px`),q(`narrow`,e.w<4),j(`tabindex`,e.index===n.tabStop()?0:-1)(`data-index`,e.index)(`aria-label`,n.describe(e))(`aria-disabled`,e.component?null:`true`),A(2),Y(e.name)}}function bk(e,t){if(e&1&&(B(0,`li`),Vg(1,`span`,13),J(2),V()),e&2){let e=t.$implicit;A(),M_(pv(`key kind-`,e.kind)),A(),Y(e.label)}}function xk(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(3);A(),Z(` Each cycle keeps its longest spans. `,e.dropped(),` shorter `,e.dropped()===1?`span was`:`spans were`,` left out. `)}}function Sk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,17),J(2),V(),B(3,`td`,18),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,17),J(8),V(),B(9,`td`,17),J(10),V(),B(11,`td`,17),J(12),V(),B(13,`td`,17),J(14),V()()),e&2){let e=t.$implicit,n=G(4);A(2),Y(e.cycleId),A(),K(`padding-left`,6+e.depth*8,`px`),A(),Y(e.name),A(2),Y(n.kindLabel(e)),A(2),Y(e.depth),A(2),Y(n.fmt(e.start)),A(2),Y(n.fmt(e.ms)),A(2),Y(n.fmt(e.selfMs))}}function Ck(e,t){if(e&1&&(B(0,`div`,10)(1,`table`)(2,`caption`,14),J(3),V(),B(4,`thead`)(5,`tr`)(6,`th`,15),J(7,`Cycle`),V(),B(8,`th`,16),J(9,`Span`),V(),B(10,`th`,16),J(11,`Kind`),V(),B(12,`th`,15),J(13,`Depth`),V(),B(14,`th`,15),J(15,`Start`),V(),B(16,`th`,15),J(17,`Total`),V(),B(18,`th`,15),J(19,`Self`),V()()(),B(20,`tbody`),P(21,Sk,15,9,`tr`,null,hk),V()()()),e&2){let e=G(),t=G(2);j(`aria-label`,t.tableLabel()),A(3),X(` `,t.tableLabel(),` `),A(18),F(e.blocks)}}function wk(e,t){if(e&1){let e=H();B(0,`div`,1),W(`keydown`,function(t){return E(e),D(G(2).onKey(t))}),B(1,`div`,2),P(2,vk,2,5,`span`,3,mk),V(),B(4,`div`,4),P(5,yk,3,16,`button`,5,hk),V()(),B(7,`p`,6),J(8),V(),B(9,`ul`,7),P(10,bk,3,4,`li`,null,gk),V(),B(12,`p`,8),J(13,` Arrow keys move along a row, Up goes to the enclosing span and Down to the first nested one. Enter on a component shows it in the tree. `),V(),M(14,xk,2,2,`p`,0),B(15,`details`,9),W(`toggle`,function(t){return E(e),D(G(2).onToggle(t))}),B(16,`summary`),J(17,`Show the spans as a table`),V(),M(18,Ck,23,2,`div`,10),V()}if(e&2){let e=t,n=G(2);j(`aria-label`,n.label()),A(2),F(e.cycles),A(2),K(`height`,e.depth*n.row,`px`),A(),F(e.blocks),A(3),Y(n.readout()),A(2),F(n.kinds),A(4),N(n.dropped()?14:-1),A(4),N(n.tableOpen()?18:-1)}}function Tk(e,t){if(e&1&&(B(0,`h3`),J(1,`Spans in the picked cycles`),V(),M(2,_k,2,2,`p`,0)(3,wk,19,6)),e&2){let e,t=G();A(2),N(t.tooMany()?2:(e=t.graph())?3:-1,e)}}var Ek=22;function Dk(e,t){for(let n=e.length-1;n>=0;n--)if(t(e[n]))return e[n]}var Ok=class e{cycles=$([]);names=$([]);scope=$(`the recording`);pick=Rv();row=Ek;max=30;kinds=[`c`,`h`,`r`,`o`].map(e=>({kind:e,label:YO[e]}));current=k(0);tableOpen=k(!1);hover=k(null);hasSpans=Q(()=>this.cycles().some(e=>e.spans?.length));count=Q(()=>this.cycles().length);tooMany=Q(()=>this.count()>30);graph=Q(()=>this.tooMany()?null:ZO(this.cycles(),this.names()));tabStop=Q(()=>Math.min(this.current(),Math.max((this.graph()?.blocks.length??1)-1,0)));dropped=Q(()=>this.graph()?.cycles.reduce((e,t)=>e+t.droppedSpans,0)??0);label=Q(()=>`Spans in ${this.scope()} over time, nested by depth. Pick a component to show it in the tree.`);readout=Q(()=>{let e=(this.graph()?.blocks??[])[this.hover()??this.tabStop()];return e?this.describe(e):``});tableLabel=Q(()=>`Timed spans in ${this.scope()}`);fmt(e){return WO(e)}kindLabel(e){return YO[e.kind]}onToggle(e){this.tableOpen.set(e.target.open)}describe(e){let t=[e.name,YO[e.kind],`${WO(e.ms)} total`];return e.selfMs!==e.ms&&t.push(`${WO(e.selfMs)} self`),t.push(e.start<0?`cycle ${e.cycleId}, ${WO(-e.start)} before it started`:`cycle ${e.cycleId} at ${WO(e.start)}`),t.join(`, `)}choose(e){this.current.set(e.index),e.component&&this.pick.emit(e.component)}onKey(e){let t=this.graph()?.blocks??[];if(!t.length)return;let n=t[this.tabStop()],r;switch(e.key){case`ArrowRight`:r=t.find(e=>e.index>n.index&&e.depth===n.depth);break;case`ArrowLeft`:r=Dk(t,e=>e.indexe.indexe.parent===n.index)??t.find(e=>e.index>n.index&&e.depth===n.depth+1);break;case`Home`:r=t[0];break;case`End`:r=t.at(-1);break;default:return}e.preventDefault(),this.hover.set(null),r&&(this.current.set(r.index),e.currentTarget.querySelector(`button[data-index="${r.index}"]`)?.focus())}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-flame-graph`]],inputs:{cycles:[1,`cycles`],names:[1,`names`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:1,vars:1,consts:[[1,`note`],[`role`,`group`,1,`flame`,3,`keydown`],[`aria-hidden`,`true`,1,`cycles`],[3,`left`,`width`],[1,`rows`],[`type`,`button`,3,`class`,`narrow`,`left`,`width`,`top`],[`aria-hidden`,`true`,1,`readout`],[`aria-label`,`Span kinds`,1,`legend`],[1,`hint`],[1,`table`,3,`toggle`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[`type`,`button`,3,`focus`,`mouseenter`,`mouseleave`,`click`],[1,`text`],[`aria-hidden`,`true`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[1,`num`],[1,`mono`]],template:function(e,t){e&1&&M(0,Tk,4,1),e&2&&N(t.hasSpans()?0:-1)},styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1305,7 +1305,7 @@ td.mono[_ngcontent-%COMP%] { .num[_ngcontent-%COMP%] { text-align: right; font-variant-numeric: tabular-nums; -}`]})};function pk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`,6),J(8),V()()),e&2){let e=t.$implicit,n=G(3);A(2),Z(``,e.name,`.`,e.hook),A(2),Y(e.calls),A(2),Y(n.ms(e.ms)),A(2),Y(n.ms(e.maxMs))}}function mk(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Lifecycle hooks`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Hook`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,pk,9,5,`tr`,null,kg),V()()()),e&2){let e=G(2);A(15),F(e.hooks())}}function hk(e,t){if(e&1&&J(0),e&2){let e=G().$implicit;X(` (`,e.listener,`) `)}}function gk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),M(3,hk,1,1),V(),B(4,`td`,6),J(5),V(),B(6,`td`,6),J(7),V(),B(8,`td`,6),J(9),V()()),e&2){let e=t.$implicit,n=G(3);A(2),X(` `,e.name,` `),A(),N(e.listener?3:-1),A(2),Y(e.calls),A(2),Y(n.ms(e.ms)),A(2),Y(n.ms(e.maxMs))}}function _k(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Output listeners`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Listener`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,gk,10,5,`tr`,null,kg),V()()()),e&2){let e=G(2);A(15),F(e.outputs())}}function vk(e,t){if(e&1&&(B(0,`p`,1),J(1),V()),e&2){let e=t,n=G(2);A(),iv(` afterRender callbacks ran `,e.runs,` `,e.runs===1?`time`:`times`,`, `,n.ms(e.ms),` in total, slowest `,n.ms(e.maxMs),`. `)}}function yk(e,t){if(e&1&&(B(0,`p`,2),J(1),V()),e&2){let e=G(2);A(),Z(` `,e.dropped(),` more hook or output `,e.dropped()===1?`row is`:`rows are`,` left out. A recording lists at most 100 of each. `)}}function bk(e,t){if(e&1&&(B(0,`div`,0),M(1,mk,17,0,`div`),M(2,_k,17,0,`div`),V(),M(3,vk,2,4,`p`,1),M(4,yk,2,2,`p`,2)),e&2){let e,t=G();A(),N(t.hooks().length?1:-1),A(),N(t.outputs().length?2:-1),A(),N((e=t.afterRender())?3:-1,e),A(),N(t.dropped()?4:-1)}}var xk=10;function Sk(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}var Ck=class e{page=$(null);hooks=Q(()=>(this.page()?.hooks??[]).slice(0,xk));outputs=Q(()=>(this.page()?.outputs??[]).slice(0,xk));afterRender=Q(()=>{let e=this.page()?.afterRender;return e?.runs?e:null});dropped=Q(()=>this.page()?.droppedTimings??0);ms(e){return Sk(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-timing`]],inputs:{page:[1,`page`]},decls:1,vars:1,consts:[[1,`timing`],[1,`after-render`],[1,`note`],[`scope`,`col`],[`scope`,`col`,1,`num`],[1,`mono`],[1,`num`]],template:function(e,t){e&1&&M(0,bk,5,4),e&2&&N(t.hooks().length||t.outputs().length||t.afterRender()?0:-1)},styles:[`[_nghost-%COMP%] { +}`]})};function kk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`,6),J(8),V()()),e&2){let e=t.$implicit,n=G(3);A(2),Z(``,e.name,`.`,e.hook),A(2),Y(e.calls),A(2),Y(n.ms(e.ms)),A(2),Y(n.ms(e.maxMs))}}function Ak(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Lifecycle hooks`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Hook`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,kk,9,5,`tr`,null,kg),V()()()),e&2){let e=G(2);A(15),F(e.hooks())}}function jk(e,t){if(e&1&&J(0),e&2){let e=G().$implicit;X(` (`,e.listener,`) `)}}function Mk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),M(3,jk,1,1),V(),B(4,`td`,6),J(5),V(),B(6,`td`,6),J(7),V(),B(8,`td`,6),J(9),V()()),e&2){let e=t.$implicit,n=G(3);A(2),X(` `,e.name,` `),A(),N(e.listener?3:-1),A(2),Y(e.calls),A(2),Y(n.ms(e.ms)),A(2),Y(n.ms(e.maxMs))}}function Nk(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Output listeners`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Listener`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,Mk,10,5,`tr`,null,kg),V()()()),e&2){let e=G(2);A(15),F(e.outputs())}}function Pk(e,t){if(e&1&&(B(0,`p`,1),J(1),V()),e&2){let e=t,n=G(2);A(),iv(` afterRender callbacks ran `,e.runs,` `,e.runs===1?`time`:`times`,`, `,n.ms(e.ms),` in total, slowest `,n.ms(e.maxMs),`. `)}}function Fk(e,t){if(e&1&&(B(0,`p`,2),J(1),V()),e&2){let e=G(2);A(),Z(` `,e.dropped(),` more hook or output `,e.dropped()===1?`row is`:`rows are`,` left out. A recording lists at most 100 of each. `)}}function Ik(e,t){if(e&1&&(B(0,`div`,0),M(1,Ak,17,0,`div`),M(2,Nk,17,0,`div`),V(),M(3,Pk,2,4,`p`,1),M(4,Fk,2,2,`p`,2)),e&2){let e,t=G();A(),N(t.hooks().length?1:-1),A(),N(t.outputs().length?2:-1),A(),N((e=t.afterRender())?3:-1,e),A(),N(t.dropped()?4:-1)}}var Lk=10;function Rk(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}var zk=class e{page=$(null);hooks=Q(()=>(this.page()?.hooks??[]).slice(0,Lk));outputs=Q(()=>(this.page()?.outputs??[]).slice(0,Lk));afterRender=Q(()=>{let e=this.page()?.afterRender;return e?.runs?e:null});dropped=Q(()=>this.page()?.droppedTimings??0);ms(e){return Rk(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-timing`]],inputs:{page:[1,`page`]},decls:1,vars:1,consts:[[1,`timing`],[1,`after-render`],[1,`note`],[`scope`,`col`],[`scope`,`col`,1,`num`],[1,`mono`],[1,`num`]],template:function(e,t){e&1&&M(0,Ik,5,4),e&2&&N(t.hooks().length||t.outputs().length||t.afterRender()?0:-1)},styles:[`[_nghost-%COMP%] { display: block; } @@ -1365,7 +1365,7 @@ td.mono[_ngcontent-%COMP%] { margin: 8px 0 0; color: var(--%NS%text-2); font-size: 12px; -}`]})},wk=864e13,Tk=200,Ek=300,Dk=100,Ok=10,kk=100,Ak=2e3,jk=2e3,Mk=4e3,Nk=1e3,Pk=100,Fk={component:`c`,hook:`h`,afterRender:`r`,output:`o`},Ik=Object.values(Fk),Lk=e=>!!e&&typeof e==`object`&&!Array.isArray(e),Rk=e=>typeof e==`number`&&Number.isFinite(e)&&e>=0?e:0,zk=(e,t)=>typeof e==`string`?e.slice(0,t):``,Bk=e=>Rk(e)>0?Rk(e):void 0,Vk=(e,t)=>Array.isArray(e)?e.slice(0,t):[];function Hk(e){if(!Lk(e))return null;let t=zk(e.name,Tk);return t?{name:t,checks:Rk(e.checks),ms:Rk(e.ms)}:null}function Uk(e,t){if(!Array.isArray(e)||e.length!==5)return null;let[n,r,i,a,o]=e;return typeof n!=`number`||!Number.isInteger(n)||n<0||n>=t||typeof r!=`number`||!Number.isFinite(r)||Math.abs(r)>1e7||typeof a!=`number`||!Number.isInteger(a)||a<0||a>Nk||typeof o!=`string`||!Ik.includes(o)?null:[n,r,Rk(i),a,o]}function Wk(e,t){if(!Lk(e)||typeof e.id!=`number`)return null;let n=Vk(e.components,Ok).map(Hk).filter(e=>!!e),r=zk(e.trigger,Ek),i=Vk(e.spans,40).map(e=>Uk(e,t)).filter(e=>!!e),a=Array.isArray(e.spans)?e.spans.length-40:0,o=Math.floor(Rk(e.droppedSpans))+Math.max(0,a),s={t:typeof e.t==`number`?Rk(e.t):void 0,hookMs:Bk(e.hookMs),afterRenderMs:Bk(e.afterRenderMs),outputMs:Bk(e.outputMs)};return{id:Rk(e.id),at:Rk(e.at),ms:Rk(e.ms),passes:Rk(e.passes),...r?{trigger:r}:{},checks:Rk(e.checks),components:n,...Object.fromEntries(Object.entries(s).filter(([,e])=>e!==void 0)),...i.length?{spans:i}:{},...o?{droppedSpans:o}:{}}}function Gk(e){let t=Hk(e);return!t||!Lk(e)?null:{...t,maxMs:Rk(e.maxMs),cycles:Rk(e.cycles)}}function Kk(e){if(!Lk(e))return null;let t=zk(e.name,Tk),n=zk(e.hook,Dk);if(!t||!n)return null;let{calls:r,ms:i,maxMs:a}=e;return{name:t,hook:n,calls:Rk(r),ms:Rk(i),maxMs:Rk(a)}}function qk(e){if(!Lk(e))return null;let t=zk(e.name,Tk);if(!t)return null;let n=zk(e.listener,Tk);return{name:t,...n?{listener:n}:{},calls:Rk(e.calls),ms:Rk(e.ms),maxMs:Rk(e.maxMs)}}function Jk(e){if(Lk(e)&&Rk(e.runs))return{runs:Rk(e.runs),ms:Rk(e.ms),maxMs:Rk(e.maxMs)}}function Yk(e,t){if(!Lk(e))return null;let n=Vk(e.spanNames,Mk).map(e=>zk(e,Ek)),r=Array.isArray(e.cycles)?e.cycles.slice(-Math.min(t,jk)).map(e=>Wk(e,n.length)).filter(e=>!!e):[],i={},a=0;if(Lk(e.hosts)){let t=Object.entries(e.hosts);a=Math.max(0,t.length-Ak);for(let[e,n]of t.slice(0,Ak))e.length<50&&Rk(n)&&(i[e]=Rk(n))}let o=Array.isArray(e.components)?e.components:[],s=Math.floor(Rk(e.droppedClasses))+Math.max(0,o.length-kk),c=Math.floor(Rk(e.droppedHosts))+a,l=Vk(e.hooks,Pk).map(Kk).filter(e=>!!e),u=Vk(e.outputs,Pk).map(qk).filter(e=>!!e),d=Math.max(0,Vk(e.hooks,1/0).length-Pk)+Math.max(0,Vk(e.outputs,1/0).length-Pk),f=Math.floor(Rk(e.droppedTimings))+d,p=Jk(e.afterRender),m=r.some(e=>e.spans?.length);return{recording:e.recording===!0,startedAt:typeof e.startedAt==`number`&&e.startedAt<=wk?Rk(e.startedAt):null,dropped:Rk(e.dropped),cycles:r,components:o.slice(0,kk).map(Gk).filter(e=>!!e),...s?{droppedClasses:s}:{},hosts:i,...c?{droppedHosts:c}:{},...l.length?{hooks:l}:{},...u.length?{outputs:u}:{},...f?{droppedTimings:f}:{},...p?{afterRender:p}:{},...m?{spanNames:n}:{}}}var Xk=`pangular-inspector/change-detection`;function Zk(e,t,n=Date.now()){return{format:Xk,version:1,exportedAt:n,pageId:t,recording:{...Yk(e,jk)??e,recording:!1,hosts:{}}}}function Qk(e,t){if(e.length>2e7||e.length*3>2e7&&new TextEncoder().encode(e).byteLength>2e7)return{ok:!1,error:`The file is larger than 20 MB.`};let n;try{n=JSON.parse(e)}catch{return{ok:!1,error:`The file is not valid JSON.`}}if(!Lk(n))return{ok:!1,error:`The file is not a recording.`};if(n.format!==void 0&&n.format!==`pangular-inspector/change-detection`)return{ok:!1,error:`The file is not a change detection recording.`};let r=Lk(n.recording)?n.recording:n;if(!Array.isArray(r.cycles))return{ok:!1,error:`The file has no change detection cycles.`};let i=Yk(r,t);if(!i)return{ok:!1,error:`The file is not a recording.`};let a=zk(n.pageId??r.pageId,49)||`imported`,o=Bk(n.exportedAt);return{ok:!0,pageId:a,...o?{exportedAt:o}:{},recording:{...i,recording:!1}}}var $k=1,eA=1,tA=2,nA={c:`component`,h:`lifecycle-hook`,r:`after-render`,o:`output`},rA=e=>Math.round(e*1e6)/1e3;function iA(e,t){let n=e.spanNames??[],r=e.cycles[0]?.at??0,i=e.startedAt??r,a=[],o=0,s=0;for(let t of e.cycles){let e=t.t??Math.max(0,t.at-i),r=e+t.ms;a.push({name:`Change detection #${t.id}`,cat:`change-detection`,ph:`X`,pid:$k,tid:eA,ts:rA(e),dur:rA(t.ms),args:{checks:t.checks,passes:t.passes,...t.trigger?{trigger:t.trigger}:{},...t.hookMs?{hookMs:t.hookMs}:{},...t.afterRenderMs?{afterRenderMs:t.afterRenderMs}:{},...t.outputMs?{outputMs:t.outputMs}:{},slowest:t.components.map(e=>`${e.name} ${e.checks}x ${e.ms}ms`)}}),s+=t.droppedSpans??0;let c=[{end:r}],l=[...t.spans??[]].sort((e,t)=>e[1]-t[1]||t[2]-e[2]);for(let[r,i,s,u,d]of l){o++;let l=n[r]??`?`;if(d===Fk.output){let n=e+i;a.push({name:l,cat:nA[d],ph:`X`,pid:$k,tid:tA,ts:rA(n),dur:rA(i<0?Math.max(0,Math.min(s,-i)):s),args:{cycle:t.id}});continue}let f=Math.max(e,e+i);for(;c.length>1&&c.at(-1).end<=f;)c.pop();let p=c.at(-1).end,m=Math.min(f+s,p);me.ts??0));if(c<0)for(let e of a)e.ts=rA((e.ts-c)/1e3);a.sort((e,t)=>e.ts-t.ts||t.dur-e.dur);let l=(e,t,n)=>({name:t,ph:`M`,pid:$k,tid:e,args:{name:n}});return{traceEvents:[l(0,`process_name`,`Angular change detection (page ${t})`),l(eA,`thread_name`,`Change detection`),l(tA,`thread_name`,`Outputs`),...a],displayTimeUnit:`ms`,otherData:{source:`Pangular Inspector change detection recording`,pageId:t,cycles:e.cycles.length,droppedCycles:e.dropped,spans:o,droppedSpans:s,...e.startedAt&&e.startedAt<=wk?{startedAt:new Date(e.startedAt).toISOString()}:{}}}}function aA(e,t){if(e&1&&(B(0,`p`,5),J(1),V()),e&2){let e=G();A(),Y(e.error())}}function oA(e,t){let n=new Blob([JSON.stringify(e,null,2)],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=t,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),0)}var sA=class e{page=$(null);maxCycles=$(200);imported=Rv();error=k(``);hasCycles(){return(this.page()?.cycles.length??0)>0}exportJson(){let e=this.page();e&&oA(Zk(e,e.pageId),`change-detection-${e.pageId}.json`)}exportTrace(){let e=this.page();e&&oA(iA(e,e.pageId),`change-detection-${e.pageId}.trace.json`)}async read(e){let t=e.files?.[0];if(e.value=``,!t)return;if(t.size>2e7){this.error.set(`${t.name}: The file is larger than 20 MB.`);return}let n;try{n=await t.text()}catch{this.error.set(`Could not read the file.`);return}let r=Qk(n,this.maxCycles());if(!r.ok){this.error.set(`${t.name}: ${r.error}`);return}this.error.set(``),this.imported.emit({fileName:t.name,page:{...r.recording,pageId:r.pageId,supported:!0}})}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-transfer`]],inputs:{page:[1,`page`],maxCycles:[1,`maxCycles`]},outputs:{imported:`imported`},decls:10,vars:3,consts:[[`file`,``],[`role`,`group`,`aria-label`,`Export and import the recording`,1,`transfer`],[`type`,`button`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[`type`,`file`,`accept`,`.json,application/json`,`hidden`,``,3,`change`],[`role`,`alert`,1,`error`]],template:function(e,t){if(e&1){let e=H();B(0,`div`,1)(1,`button`,2),W(`click`,function(){return t.exportJson()}),J(2,`Export JSON`),V(),B(3,`button`,2),W(`click`,function(){return t.exportTrace()}),J(4,` Export trace (Perfetto) `),V(),B(5,`button`,3),W(`click`,function(){return E(e),D(d_(8).click())}),J(6,`Import`),V(),B(7,`input`,4,0),W(`change`,function(){E(e);let n=d_(8);return D(t.read(n))}),V()(),M(9,aA,2,1,`p`,5)}e&2&&(A(),qg(`disabled`,!t.hasCycles()),A(2),qg(`disabled`,!t.hasCycles()),A(6),N(t.error()?9:-1))},styles:[`[_nghost-%COMP%] { +}`]})},Bk=864e13,Vk=200,Hk=300,Uk=100,Wk=10,Gk=100,Kk=2e3,qk=2e3,Jk=4e3,Yk=1e3,Xk=100,Zk={component:`c`,hook:`h`,afterRender:`r`,output:`o`},Qk=Object.values(Zk),$k=e=>!!e&&typeof e==`object`&&!Array.isArray(e),eA=e=>typeof e==`number`&&Number.isFinite(e)&&e>=0?e:0,tA=(e,t)=>typeof e==`string`?e.slice(0,t):``,nA=e=>eA(e)>0?eA(e):void 0,rA=(e,t)=>Array.isArray(e)?e.slice(0,t):[];function iA(e){if(!$k(e))return null;let t=tA(e.name,Vk);return t?{name:t,checks:eA(e.checks),ms:eA(e.ms)}:null}function aA(e,t){if(!Array.isArray(e)||e.length!==5)return null;let[n,r,i,a,o]=e;return typeof n!=`number`||!Number.isInteger(n)||n<0||n>=t||typeof r!=`number`||!Number.isFinite(r)||Math.abs(r)>1e7||typeof a!=`number`||!Number.isInteger(a)||a<0||a>Yk||typeof o!=`string`||!Qk.includes(o)?null:[n,r,eA(i),a,o]}function oA(e,t){if(!$k(e)||typeof e.id!=`number`)return null;let n=rA(e.components,Wk).map(iA).filter(e=>!!e),r=tA(e.trigger,Hk),i=rA(e.spans,40).map(e=>aA(e,t)).filter(e=>!!e),a=Array.isArray(e.spans)?e.spans.length-40:0,o=Math.floor(eA(e.droppedSpans))+Math.max(0,a),s={t:typeof e.t==`number`?eA(e.t):void 0,hookMs:nA(e.hookMs),afterRenderMs:nA(e.afterRenderMs),outputMs:nA(e.outputMs)};return{id:eA(e.id),at:eA(e.at),ms:eA(e.ms),passes:eA(e.passes),...r?{trigger:r}:{},checks:eA(e.checks),components:n,...Object.fromEntries(Object.entries(s).filter(([,e])=>e!==void 0)),...i.length?{spans:i}:{},...o?{droppedSpans:o}:{}}}function sA(e){let t=iA(e);return!t||!$k(e)?null:{...t,maxMs:eA(e.maxMs),cycles:eA(e.cycles)}}function cA(e){if(!$k(e))return null;let t=tA(e.name,Vk),n=tA(e.hook,Uk);if(!t||!n)return null;let{calls:r,ms:i,maxMs:a}=e;return{name:t,hook:n,calls:eA(r),ms:eA(i),maxMs:eA(a)}}function lA(e){if(!$k(e))return null;let t=tA(e.name,Vk);if(!t)return null;let n=tA(e.listener,Vk);return{name:t,...n?{listener:n}:{},calls:eA(e.calls),ms:eA(e.ms),maxMs:eA(e.maxMs)}}function uA(e){if($k(e)&&eA(e.runs))return{runs:eA(e.runs),ms:eA(e.ms),maxMs:eA(e.maxMs)}}function dA(e,t){if(!$k(e))return null;let n=rA(e.spanNames,Jk).map(e=>tA(e,Hk)),r=Array.isArray(e.cycles)?e.cycles.slice(-Math.min(t,qk)).map(e=>oA(e,n.length)).filter(e=>!!e):[],i={},a=0;if($k(e.hosts)){let t=Object.entries(e.hosts);a=Math.max(0,t.length-Kk);for(let[e,n]of t.slice(0,Kk))e.length<50&&eA(n)&&(i[e]=eA(n))}let o=Array.isArray(e.components)?e.components:[],s=Math.floor(eA(e.droppedClasses))+Math.max(0,o.length-Gk),c=Math.floor(eA(e.droppedHosts))+a,l=rA(e.hooks,Xk).map(cA).filter(e=>!!e),u=rA(e.outputs,Xk).map(lA).filter(e=>!!e),d=Math.max(0,rA(e.hooks,1/0).length-Xk)+Math.max(0,rA(e.outputs,1/0).length-Xk),f=Math.floor(eA(e.droppedTimings))+d,p=uA(e.afterRender),m=r.some(e=>e.spans?.length);return{recording:e.recording===!0,startedAt:typeof e.startedAt==`number`&&e.startedAt<=Bk?eA(e.startedAt):null,dropped:eA(e.dropped),cycles:r,components:o.slice(0,Gk).map(sA).filter(e=>!!e),...s?{droppedClasses:s}:{},hosts:i,...c?{droppedHosts:c}:{},...l.length?{hooks:l}:{},...u.length?{outputs:u}:{},...f?{droppedTimings:f}:{},...p?{afterRender:p}:{},...m?{spanNames:n}:{}}}var fA=`pangular-inspector/change-detection`;function pA(e,t,n=Date.now()){return{format:fA,version:1,exportedAt:n,pageId:t,recording:{...dA(e,qk)??e,recording:!1,hosts:{}}}}function mA(e,t){if(e.length>2e7||e.length*3>2e7&&new TextEncoder().encode(e).byteLength>2e7)return{ok:!1,error:`The file is larger than 20 MB.`};let n;try{n=JSON.parse(e)}catch{return{ok:!1,error:`The file is not valid JSON.`}}if(!$k(n))return{ok:!1,error:`The file is not a recording.`};if(n.format!==void 0&&n.format!==`pangular-inspector/change-detection`)return{ok:!1,error:`The file is not a change detection recording.`};let r=$k(n.recording)?n.recording:n;if(!Array.isArray(r.cycles))return{ok:!1,error:`The file has no change detection cycles.`};let i=dA(r,t);if(!i)return{ok:!1,error:`The file is not a recording.`};let a=tA(n.pageId??r.pageId,49)||`imported`,o=nA(n.exportedAt);return{ok:!0,pageId:a,...o?{exportedAt:o}:{},recording:{...i,recording:!1}}}var hA=1,gA=1,_A=2,vA={c:`component`,h:`lifecycle-hook`,r:`after-render`,o:`output`},yA=e=>Math.round(e*1e6)/1e3;function bA(e,t){let n=e.spanNames??[],r=e.cycles[0]?.at??0,i=e.startedAt??r,a=[],o=0,s=0;for(let t of e.cycles){let e=t.t??Math.max(0,t.at-i),r=e+t.ms;a.push({name:`Change detection #${t.id}`,cat:`change-detection`,ph:`X`,pid:hA,tid:gA,ts:yA(e),dur:yA(t.ms),args:{checks:t.checks,passes:t.passes,...t.trigger?{trigger:t.trigger}:{},...t.hookMs?{hookMs:t.hookMs}:{},...t.afterRenderMs?{afterRenderMs:t.afterRenderMs}:{},...t.outputMs?{outputMs:t.outputMs}:{},slowest:t.components.map(e=>`${e.name} ${e.checks}x ${e.ms}ms`)}}),s+=t.droppedSpans??0;let c=[{end:r}],l=[...t.spans??[]].sort((e,t)=>e[1]-t[1]||t[2]-e[2]);for(let[r,i,s,u,d]of l){o++;let l=n[r]??`?`;if(d===Zk.output){let n=e+i;a.push({name:l,cat:vA[d],ph:`X`,pid:hA,tid:_A,ts:yA(n),dur:yA(i<0?Math.max(0,Math.min(s,-i)):s),args:{cycle:t.id}});continue}let f=Math.max(e,e+i);for(;c.length>1&&c.at(-1).end<=f;)c.pop();let p=c.at(-1).end,m=Math.min(f+s,p);me.ts??0));if(c<0)for(let e of a)e.ts=yA((e.ts-c)/1e3);a.sort((e,t)=>e.ts-t.ts||t.dur-e.dur);let l=(e,t,n)=>({name:t,ph:`M`,pid:hA,tid:e,args:{name:n}});return{traceEvents:[l(0,`process_name`,`Angular change detection (page ${t})`),l(gA,`thread_name`,`Change detection`),l(_A,`thread_name`,`Outputs`),...a],displayTimeUnit:`ms`,otherData:{source:`Pangular Inspector change detection recording`,pageId:t,cycles:e.cycles.length,droppedCycles:e.dropped,spans:o,droppedSpans:s,...e.startedAt&&e.startedAt<=Bk?{startedAt:new Date(e.startedAt).toISOString()}:{}}}}function xA(e,t){if(e&1&&(B(0,`p`,5),J(1),V()),e&2){let e=G();A(),Y(e.error())}}function SA(e,t){let n=new Blob([JSON.stringify(e,null,2)],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=t,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),0)}var CA=class e{page=$(null);maxCycles=$(200);imported=Rv();error=k(``);hasCycles(){return(this.page()?.cycles.length??0)>0}exportJson(){let e=this.page();e&&SA(pA(e,e.pageId),`change-detection-${e.pageId}.json`)}exportTrace(){let e=this.page();e&&SA(bA(e,e.pageId),`change-detection-${e.pageId}.trace.json`)}async read(e){let t=e.files?.[0];if(e.value=``,!t)return;if(t.size>2e7){this.error.set(`${t.name}: The file is larger than 20 MB.`);return}let n;try{n=await t.text()}catch{this.error.set(`Could not read the file.`);return}let r=mA(n,this.maxCycles());if(!r.ok){this.error.set(`${t.name}: ${r.error}`);return}this.error.set(``),this.imported.emit({fileName:t.name,page:{...r.recording,pageId:r.pageId,supported:!0}})}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-transfer`]],inputs:{page:[1,`page`],maxCycles:[1,`maxCycles`]},outputs:{imported:`imported`},decls:10,vars:3,consts:[[`file`,``],[`role`,`group`,`aria-label`,`Export and import the recording`,1,`transfer`],[`type`,`button`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[`type`,`file`,`accept`,`.json,application/json`,`hidden`,``,3,`change`],[`role`,`alert`,1,`error`]],template:function(e,t){if(e&1){let e=H();B(0,`div`,1)(1,`button`,2),W(`click`,function(){return t.exportJson()}),J(2,`Export JSON`),V(),B(3,`button`,2),W(`click`,function(){return t.exportTrace()}),J(4,` Export trace (Perfetto) `),V(),B(5,`button`,3),W(`click`,function(){return E(e),D(d_(8).click())}),J(6,`Import`),V(),B(7,`input`,4,0),W(`change`,function(){E(e);let n=d_(8);return D(t.read(n))}),V()(),M(9,xA,2,1,`p`,5)}e&2&&(A(),qg(`disabled`,!t.hasCycles()),A(2),qg(`disabled`,!t.hasCycles()),A(6),N(t.error()?9:-1))},styles:[`[_nghost-%COMP%] { display: contents; } @@ -1407,7 +1407,7 @@ button[_ngcontent-%COMP%]:disabled { margin: 0; color: var(--%NS%danger-text); font-size: 12px; -}`]})},cA=(e,t)=>t.stat.name;function lA(e,t){if(e&1&&(B(0,`span`,8),J(1),V()),e&2){let e=G(2).$implicit;A(),X(``,e.other,` more`)}}function uA(e,t){if(e&1&&(B(0,`div`,6)(1,`span`,7),J(2),V(),M(3,lA,2,1,`span`,8),V()),e&2){let e=G().$implicit;K(`--%NS%tone`,e.tone+`%`),A(2),Y(e.label),A(),N(e.roomy?3:-1)}}function dA(e,t){if(e&1&&(B(0,`span`,10),J(1),V(),B(2,`span`,11),J(3),V()),e&2){let e=G(2).$implicit,t=G(2);A(),Y(e.stat.name),A(2),Y(t.fmt(e.stat.ms))}}function fA(e,t){if(e&1){let e=H();B(0,`button`,9),W(`focus`,function(){E(e);let t=G().$index;return D(G(2).current.set(t))})(`click`,function(){E(e);let t=G().$implicit;return D(G(2).pick.emit(t.stat.name))}),M(1,dA,4,2),V()}if(e&2){let e=G(),t=e.$implicit,n=e.$index,r=G(2);K(`--%NS%tone`,t.tone+`%`),j(`tabindex`,n===r.tabStop()?0:-1)(`aria-label`,t.label)(`data-index`,n),A(),N(t.roomy?1:-1)}}function pA(e,t){if(e&1&&(B(0,`li`),M(1,uA,4,4,`div`,4)(2,fA,2,6,`button`,5),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`top`,e.y,`%`)(`width`,e.w,`%`)(`height`,e.h,`%`),A(),N(e.other?1:2)}}function mA(e,t){if(e&1){let e=H();B(0,`ul`,2),W(`keydown`,function(t){return E(e),D(G().onKey(t))}),P(1,pA,3,9,`li`,3,cA),V()}if(e&2){let e=G();j(`aria-label`,e.label()),A(),F(e.cells())}}function hA(e,t){e&1&&(B(0,`p`,1),J(1,`No component time in these cycles.`),V())}var gA=24,_A=3,vA=class e{stats=$([]);scope=$(`the recording`);pick=Rv();current=k(0);label=Q(()=>`Self time per component in ${this.scope()}, largest first. Pick one to show it in the tree.`);cells=Q(()=>{let e=this.stats().filter(e=>e.ms>0),t=e.slice(0,gA),n=e.slice(gA),r=n.reduce((e,t)=>e+t.ms,0),i=t.map(e=>({stat:e,other:0}));n.length&&i.push({stat:{name:`Other components`,checks:0,ms:r,maxMs:0,cycles:0},other:n.length});let a=e.reduce((e,t)=>e+t.ms,0),o=t[0]?.ms??1,s=MO(i,e=>e.stat.ms,_A);return s.sort((e,t)=>Number(e.item.other>0)-Number(t.item.other>0)),s.map(e=>{let{stat:t,other:n}=e.item,r=a?Math.round(t.ms/a*100):0;return{stat:t,other:n,x:e.x,y:e.y,w:e.w,h:e.h,tone:n?0:14+Math.round(26*Math.min(t.ms/o,1)),roomy:e.w>=10&&e.h>=22,label:n?`${n} more components, ${OO(t.ms)}, ${r}% of self time`:`${t.name}, ${OO(t.ms)} self time, ${r}%, ${t.checks} ${t.checks===1?`check`:`checks`}`}})});tabStop=Q(()=>Math.min(this.current(),Math.max(this.cells().filter(e=>!e.other).length-1,0)));fmt(e){return OO(e)}onKey(e){let t=this.cells().filter(e=>!e.other).length;if(!t)return;let n=this.tabStop(),r;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=Math.min(n+1,t-1);break;case`ArrowLeft`:case`ArrowUp`:r=Math.max(n-1,0);break;case`Home`:r=0;break;case`End`:r=t-1;break;default:return}e.preventDefault(),this.current.set(r),e.currentTarget.querySelector(`button[data-index="${r}"]`)?.focus()}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-treemap`]],inputs:{stats:[1,`stats`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:2,vars:1,consts:[[1,`map`],[1,`empty`],[1,`map`,3,`keydown`],[3,`left`,`top`,`width`,`height`],[1,`cell`,`other`,3,`--%NS%tone`],[`type`,`button`,1,`cell`,3,`--%NS%tone`],[1,`cell`,`other`],[1,`sr-only`],[`aria-hidden`,`true`,1,`name`],[`type`,`button`,1,`cell`,3,`focus`,`click`],[1,`name`,`mono`],[1,`ms`]],template:function(e,t){e&1&&M(0,mA,3,1,`ul`,0)(1,hA,2,0,`p`,1),e&2&&N(+!t.cells().length)},styles:[`[_nghost-%COMP%] { +}`]})},wA=(e,t)=>t.stat.name;function TA(e,t){if(e&1&&(B(0,`span`,8),J(1),V()),e&2){let e=G(2).$implicit;A(),X(``,e.other,` more`)}}function EA(e,t){if(e&1&&(B(0,`div`,6)(1,`span`,7),J(2),V(),M(3,TA,2,1,`span`,8),V()),e&2){let e=G().$implicit;K(`--%NS%tone`,e.tone+`%`),A(2),Y(e.label),A(),N(e.roomy?3:-1)}}function DA(e,t){if(e&1&&(B(0,`span`,10),J(1),V(),B(2,`span`,11),J(3),V()),e&2){let e=G(2).$implicit,t=G(2);A(),Y(e.stat.name),A(2),Y(t.fmt(e.stat.ms))}}function OA(e,t){if(e&1){let e=H();B(0,`button`,9),W(`focus`,function(){E(e);let t=G().$index;return D(G(2).current.set(t))})(`click`,function(){E(e);let t=G().$implicit;return D(G(2).pick.emit(t.stat.name))}),M(1,DA,4,2),V()}if(e&2){let e=G(),t=e.$implicit,n=e.$index,r=G(2);K(`--%NS%tone`,t.tone+`%`),j(`tabindex`,n===r.tabStop()?0:-1)(`aria-label`,t.label)(`data-index`,n),A(),N(t.roomy?1:-1)}}function kA(e,t){if(e&1&&(B(0,`li`),M(1,EA,4,4,`div`,4)(2,OA,2,6,`button`,5),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`top`,e.y,`%`)(`width`,e.w,`%`)(`height`,e.h,`%`),A(),N(e.other?1:2)}}function AA(e,t){if(e&1){let e=H();B(0,`ul`,2),W(`keydown`,function(t){return E(e),D(G().onKey(t))}),P(1,kA,3,9,`li`,3,wA),V()}if(e&2){let e=G();j(`aria-label`,e.label()),A(),F(e.cells())}}function jA(e,t){e&1&&(B(0,`p`,1),J(1,`No component time in these cycles.`),V())}var MA=24,NA=3,PA=class e{stats=$([]);scope=$(`the recording`);pick=Rv();current=k(0);label=Q(()=>`Self time per component in ${this.scope()}, largest first. Pick one to show it in the tree.`);cells=Q(()=>{let e=this.stats().filter(e=>e.ms>0),t=e.slice(0,MA),n=e.slice(MA),r=n.reduce((e,t)=>e+t.ms,0),i=t.map(e=>({stat:e,other:0}));n.length&&i.push({stat:{name:`Other components`,checks:0,ms:r,maxMs:0,cycles:0},other:n.length});let a=e.reduce((e,t)=>e+t.ms,0),o=t[0]?.ms??1,s=JO(i,e=>e.stat.ms,NA);return s.sort((e,t)=>Number(e.item.other>0)-Number(t.item.other>0)),s.map(e=>{let{stat:t,other:n}=e.item,r=a?Math.round(t.ms/a*100):0;return{stat:t,other:n,x:e.x,y:e.y,w:e.w,h:e.h,tone:n?0:14+Math.round(26*Math.min(t.ms/o,1)),roomy:e.w>=10&&e.h>=22,label:n?`${n} more components, ${WO(t.ms)}, ${r}% of self time`:`${t.name}, ${WO(t.ms)} self time, ${r}%, ${t.checks} ${t.checks===1?`check`:`checks`}`}})});tabStop=Q(()=>Math.min(this.current(),Math.max(this.cells().filter(e=>!e.other).length-1,0)));fmt(e){return WO(e)}onKey(e){let t=this.cells().filter(e=>!e.other).length;if(!t)return;let n=this.tabStop(),r;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=Math.min(n+1,t-1);break;case`ArrowLeft`:case`ArrowUp`:r=Math.max(n-1,0);break;case`Home`:r=0;break;case`End`:r=t-1;break;default:return}e.preventDefault(),this.current.set(r),e.currentTarget.querySelector(`button[data-index="${r}"]`)?.focus()}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-treemap`]],inputs:{stats:[1,`stats`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:2,vars:1,consts:[[1,`map`],[1,`empty`],[1,`map`,3,`keydown`],[3,`left`,`top`,`width`,`height`],[1,`cell`,`other`,3,`--%NS%tone`],[`type`,`button`,1,`cell`,3,`--%NS%tone`],[1,`cell`,`other`],[1,`sr-only`],[`aria-hidden`,`true`,1,`name`],[`type`,`button`,1,`cell`,3,`focus`,`click`],[1,`name`,`mono`],[1,`ms`]],template:function(e,t){e&1&&M(0,AA,3,1,`ul`,0)(1,jA,2,0,`p`,1),e&2&&N(+!t.cells().length)},styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1483,7 +1483,7 @@ button.cell[_ngcontent-%COMP%]:focus-visible { .empty[_ngcontent-%COMP%] { margin: 8px 0; color: var(--%NS%text-2); -}`]})},yA=(e,t)=>t.id;function bA(e,t){if(e&1){let e=H();L(0,`button`,14),U(`click`,function(){return E(e),D(G(2).clear())}),J(1,`Clear`),R()}}function xA(e,t){if(e&1){let e=H();L(0,`button`,11),U(`click`,function(){return E(e),D(G().toggle())}),z(1,`span`,12),J(2),R(),M(3,bA,2,0,`button`,13)}if(e&2){let e=G();q(`on`,e.recording()),I(`disabled`,!e.pageId()),A(2),X(` `,e.recording()?`Stop recording`:`Record`,` `),A(),N(e.cycles().length?3:-1)}}function SA(e,t){if(e&1){let e=H();L(0,`p`,6)(1,`span`,15),J(2,`Imported recording`),R(),L(3,`span`,16),J(4),R(),L(5,`button`,14),U(`click`,function(){return E(e),D(G().closeImport())}),J(6,`Back to live recording`),R()()}e&2&&(A(4),Y(t.fileName))}function CA(e,t){e&1&&(L(0,`p`,8),J(1,`This page can't record change detection. It needs Angular 20 or later.`),R())}function wA(e,t){e&1&&(L(0,`p`,8),J(1,`Angular profiling stays on until the page reloads.`),R())}function TA(e,t){e&1&&(L(0,`p`,8),J(1,` This page has no `),L(2,`span`,16),J(3,`ng.enableProfiling`),R(),J(4,`. It needs Angular 20 or later in a development build. `),R())}function EA(e,t){if(e&1){let e=H();L(0,`div`,17)(1,`span`,18),J(2,`Live views`),R(),L(3,`button`,19),U(`click`,function(){E(e);let t=G();return D(t.setView(`flash`,!t.views().flash))}),z(4,`span`,12),J(5,` Flash checks `),R(),L(6,`button`,19),U(`click`,function(){E(e);let t=G();return D(t.setView(`track`,!t.views().track))}),z(7,`span`,12),J(8,` Performance track `),R(),L(9,`button`,19),U(`click`,function(){return E(e),D(G().setView(`angularProfiling`,!0))}),z(10,`span`,12),J(11,` Angular profiling `),R()(),L(12,`p`,7),J(13,` Flash checks draws a box over each component on the page as Angular checks it, with its name and how often it was checked, fading over a second. Performance track adds a Pangular track to the Chrome Performance panel with every component check, hook and output. Angular profiling turns on Angular's own track there. `),R(),M(14,wA,2,0,`p`,8)(15,TA,5,0,`p`,8)}if(e&2){let e=G();A(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().flash),A(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().track),A(3),I(`disabled`,!e.canShowViews()||e.views().angularProfiling||!e.views().angularProfilingAvailable),j(`aria-pressed`,e.views().angularProfiling),A(5),N(e.views().angularProfiling?14:e.views().angularProfilingAvailable?-1:15)}}function DA(e,t){if(e&1&&(L(0,`p`,8),J(1),R()),e&2){let e=t.$implicit;A(),Y(e)}}function OA(e,t){if(e&1&&(L(0,`p`,22),J(1),R()),e&2){let e=G(2);A(),X(` `,e.range()?`The picked cycles have no timed spans, so there is no flame graph for them.`:`This recording has no timed spans, so there is no flame graph. A recording from an older version, or a file saved without spans, has none.`,` `)}}function kA(e,t){e&1&&(L(0,`p`,8),J(1,` For picked cycles, totals come from the 10 slowest components each cycle lists. `),R())}function AA(e,t){if(e&1){let e=H();L(0,`h3`),J(1,`Cycles`),R(),L(2,`app-cd-cycle-chart`,20),cv(`rangeChange`,function(t){E(e);let n=G();return sv(n.range,t)||(n.range=t),D(t)}),R(),L(3,`app-cd-flame-graph`,21),U(`pick`,function(t){return E(e),D(G().showComponent.emit(t))}),R(),M(4,OA,2,1,`p`,22),L(5,`h3`),J(6,`Self time by component`),R(),M(7,kA,2,0,`p`,8),L(8,`app-cd-treemap`,23),U(`pick`,function(t){return E(e),D(G().showComponent.emit(t))}),R()}if(e&2){let e=G();A(2),I(`cycles`,e.cycles()),ov(`range`,e.range),A(),I(`cycles`,e.picked())(`names`,e.spanNames())(`scope`,e.scope()),A(),N(e.hasSpans()?-1:4),A(3),N(e.range()?7:-1),A(),I(`stats`,e.stats())(`scope`,e.scope())}}function jA(e,t){if(e&1&&(L(0,`tr`)(1,`td`,16),J(2),R(),L(3,`td`,29),J(4),R(),L(5,`td`,29),J(6),R(),L(7,`td`,29),J(8),R()()),e&2){let e=t.$implicit,n=G(2);A(2),Y(e.name),A(2),Y(e.checks),A(2),Y(n.ms(e.ms)),A(2),Y(n.ms(e.maxMs))}}function MA(e,t){e&1&&(L(0,`tr`)(1,`td`,30),J(2,`No component time in the picked cycles.`),R()())}function NA(e,t){if(e&1&&(L(0,`span`,32),J(1,`after `),L(2,`span`,16),J(3),R()()),e&2){let e=G().$implicit;A(3),Y(e.trigger)}}function PA(e,t){if(e&1&&(L(0,`span`,33),J(1),R()),e&2){let e=G().$implicit,t=G(2);A(),X(`hooks `,t.ms(e.hookMs))}}function FA(e,t){if(e&1&&(L(0,`span`,33),J(1),R()),e&2){let e=G().$implicit,t=G(2);A(),X(`afterRender `,t.ms(e.afterRenderMs))}}function IA(e,t){if(e&1&&(L(0,`span`,34),J(1,` slowest `),L(2,`span`,16),J(3),R(),J(4),R()),e&2){let e=t,n=G(3);A(3),Y(e.name),A(),X(` `,n.ms(e.ms),` `)}}function LA(e,t){if(e&1&&(L(0,`li`)(1,`span`,31),J(2),R(),L(3,`span`,16),J(4),R(),L(5,`span`),J(6),R(),M(7,NA,4,1,`span`,32),M(8,PA,2,1,`span`,33),M(9,FA,2,1,`span`,33),M(10,IA,5,2,`span`,34),R()),e&2){let e,n=t.$implicit,r=G(2);A(2),Y(r.clock(n.at)),A(2),Y(r.ms(n.ms)),A(2),iv(` `,n.checks,` `,n.checks===1?`check`:`checks`,`, `,n.passes,` `,n.passes===1?`pass`:`passes`,` `),A(),N(n.trigger?7:-1),A(),N(n.hookMs?8:-1),A(),N(n.afterRenderMs?9:-1),A(),N((e=n.components[0])?10:-1,e)}}function RA(e,t){if(e&1&&(L(0,`div`,24)(1,`div`)(2,`h3`),J(3),R(),L(4,`table`)(5,`thead`)(6,`tr`)(7,`th`,25),J(8,`Component`),R(),L(9,`th`,26),J(10,`Checks`),R(),L(11,`th`,26),J(12,`Self time`),R(),L(13,`th`,26),J(14,`Slowest`),R()()(),L(15,`tbody`),P(16,jA,9,4,`tr`,null,kg,!1,MA,3,0,`tr`),R()()(),L(19,`div`)(20,`h3`),J(21,`Latest cycles`),R(),L(22,`ol`,27),P(23,LA,11,10,`li`,null,yA),R()()(),z(25,`app-cd-timing`,28)),e&2){let e=G();A(3),X(` `,e.range()?`Slowest components in the picked cycles`:`Slowest components`,` `),A(13),F(e.slowest()),A(7),F(e.latest()),A(2),I(`page`,e.page())}}function zA(e,t){e&1&&(L(0,`p`,10),J(1,`Use the app. Cycles show up here as Angular runs change detection.`),R())}var BA=10,VA=class e{livePage=$(null,{alias:`page`});pageId=$(null);rpc=$(null);showComponent=Rv();range=k(null);imported=k(null);page=Q(()=>this.imported()?.page??this.livePage());views=Fv(()=>this.livePage()?.options??{flash:!1,track:!1,angularProfiling:!1,angularProfilingAvailable:!0});canShowViews=Q(()=>!!this.pageId()&&this.livePage()?.supported!==!1);message=k(``);announcement=k(``);recording=Q(()=>this.page()?.recording===!0);cycles=Q(()=>this.page()?.cycles??[]);maxCycles=Q(()=>PE(this.rpc()).limits.cdCycles);picked=Q(()=>kO(this.cycles(),this.range()));hasSpans=Q(()=>this.picked().some(e=>e.spans?.length));spanNames=Q(()=>this.page()?.spanNames??[]);stats=Q(()=>this.range()?AO(this.picked()):[...this.page()?.components??[]].sort((e,t)=>t.ms-e.ms));scope=Q(()=>{let e=this.range()?this.picked():[];return e.length?e.length===1?`cycle ${e[0].id}`:`cycles ${e[0].id} to ${e.at(-1).id}`:`the recording`});slowest=Q(()=>this.stats().slice(0,BA));latest=Q(()=>this.cycles().slice(-30).reverse());capNotes=Q(()=>{let e=this.page()?.droppedClasses??0,t=this.page()?.droppedHosts??0,n=[];return e>0&&n.push(`${e} more component ${e===1?`class was`:`classes were`} checked than a recording keeps, so ${e===1?`it is`:`they are`} left out of these totals.`),t>0&&n.push(`${t} component ${t===1?`instance was`:`instances were`} checked past the 2000 a recording counts, so ${t===1?`its tree row shows`:`their tree rows show`} no check count.`),n});status=Q(()=>{if(this.message())return this.message();let e=this.cycles().length;return this.imported()?`${e} ${e===1?`cycle`:`cycles`} imported.`:this.recording()?`Recording. ${e} ${e===1?`cycle`:`cycles`} so far.`:e?`${e} ${e===1?`cycle`:`cycles`} recorded.`:``});ms(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}clock(e){return bO(e)}async toggle(){this.recording()?await this.send({on:!1},``,()=>{let e=this.cycles().length;return`Recording stopped. ${e} ${e===1?`cycle`:`cycles`} recorded.`}):await this.send({on:!0},`Starting…`,()=>`Recording started.`)}showImport(e){this.message.set(``),this.range.set(null),this.imported.set(e);let t=e.page.cycles.length;this.announce(`Imported ${e.fileName}: ${t} ${t===1?`cycle`:`cycles`}. Showing the imported recording.`)}closeImport(){this.imported.set(null),this.range.set(null),this.announce(`Showing the live recording.`)}async clear(){this.range.set(null),await this.send({clear:!0},``,()=>`Cleared the recorded cycles.`)}async setView(e,t){let n=this.views();this.views.set({...n,[e]:t});let r={flash:t?`Flash checks on.`:`Flash checks off.`,track:t?`Performance track on. Record in the Chrome Performance panel to see it.`:`Performance track off.`,angularProfiling:`Angular profiling on. It stays on until the page reloads.`}[e];await this.send({[e]:t},``,()=>r,`request-change-detection-options`)||this.views.set(n)}async send(e,t,n,r=`request-change-detection-record`){this.message.set(t);try{if(!this.rpc())throw Error(`no client`);return await yE(this.rpc(),r,{pageId:this.pageId(),...e}),this.message.set(``),this.announce(n()),!0}catch{let e=`Could not reach the page.`;return this.message.set(e),this.announce(e),!1}}announce(e){this.announcement.update(t=>t===e?`${e} `:e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-recording`]],inputs:{livePage:[1,`page`,`livePage`],pageId:[1,`pageId`],rpc:[1,`rpc`]},outputs:{showComponent:`showComponent`},decls:21,vars:12,consts:[[`aria-labelledby`,`cd-heading`,1,`cd`],[1,`cd-head`],[`id`,`cd-heading`],[3,`imported`,`page`,`maxCycles`],[1,`status`],[`role`,`status`,1,`sr-only`],[1,`imported`],[1,`hint`],[1,`note`],[`what`,`cycles`,`limit`,`cdCycles`,3,`dropped`,`max`],[1,`empty`],[`type`,`button`,3,`click`,`disabled`],[`aria-hidden`,`true`,1,`dot`],[`type`,`button`],[`type`,`button`,3,`click`],[1,`badge`],[1,`mono`],[`role`,`group`,`aria-labelledby`,`cd-views-label`,1,`views`],[`id`,`cd-views-label`,1,`views-label`],[`type`,`button`,1,`view`,3,`click`,`disabled`],[3,`rangeChange`,`cycles`,`range`],[3,`pick`,`cycles`,`names`,`scope`],[1,`spans-note`],[3,`pick`,`stats`,`scope`],[1,`cd-grid`],[`scope`,`col`],[`scope`,`col`,1,`num`],[`aria-label`,`Latest change detection cycles, newest first`,1,`cycles`],[3,`page`],[1,`num`],[`colspan`,`4`],[1,`when`],[1,`trigger`],[1,`timing`],[1,`top`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`h2`,2),J(3,`Change detection`),R(),M(4,xA,4,5),L(5,`app-cd-transfer`,3),U(`imported`,function(e){return t.showImport(e)}),R(),L(6,`p`,4),J(7),R(),L(8,`p`,5),J(9),R()(),M(10,SA,7,1,`p`,6),L(11,`p`,7),J(12,` Records each change detection cycle with Angular's profiler: how long it took, how many components it checked and the output that ran before it. Tree rows show how often each instance was checked. Times come from a development build. `),R(),M(13,CA,2,0,`p`,8),M(14,EA,16,7),z(15,`app-limit-note`,9),P(16,DA,2,1,`p`,8,Ag),M(18,AA,9,9),M(19,RA,26,3)(20,zA,2,0,`p`,10),R()),e&2){let e;A(4),N(t.imported()?-1:4),A(),I(`page`,t.page())(`maxCycles`,t.maxCycles()),A(2),Y(t.status()),A(2),Y(t.announcement()),A(),N((e=t.imported())?10:-1,e),A(3),N(t.page()?.supported===!1?13:-1),A(),N(t.imported()?-1:14),A(),I(`dropped`,t.page()?.dropped??0)(`max`,t.maxCycles()),A(),F(t.capNotes()),A(2),N(t.cycles().length?18:-1),A(),N(t.page()?.components?.length?19:t.recording()?20:-1)}},dependencies:[TO,Ck,sA,ZO,fk,vA],styles:[`[_nghost-%COMP%] { +}`]})},FA=(e,t)=>t.id;function IA(e,t){if(e&1){let e=H();L(0,`button`,14),U(`click`,function(){return E(e),D(G(2).clear())}),J(1,`Clear`),R()}}function LA(e,t){if(e&1){let e=H();L(0,`button`,11),U(`click`,function(){return E(e),D(G().toggle())}),z(1,`span`,12),J(2),R(),M(3,IA,2,0,`button`,13)}if(e&2){let e=G();q(`on`,e.recording()),I(`disabled`,!e.pageId()),A(2),X(` `,e.recording()?`Stop recording`:`Record`,` `),A(),N(e.cycles().length?3:-1)}}function RA(e,t){if(e&1){let e=H();L(0,`p`,6)(1,`span`,15),J(2,`Imported recording`),R(),L(3,`span`,16),J(4),R(),L(5,`button`,14),U(`click`,function(){return E(e),D(G().closeImport())}),J(6,`Back to live recording`),R()()}e&2&&(A(4),Y(t.fileName))}function zA(e,t){e&1&&(L(0,`p`,8),J(1,`This page can't record change detection. It needs Angular 20 or later.`),R())}function BA(e,t){e&1&&(L(0,`p`,8),J(1,`Angular profiling stays on until the page reloads.`),R())}function VA(e,t){e&1&&(L(0,`p`,8),J(1,` This page has no `),L(2,`span`,16),J(3,`ng.enableProfiling`),R(),J(4,`. It needs Angular 20 or later in a development build. `),R())}function HA(e,t){if(e&1){let e=H();L(0,`div`,17)(1,`span`,18),J(2,`Live views`),R(),L(3,`button`,19),U(`click`,function(){E(e);let t=G();return D(t.setView(`flash`,!t.views().flash))}),z(4,`span`,12),J(5,` Flash checks `),R(),L(6,`button`,19),U(`click`,function(){E(e);let t=G();return D(t.setView(`track`,!t.views().track))}),z(7,`span`,12),J(8,` Performance track `),R(),L(9,`button`,19),U(`click`,function(){return E(e),D(G().setView(`angularProfiling`,!0))}),z(10,`span`,12),J(11,` Angular profiling `),R()(),L(12,`p`,7),J(13,` Flash checks draws a box over each component on the page as Angular checks it, with its name and how often it was checked, fading over a second. Performance track adds a Pangular track to the Chrome Performance panel with every component check, hook and output. Angular profiling turns on Angular's own track there. `),R(),M(14,BA,2,0,`p`,8)(15,VA,5,0,`p`,8)}if(e&2){let e=G();A(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().flash),A(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().track),A(3),I(`disabled`,!e.canShowViews()||e.views().angularProfiling||!e.views().angularProfilingAvailable),j(`aria-pressed`,e.views().angularProfiling),A(5),N(e.views().angularProfiling?14:e.views().angularProfilingAvailable?-1:15)}}function UA(e,t){if(e&1&&(L(0,`p`,8),J(1),R()),e&2){let e=t.$implicit;A(),Y(e)}}function WA(e,t){if(e&1&&(L(0,`p`,22),J(1),R()),e&2){let e=G(2);A(),X(` `,e.range()?`The picked cycles have no timed spans, so there is no flame graph for them.`:`This recording has no timed spans, so there is no flame graph. A recording from an older version, or a file saved without spans, has none.`,` `)}}function GA(e,t){e&1&&(L(0,`p`,8),J(1,` For picked cycles, totals come from the 10 slowest components each cycle lists. `),R())}function KA(e,t){if(e&1){let e=H();L(0,`h3`),J(1,`Cycles`),R(),L(2,`app-cd-cycle-chart`,20),cv(`rangeChange`,function(t){E(e);let n=G();return sv(n.range,t)||(n.range=t),D(t)}),R(),L(3,`app-cd-flame-graph`,21),U(`pick`,function(t){return E(e),D(G().showComponent.emit(t))}),R(),M(4,WA,2,1,`p`,22),L(5,`h3`),J(6,`Self time by component`),R(),M(7,GA,2,0,`p`,8),L(8,`app-cd-treemap`,23),U(`pick`,function(t){return E(e),D(G().showComponent.emit(t))}),R()}if(e&2){let e=G();A(2),I(`cycles`,e.cycles()),ov(`range`,e.range),A(),I(`cycles`,e.picked())(`names`,e.spanNames())(`scope`,e.scope()),A(),N(e.hasSpans()?-1:4),A(3),N(e.range()?7:-1),A(),I(`stats`,e.stats())(`scope`,e.scope())}}function qA(e,t){if(e&1&&(L(0,`tr`)(1,`td`,16),J(2),R(),L(3,`td`,29),J(4),R(),L(5,`td`,29),J(6),R(),L(7,`td`,29),J(8),R()()),e&2){let e=t.$implicit,n=G(2);A(2),Y(e.name),A(2),Y(e.checks),A(2),Y(n.ms(e.ms)),A(2),Y(n.ms(e.maxMs))}}function JA(e,t){e&1&&(L(0,`tr`)(1,`td`,30),J(2,`No component time in the picked cycles.`),R()())}function YA(e,t){if(e&1&&(L(0,`span`,32),J(1,`after `),L(2,`span`,16),J(3),R()()),e&2){let e=G().$implicit;A(3),Y(e.trigger)}}function XA(e,t){if(e&1&&(L(0,`span`,33),J(1),R()),e&2){let e=G().$implicit,t=G(2);A(),X(`hooks `,t.ms(e.hookMs))}}function ZA(e,t){if(e&1&&(L(0,`span`,33),J(1),R()),e&2){let e=G().$implicit,t=G(2);A(),X(`afterRender `,t.ms(e.afterRenderMs))}}function QA(e,t){if(e&1&&(L(0,`span`,34),J(1,` slowest `),L(2,`span`,16),J(3),R(),J(4),R()),e&2){let e=t,n=G(3);A(3),Y(e.name),A(),X(` `,n.ms(e.ms),` `)}}function $A(e,t){if(e&1&&(L(0,`li`)(1,`span`,31),J(2),R(),L(3,`span`,16),J(4),R(),L(5,`span`),J(6),R(),M(7,YA,4,1,`span`,32),M(8,XA,2,1,`span`,33),M(9,ZA,2,1,`span`,33),M(10,QA,5,2,`span`,34),R()),e&2){let e,n=t.$implicit,r=G(2);A(2),Y(r.clock(n.at)),A(2),Y(r.ms(n.ms)),A(2),iv(` `,n.checks,` `,n.checks===1?`check`:`checks`,`, `,n.passes,` `,n.passes===1?`pass`:`passes`,` `),A(),N(n.trigger?7:-1),A(),N(n.hookMs?8:-1),A(),N(n.afterRenderMs?9:-1),A(),N((e=n.components[0])?10:-1,e)}}function ej(e,t){if(e&1&&(L(0,`div`,24)(1,`div`)(2,`h3`),J(3),R(),L(4,`table`)(5,`thead`)(6,`tr`)(7,`th`,25),J(8,`Component`),R(),L(9,`th`,26),J(10,`Checks`),R(),L(11,`th`,26),J(12,`Self time`),R(),L(13,`th`,26),J(14,`Slowest`),R()()(),L(15,`tbody`),P(16,qA,9,4,`tr`,null,kg,!1,JA,3,0,`tr`),R()()(),L(19,`div`)(20,`h3`),J(21,`Latest cycles`),R(),L(22,`ol`,27),P(23,$A,11,10,`li`,null,FA),R()()(),z(25,`app-cd-timing`,28)),e&2){let e=G();A(3),X(` `,e.range()?`Slowest components in the picked cycles`:`Slowest components`,` `),A(13),F(e.slowest()),A(7),F(e.latest()),A(2),I(`page`,e.page())}}function tj(e,t){e&1&&(L(0,`p`,10),J(1,`Use the app. Cycles show up here as Angular runs change detection.`),R())}var nj=10,rj=class e{livePage=$(null,{alias:`page`});pageId=$(null);rpc=$(null);showComponent=Rv();range=k(null);imported=k(null);page=Q(()=>this.imported()?.page??this.livePage());views=Fv(()=>this.livePage()?.options??{flash:!1,track:!1,angularProfiling:!1,angularProfilingAvailable:!0});canShowViews=Q(()=>!!this.pageId()&&this.livePage()?.supported!==!1);message=k(``);announcement=k(``);recording=Q(()=>this.page()?.recording===!0);cycles=Q(()=>this.page()?.cycles??[]);maxCycles=Q(()=>JE(this.rpc()).limits.cdCycles);picked=Q(()=>GO(this.cycles(),this.range()));hasSpans=Q(()=>this.picked().some(e=>e.spans?.length));spanNames=Q(()=>this.page()?.spanNames??[]);stats=Q(()=>this.range()?KO(this.picked()):[...this.page()?.components??[]].sort((e,t)=>t.ms-e.ms));scope=Q(()=>{let e=this.range()?this.picked():[];return e.length?e.length===1?`cycle ${e[0].id}`:`cycles ${e[0].id} to ${e.at(-1).id}`:`the recording`});slowest=Q(()=>this.stats().slice(0,nj));latest=Q(()=>this.cycles().slice(-30).reverse());capNotes=Q(()=>{let e=this.page()?.droppedClasses??0,t=this.page()?.droppedHosts??0,n=[];return e>0&&n.push(`${e} more component ${e===1?`class was`:`classes were`} checked than a recording keeps, so ${e===1?`it is`:`they are`} left out of these totals.`),t>0&&n.push(`${t} component ${t===1?`instance was`:`instances were`} checked past the 2000 a recording counts, so ${t===1?`its tree row shows`:`their tree rows show`} no check count.`),n});status=Q(()=>{if(this.message())return this.message();let e=this.cycles().length;return this.imported()?`${e} ${e===1?`cycle`:`cycles`} imported.`:this.recording()?`Recording. ${e} ${e===1?`cycle`:`cycles`} so far.`:e?`${e} ${e===1?`cycle`:`cycles`} recorded.`:``});ms(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}clock(e){return IO(e)}async toggle(){this.recording()?await this.send({on:!1},``,()=>{let e=this.cycles().length;return`Recording stopped. ${e} ${e===1?`cycle`:`cycles`} recorded.`}):await this.send({on:!0},`Starting…`,()=>`Recording started.`)}showImport(e){this.message.set(``),this.range.set(null),this.imported.set(e);let t=e.page.cycles.length;this.announce(`Imported ${e.fileName}: ${t} ${t===1?`cycle`:`cycles`}. Showing the imported recording.`)}closeImport(){this.imported.set(null),this.range.set(null),this.announce(`Showing the live recording.`)}async clear(){this.range.set(null),await this.send({clear:!0},``,()=>`Cleared the recorded cycles.`)}async setView(e,t){let n=this.views();this.views.set({...n,[e]:t});let r={flash:t?`Flash checks on.`:`Flash checks off.`,track:t?`Performance track on. Record in the Chrome Performance panel to see it.`:`Performance track off.`,angularProfiling:`Angular profiling on. It stays on until the page reloads.`}[e];await this.send({[e]:t},``,()=>r,`request-change-detection-options`)||this.views.set(n)}async send(e,t,n,r=`request-change-detection-record`){this.message.set(t);try{if(!this.rpc())throw Error(`no client`);return await NE(this.rpc(),r,{pageId:this.pageId(),...e}),this.message.set(``),this.announce(n()),!0}catch{let e=`Could not reach the page.`;return this.message.set(e),this.announce(e),!1}}announce(e){this.announcement.update(t=>t===e?`${e} `:e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-recording`]],inputs:{livePage:[1,`page`,`livePage`],pageId:[1,`pageId`],rpc:[1,`rpc`]},outputs:{showComponent:`showComponent`},decls:21,vars:12,consts:[[`aria-labelledby`,`cd-heading`,1,`cd`],[1,`cd-head`],[`id`,`cd-heading`],[3,`imported`,`page`,`maxCycles`],[1,`status`],[`role`,`status`,1,`sr-only`],[1,`imported`],[1,`hint`],[1,`note`],[`what`,`cycles`,`limit`,`cdCycles`,3,`dropped`,`max`],[1,`empty`],[`type`,`button`,3,`click`,`disabled`],[`aria-hidden`,`true`,1,`dot`],[`type`,`button`],[`type`,`button`,3,`click`],[1,`badge`],[1,`mono`],[`role`,`group`,`aria-labelledby`,`cd-views-label`,1,`views`],[`id`,`cd-views-label`,1,`views-label`],[`type`,`button`,1,`view`,3,`click`,`disabled`],[3,`rangeChange`,`cycles`,`range`],[3,`pick`,`cycles`,`names`,`scope`],[1,`spans-note`],[3,`pick`,`stats`,`scope`],[1,`cd-grid`],[`scope`,`col`],[`scope`,`col`,1,`num`],[`aria-label`,`Latest change detection cycles, newest first`,1,`cycles`],[3,`page`],[1,`num`],[`colspan`,`4`],[1,`when`],[1,`trigger`],[1,`timing`],[1,`top`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`h2`,2),J(3,`Change detection`),R(),M(4,LA,4,5),L(5,`app-cd-transfer`,3),U(`imported`,function(e){return t.showImport(e)}),R(),L(6,`p`,4),J(7),R(),L(8,`p`,5),J(9),R()(),M(10,RA,7,1,`p`,6),L(11,`p`,7),J(12,` Records each change detection cycle with Angular's profiler: how long it took, how many components it checked and the output that ran before it. Tree rows show how often each instance was checked. Times come from a development build. `),R(),M(13,zA,2,0,`p`,8),M(14,HA,16,7),z(15,`app-limit-note`,9),P(16,UA,2,1,`p`,8,Ag),M(18,KA,9,9),M(19,ej,26,3)(20,tj,2,0,`p`,10),R()),e&2){let e;A(4),N(t.imported()?-1:4),A(),I(`page`,t.page())(`maxCycles`,t.maxCycles()),A(2),Y(t.status()),A(2),Y(t.announcement()),A(),N((e=t.imported())?10:-1,e),A(3),N(t.page()?.supported===!1?13:-1),A(),N(t.imported()?-1:14),A(),I(`dropped`,t.page()?.dropped??0)(`max`,t.maxCycles()),A(),F(t.capNotes()),A(2),N(t.cycles().length?18:-1),A(),N(t.page()?.components?.length?19:t.recording()?20:-1)}},dependencies:[VO,zk,CA,pk,Ok,PA],styles:[`[_nghost-%COMP%] { display: block; margin-top: 16px; } @@ -1685,7 +1685,7 @@ td.mono[_ngcontent-%COMP%] { .trigger[_ngcontent-%COMP%] .mono[_ngcontent-%COMP%], .top[_ngcontent-%COMP%] .mono[_ngcontent-%COMP%] { overflow-wrap: anywhere; -}`]})},HA=[`*`];function UA(e,t){e&1&&J(0),e&2&&Y(G(2).label())}function WA(e,t){e&1&&s_(0,0,null,UA,1,1)}function GA(e,t){if(e&1&&(L(0,`span`,4),J(1),R()),e&2){let e=G(2);A(),Y(e.message())}}function KA(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){return E(e),D(G().open())}),Gg(1,3),R(),M(2,GA,2,1,`span`,4)}if(e&2){let e=G(),t=d_(1);I(`title`,`Open `+e.label()+` in your editor`),j(`aria-label`,`Open `+e.label()+` in your editor`),A(),I(`ngTemplateOutlet`,t),A(),N(e.message()?2:-1)}}function qA(e,t){if(e&1&&(L(0,`span`,1),Gg(1,3),R()),e&2){let e=G(),t=d_(1);I(`title`,e.label()),A(),I(`ngTemplateOutlet`,t)}}var JA=class e{source=k(k(null));client=Q(()=>this.source()());available=Q(()=>{let e=this.client();return!!e&&!xE(e)});use(e){this.source.set(e)}async open(e,t){if(!this.available())return{ok:!1,error:`No server is connected.`};try{let n=await yE(this.client(),`open-in-editor`,{file:e,...t?{line:t}:{}});return n?.ok?{ok:!0}:{ok:!1,error:n?.error??`The server did not open it.`}}catch{return{ok:!1,error:`The server did not open it.`}}}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})};function YA(e,t){return t?`${e}:${t}`:e}var XA=class e{editor=w(JA);file=$.required();line=$(void 0);label=Q(()=>YA(this.file(),this.line()));message=k(``);async open(){this.message.set(``);let e=await this.editor.open(this.file(),this.line()??void 0);e.ok||this.message.set(`Not opened: ${e.error}`)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-source-link`]],inputs:{file:[1,`file`],line:[1,`line`]},ngContentSelectors:HA,decls:4,vars:1,consts:[[`text`,``],[1,`source-text`,3,`title`],[`type`,`button`,1,`source-link`,3,`click`,`title`],[3,`ngTemplateOutlet`],[`role`,`alert`,1,`message`]],template:function(e,t){e&1&&(o_(),sg(0,WA,2,0,`ng-template`,null,0,Ev),M(2,KA,3,4)(3,qA,2,2,`span`,1)),e&2&&(A(2),N(t.editor.available()?2:3))},dependencies:[lb],styles:[`[_nghost-%COMP%] { +}`]})},ij=[`*`];function aj(e,t){e&1&&J(0),e&2&&Y(G(2).label())}function oj(e,t){e&1&&s_(0,0,null,aj,1,1)}function sj(e,t){if(e&1&&(L(0,`span`,4),J(1),R()),e&2){let e=G(2);A(),Y(e.message())}}function cj(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){return E(e),D(G().open())}),Gg(1,3),R(),M(2,sj,2,1,`span`,4)}if(e&2){let e=G(),t=d_(1);I(`title`,`Open `+e.label()+` in your editor`),j(`aria-label`,`Open `+e.label()+` in your editor`),A(),I(`ngTemplateOutlet`,t),A(),N(e.message()?2:-1)}}function lj(e,t){if(e&1&&(L(0,`span`,1),Gg(1,3),R()),e&2){let e=G(),t=d_(1);I(`title`,e.label()),A(),I(`ngTemplateOutlet`,t)}}var uj=class e{source=k(k(null));client=Q(()=>this.source()());available=Q(()=>{let e=this.client();return!!e&&!FE(e)});use(e){this.source.set(e)}async open(e,t){if(!this.available())return{ok:!1,error:`No server is connected.`};try{let n=await NE(this.client(),`open-in-editor`,{file:e,...t?{line:t}:{}});return n?.ok?{ok:!0}:{ok:!1,error:n?.error??`The server did not open it.`}}catch{return{ok:!1,error:`The server did not open it.`}}}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})};function dj(e,t){return t?`${e}:${t}`:e}var fj=class e{editor=w(uj);file=$.required();line=$(void 0);label=Q(()=>dj(this.file(),this.line()));message=k(``);async open(){this.message.set(``);let e=await this.editor.open(this.file(),this.line()??void 0);e.ok||this.message.set(`Not opened: ${e.error}`)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-source-link`]],inputs:{file:[1,`file`],line:[1,`line`]},ngContentSelectors:ij,decls:4,vars:1,consts:[[`text`,``],[1,`source-text`,3,`title`],[`type`,`button`,1,`source-link`,3,`click`,`title`],[3,`ngTemplateOutlet`],[`role`,`alert`,1,`message`]],template:function(e,t){e&1&&(o_(),sg(0,oj,2,0,`ng-template`,null,0,Ev),M(2,cj,3,4)(3,lj,2,2,`span`,1)),e&2&&(A(2),N(t.editor.available()?2:3))},dependencies:[lb],styles:[`[_nghost-%COMP%] { display: inline; min-width: 0; } @@ -1720,7 +1720,7 @@ td.mono[_ngcontent-%COMP%] { color: var(--%NS%danger-text); font-family: var(--%NS%font-sans); font-size: 0.92em; -}`]})},ZA=[`field`],QA=[`editButton`],$A=[`valueBox`];function ej(e,t){if(e&1){let e=H();B(0,`div`,5)(1,`label`,6),J(2),V(),B(3,`input`,7,0),W(`input`,function(t){return E(e),D(G().draft.set(t.target.value))})(`keydown.enter`,function(t){E(e);let n=G();return t.preventDefault(),D(n.apply())})(`keydown.escape`,function(t){E(e);let n=G();return t.preventDefault(),t.stopPropagation(),D(n.cancel())}),V(),B(5,`button`,8),W(`click`,function(){return E(e),D(G().apply())}),J(6,`Apply`),V(),B(7,`button`,9),W(`click`,function(){return E(e),D(G().cancel())}),J(8,`Cancel`),V()(),B(9,`p`,10),J(10),V()}if(e&2){let e=G();A(),qg(`htmlFor`,e.fieldId),A(),X(`New value of `,e.prop().name,`, as JSON`),A(),qg(`id`,e.fieldId)(`value`,e.draft())(`readOnly`,e.busy()),j(`aria-busy`,e.busy()?`true`:null)(`aria-invalid`,e.error()?`true`:null)(`aria-describedby`,e.hintId+(e.error()?` `+e.errorId:``)),A(2),qg(`disabled`,e.busy()),A(4),qg(`id`,e.hintId),A(),X(` JSON, such as "text", 42, true or `,e.objectSample,`. Enter applies, Escape cancels. `)}}function tj(e,t){if(e&1&&(B(0,`pre`,null,1),J(2),xv(3,`json`),V()),e&2){let e=G(2);j(`tabindex`,e.scrollable()?0:null)(`role`,e.scrollable()?`region`:null)(`aria-label`,e.scrollable()?`Value of `+e.prop().name:null),A(2),Y(Cv(3,4,e.prop().value))}}function nj(e,t){if(e&1){let e=H();B(0,`button`,14,2),W(`click`,function(){return E(e),D(G(2).start())}),J(2,` Edit `),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()),j(`aria-label`,`Edit `+e.prop().name)}}function rj(e,t){if(e&1&&(B(0,`p`,13),J(1),V()),e&2){let e=G(2);A(),Y(e.prop().locked)}}function ij(e,t){if(e&1&&(B(0,`div`,11),M(1,tj,4,6,`pre`),M(2,nj,3,2,`button`,12),V(),M(3,rj,2,1,`p`,13)),e&2){let e=G();A(),N(e.bare()?-1:1),A(),N(e.editable()?2:-1),A(),N(e.writes()&&e.prop().locked?3:-1)}}function aj(e,t){if(e&1&&(B(0,`p`,3),J(1),V()),e&2){let e=G();qg(`id`,e.errorId),A(),Y(e.error())}}var oj=0;function sj(e){let t=e.trim();if(!t)return{error:`Type a JSON value, such as "text", 42, true, null or [1, 2].`};try{return{value:JSON.parse(t)}}catch{return{error:`Not valid JSON. Put text in double quotes, such as "Paris".`}}}var cj=class e{prop=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);bare=$(!1);readDraft=$(null);fieldId=`prop-edit-${++oj}`;hintId=`${this.fieldId}-hint`;errorId=`${this.fieldId}-error`;objectSample=`{"a": 1}`;editing=k(!1);draft=k(``);busy=k(!1);error=k(``);done=k(``);editable=Q(()=>this.writes()&&!!this.prop().edit&&!!this.pageId()&&!!this.rpc());field=Jv(`field`);editButton=Jv(`editButton`);valueBox=Jv(`valueBox`);injector=w(ws);scrollable=k(!1);constructor(){uy(()=>{this.prop();let e=this.valueBox()?.nativeElement;this.scrollable.set(!!e&&e.scrollHeight>e.clientHeight+1)})}async start(){let e=this.prop().value;this.error.set(``),this.done.set(``);let t=this.readDraft();if(t){this.busy.set(!0);let n=await t();if(this.busy.set(!1),n.error!==void 0){this.error.set(n.error);return}e=n.value}this.draft.set(e===void 0?``:JSON.stringify(e)),this.editing.set(!0),Vd(()=>{let e=this.field()?.nativeElement;e?.focus(),e?.select()},{injector:this.injector})}cancel(){this.editing()&&(this.editing.set(!1),this.busy.set(!1),this.error.set(``),this.focusEdit())}async apply(){if(this.busy())return;let e=sj(this.draft());if(`error`in e){this.error.set(e.error);return}let t=this.prop(),n=this.rpc(),r=this.pageId();if(!n||!r||!t.edit)return;this.busy.set(!0),this.error.set(``);let i;try{i=await n.scope(`pangular`).rpc.call(`request-component-edit`,{pageId:r,request:{id:this.componentId(),path:t.prop,value:e.value,kind:t.edit}})??{}}catch{i={error:`The devtools server did not answer. Try again.`}}this.busy.set(!1),this.editing()&&(i.ok?(this.editing.set(!1),this.done.set(`Set ${t.name}.`),this.focusEdit()):(this.error.set(i.error??`The page did not write it.`),this.field()?.nativeElement.focus()))}focusEdit(){Vd(()=>this.editButton()?.nativeElement.focus(),{injector:this.injector})}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-prop-value`]],viewQuery:function(e,t){e&1&&l_(t.field,ZA,5)(t.editButton,QA,5)(t.valueBox,$A,5),e&2&&u_(3)},inputs:{prop:[1,`prop`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],bare:[1,`bare`],readDraft:[1,`readDraft`]},decls:5,vars:3,consts:[[`field`,``],[`valueBox`,``],[`editButton`,``],[`role`,`alert`,1,`error`,3,`id`],[`role`,`status`,1,`sr-only`],[1,`editor`],[1,`sr-only`,3,`for`],[`type`,`text`,`autocomplete`,`off`,`spellcheck`,`false`,1,`field`,`mono`,3,`input`,`keydown.enter`,`keydown.escape`,`id`,`value`,`readOnly`],[`type`,`button`,1,`primary`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[1,`hint`,3,`id`],[1,`view`],[`type`,`button`,1,`edit`,3,`disabled`],[1,`locked`],[`type`,`button`,1,`edit`,3,`click`,`disabled`]],template:function(e,t){e&1&&(M(0,ej,11,11)(1,ij,4,3),M(2,aj,2,2,`p`,3),B(3,`p`,4),J(4),V()),e&2&&(N(+!t.editing()),A(2),N(t.error()?2:-1),A(2),Y(t.done()))},dependencies:[hb],styles:[`[_nghost-%COMP%] { +}`]})},pj=[`field`],mj=[`editButton`],hj=[`valueBox`];function gj(e,t){if(e&1){let e=H();B(0,`div`,5)(1,`label`,6),J(2),V(),B(3,`input`,7,0),W(`input`,function(t){return E(e),D(G().draft.set(t.target.value))})(`keydown.enter`,function(t){E(e);let n=G();return t.preventDefault(),D(n.apply())})(`keydown.escape`,function(t){E(e);let n=G();return t.preventDefault(),t.stopPropagation(),D(n.cancel())}),V(),B(5,`button`,8),W(`click`,function(){return E(e),D(G().apply())}),J(6,`Apply`),V(),B(7,`button`,9),W(`click`,function(){return E(e),D(G().cancel())}),J(8,`Cancel`),V()(),B(9,`p`,10),J(10),V()}if(e&2){let e=G();A(),qg(`htmlFor`,e.fieldId),A(),X(`New value of `,e.prop().name,`, as JSON`),A(),qg(`id`,e.fieldId)(`value`,e.draft())(`readOnly`,e.busy()),j(`aria-busy`,e.busy()?`true`:null)(`aria-invalid`,e.error()?`true`:null)(`aria-describedby`,e.hintId+(e.error()?` `+e.errorId:``)),A(2),qg(`disabled`,e.busy()),A(4),qg(`id`,e.hintId),A(),X(` JSON, such as "text", 42, true or `,e.objectSample,`. Enter applies, Escape cancels. `)}}function _j(e,t){if(e&1&&(B(0,`pre`,null,1),J(2),xv(3,`json`),V()),e&2){let e=G(2);j(`tabindex`,e.scrollable()?0:null)(`role`,e.scrollable()?`region`:null)(`aria-label`,e.scrollable()?`Value of `+e.prop().name:null),A(2),Y(Cv(3,4,e.prop().value))}}function vj(e,t){if(e&1){let e=H();B(0,`button`,14,2),W(`click`,function(){return E(e),D(G(2).start())}),J(2,` Edit `),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()),j(`aria-label`,`Edit `+e.prop().name)}}function yj(e,t){if(e&1&&(B(0,`p`,13),J(1),V()),e&2){let e=G(2);A(),Y(e.prop().locked)}}function bj(e,t){if(e&1&&(B(0,`div`,11),M(1,_j,4,6,`pre`),M(2,vj,3,2,`button`,12),V(),M(3,yj,2,1,`p`,13)),e&2){let e=G();A(),N(e.bare()?-1:1),A(),N(e.editable()?2:-1),A(),N(e.writes()&&e.prop().locked?3:-1)}}function xj(e,t){if(e&1&&(B(0,`p`,3),J(1),V()),e&2){let e=G();qg(`id`,e.errorId),A(),Y(e.error())}}var Sj=0;function Cj(e){let t=e.trim();if(!t)return{error:`Type a JSON value, such as "text", 42, true, null or [1, 2].`};try{return{value:JSON.parse(t)}}catch{return{error:`Not valid JSON. Put text in double quotes, such as "Paris".`}}}var wj=class e{prop=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);bare=$(!1);readDraft=$(null);fieldId=`prop-edit-${++Sj}`;hintId=`${this.fieldId}-hint`;errorId=`${this.fieldId}-error`;objectSample=`{"a": 1}`;editing=k(!1);draft=k(``);busy=k(!1);error=k(``);done=k(``);editable=Q(()=>this.writes()&&!!this.prop().edit&&!!this.pageId()&&!!this.rpc());field=Jv(`field`);editButton=Jv(`editButton`);valueBox=Jv(`valueBox`);injector=w(ws);scrollable=k(!1);constructor(){uy(()=>{this.prop();let e=this.valueBox()?.nativeElement;this.scrollable.set(!!e&&e.scrollHeight>e.clientHeight+1)})}async start(){let e=this.prop().value;this.error.set(``),this.done.set(``);let t=this.readDraft();if(t){this.busy.set(!0);let n=await t();if(this.busy.set(!1),n.error!==void 0){this.error.set(n.error);return}e=n.value}this.draft.set(e===void 0?``:JSON.stringify(e)),this.editing.set(!0),Vd(()=>{let e=this.field()?.nativeElement;e?.focus(),e?.select()},{injector:this.injector})}cancel(){this.editing()&&(this.editing.set(!1),this.busy.set(!1),this.error.set(``),this.focusEdit())}async apply(){if(this.busy())return;let e=Cj(this.draft());if(`error`in e){this.error.set(e.error);return}let t=this.prop(),n=this.rpc(),r=this.pageId();if(!n||!r||!t.edit)return;this.busy.set(!0),this.error.set(``);let i;try{i=await n.scope(`pangular`).rpc.call(`request-component-edit`,{pageId:r,request:{id:this.componentId(),path:t.prop,value:e.value,kind:t.edit}})??{}}catch{i={error:`The devtools server did not answer. Try again.`}}this.busy.set(!1),this.editing()&&(i.ok?(this.editing.set(!1),this.done.set(`Set ${t.name}.`),this.focusEdit()):(this.error.set(i.error??`The page did not write it.`),this.field()?.nativeElement.focus()))}focusEdit(){Vd(()=>this.editButton()?.nativeElement.focus(),{injector:this.injector})}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-prop-value`]],viewQuery:function(e,t){e&1&&l_(t.field,pj,5)(t.editButton,mj,5)(t.valueBox,hj,5),e&2&&u_(3)},inputs:{prop:[1,`prop`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],bare:[1,`bare`],readDraft:[1,`readDraft`]},decls:5,vars:3,consts:[[`field`,``],[`valueBox`,``],[`editButton`,``],[`role`,`alert`,1,`error`,3,`id`],[`role`,`status`,1,`sr-only`],[1,`editor`],[1,`sr-only`,3,`for`],[`type`,`text`,`autocomplete`,`off`,`spellcheck`,`false`,1,`field`,`mono`,3,`input`,`keydown.enter`,`keydown.escape`,`id`,`value`,`readOnly`],[`type`,`button`,1,`primary`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[1,`hint`,3,`id`],[1,`view`],[`type`,`button`,1,`edit`,3,`disabled`],[1,`locked`],[`type`,`button`,1,`edit`,3,`click`,`disabled`]],template:function(e,t){e&1&&(M(0,gj,11,11)(1,bj,4,3),M(2,xj,2,2,`p`,3),B(3,`p`,4),J(4),V()),e&2&&(N(+!t.editing()),A(2),N(t.error()?2:-1),A(2),Y(t.done()))},dependencies:[hb],styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1843,7 +1843,7 @@ button.edit[_ngcontent-%COMP%] { .error[_ngcontent-%COMP%] { color: var(--%NS%danger-text); -}`]})},lj=1e3,uj={depth:5,limit:100},dj=`[redacted]`;function fj(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function pj(e){return fj(e)&&typeof e.$more==`number`&&Object.keys(e).length===1}function mj(e){return fj(e)&&typeof e.$collapsed==`string`&&typeof e.size==`number`&&Object.keys(e).length===2}function hj(e){return e===`Array`?`array`:e===`Map`?`map`:e===`Set`?`set`:`object`}function gj(e){return e.$type===`Map`&&Array.isArray(e.entries)}function _j(e){return e.$type===`Set`&&Array.isArray(e.values)}function vj(e){return Object.keys(e).filter(e=>e!==`$type`&&e!==`$more`)}function yj(e){if(!e||typeof e!=`object`)return null;if(mj(e))return e.size<=0?null:{kind:hj(e.$collapsed),type:e.$collapsed,size:e.size,collapsed:!0};if(pj(e))return null;if(Array.isArray(e)){let t=e.at(-1),n=pj(t)?t.$more:0,r=e.length-+!!n+n;return r?{kind:`array`,type:`Array`,size:r,collapsed:!1}:null}let t=e;if(gj(t)||_j(t)){let e=typeof t.size==`number`?t.size:0,n=gj(t)?`map`:`set`;return e?{kind:n,type:n===`map`?`Map`:`Set`,size:e,collapsed:!1}:null}let n=typeof t.$more==`number`?t.$more:0,r=vj(t).length+n,i=typeof t.$type==`string`?t.$type:`Object`;return r?{kind:`object`,type:i,size:r,collapsed:!1}:null}function bj(e){if(typeof e==`string`)return JSON.stringify(e);let t=yj(e);if(t)return Cj(t);try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function xj(e){let t=yj(e);if(!t||t.collapsed)return{children:[],more:0};if(Array.isArray(e)){let n=(pj(e.at(-1))?e.slice(0,-1):e).map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:n,more:t.size-n.length}}let n=e;if(t.kind===`map`){let e=n.entries.map((e,t)=>{let[n,r]=Array.isArray(e)?e:[void 0,e];return{key:String(t),label:bj(n),value:r}});return{children:e,more:Math.max(0,t.size-e.length)}}if(t.kind===`set`){let e=n.values.map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:e,more:Math.max(0,t.size-e.length)}}return{children:vj(n).map(e=>({key:e,label:e,value:n[e]})),more:typeof n.$more==`number`?n.$more:0}}function Sj(e,t,n){return`${e} ${e===1?t:n}`}function Cj(e){let t={array:Sj(e.size,`item`,`items`),object:Sj(e.size,`key`,`keys`),map:Sj(e.size,`entry`,`entries`),set:Sj(e.size,`value`,`values`)}[e.kind];return`${e.type} (${t})`}function wj(e,t){return JSON.stringify(t===void 0?e:[t,...e])}function Tj(e,t){return e.map((e,n)=>n===0?e:(t?t[n-1]!==`object`:/^\d+$/.test(e))?`[${e}]`:`.${e}`).join(``)}function Ej(e){return e.every(e=>e&&e===e.trim()&&!/[.[\]]/.test(e))?e.join(`.`):null}var Dj=/^\[(Getter|Unreadable|Circular|Truncated|Function\b.*|Promise)\]$/;function Oj(e){return e===null||typeof e==`boolean`?!0:typeof e==`number`?Number.isFinite(e):typeof e==`string`&&e!==dj&&!Dj.test(e)&&!e.endsWith(`…`)}function kj(e,t){return!e||t.kind===`map`||t.kind===`set`||e===`signal`&&t.kind===`object`&&t.type!==`Object`?null:e}function Aj(e,t,n,r,i=500){let a=[],o=r.trim().toLowerCase();if(!o)return a;let s=new Set,c=(e,t)=>{let r=wj(e);if(!(s.has(r)||a.length>=i)){s.add(r);for(let r of xj(t).children){let t=[...e,r.key];if(r.label.toLowerCase().includes(o)&&a.push(t),!yj(r.value))continue;let i=n(t)??(yj(r.value)?.collapsed?void 0:r.value);i!==void 0&&c(t,i)}}};return c(e,n(e)??t),a}var jj=(e,t)=>t.id;function Mj(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){E(e);let t=G().$implicit;return D(G(3).toggle(t))}),O(),L(1,`svg`,3),z(2,`path`,4),R(),gs(),L(3,`span`,14),J(4),R(),L(5,`span`,5),J(6),R()()}if(e&2){let e=G().$implicit;j(`aria-expanded`,e.open)(`aria-label`,e.label+`: `+e.text),A(4),X(``,e.label,`:`),A(2),Y(e.text)}}function Nj(e,t){if(e&1&&z(0,`app-prop-value`,15),e&2){let e=G(5);I(`prop`,t)(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}function Pj(e,t){if(e&1&&(L(0,`span`,16),J(1),R()),e&2){let e=G(2).$implicit;A(),Y(e.text)}}function Fj(e,t){if(e&1&&(L(0,`span`,14),J(1),R(),M(2,Nj,1,5,`app-prop-value`,15)(3,Pj,2,1,`span`,16)),e&2){let e,t=G().$implicit;A(),X(``,t.label,`:`),A(),N((e=t.edit)?2:3,e)}}function Ij(e,t){if(e&1){let e=H();L(0,`button`,17),U(`click`,function(){E(e);let t=G().$implicit;return D(G(3).more(t))}),J(1),L(2,`span`,18),J(3),R()()}if(e&2){let e=G().$implicit,t=G(3);A(),X(` Show `,t.step(e),` more `),A(2),X(`(`,e.more,` not listed)`)}}function Lj(e,t){e&1&&(L(0,`span`,12),J(1,`Reading from the page…`),R())}function Rj(e,t){if(e&1&&(L(0,`span`,13),J(1),R()),e&2){let e=G().$implicit;A(),Y(e.text)}}function zj(e,t){if(e&1&&(L(0,`li`,9),M(1,Mj,7,4,`button`,10)(2,Fj,4,2)(3,Ij,4,2,`button`,11)(4,Lj,2,0,`span`,12)(5,Rj,2,1,`span`,13),R()),e&2){let e,n=t.$implicit;K(`padding-left`,n.depth*14,`px`),A(),N((e=n.kind)===`node`?1:e===`leaf`?2:e===`more`?3:e===`loading`?4:e===`error`?5:-1)}}function Bj(e,t){if(e&1&&(L(0,`ul`,7),P(1,zj,6,3,`li`,8,jj),R()),e&2){let e=G(2);I(`id`,e.listId),j(`aria-label`,e.prop().name+` entries`),A(),F(e.rows())}}function Vj(e,t){if(e&1){let e=H();L(0,`div`,1)(1,`button`,2),U(`click`,function(){return E(e),D(G().toggleRoot())}),O(),L(2,`svg`,3),z(3,`path`,4),R(),gs(),L(4,`span`,5),J(5),R()(),z(6,`app-prop-value`,6),R(),M(7,Bj,3,2,`ul`,7)}if(e&2){let e=t,n=G();A(),j(`aria-expanded`,n.rootOpen())(`aria-controls`,n.rootOpen()?n.listId:null)(`aria-label`,n.prop().name+`: `+n.summaryOf(e)),A(4),Y(n.summaryOf(e)),A(),I(`bare`,!0)(`prop`,n.prop())(`componentId`,n.componentId())(`pageId`,n.pageId())(`rpc`,n.rpc())(`writes`,n.writes())(`readDraft`,n.readWhole),A(),N(n.rootOpen()?7:-1)}}function Hj(e,t){if(e&1&&z(0,`app-prop-value`,0),e&2){let e=G();I(`prop`,e.prop())(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}var Uj=0;function Wj(e){if(e===void 0)return`undefined`;try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function Gj(e){if(Array.isArray(e))return e.every(Gj);if(e&&typeof e==`object`){let t=e;return![`$collapsed`,`$more`,`$type`].some(e=>Object.hasOwn(t,e))&&Object.values(t).every(Gj)}return Oj(e)}var Kj=class e{prop=$.required();store=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);directive=$(void 0);query=$(``);listId=`value-tree-${++Uj}`;host=w(Fl);pendingMore=null;constructor(){uy(()=>{let e=this.rows(),t=this.pendingMore;if(!t)return;let n=e.findIndex(e=>(e.kind===`leaf`||e.kind===`node`)&&!t.has(e.id));if(n<0)return;this.pendingMore=null;let r=document.activeElement;r&&r!==document.body&&r.isConnected||this.focusNear(n)})}rootPath=Q(()=>[this.prop().prop]);rootValue=Q(()=>this.store().level(this.rootPath(),this.directive())??this.prop().value);root=Q(()=>yj(this.rootValue()));needle=Q(()=>this.query().trim().toLowerCase());matches=Q(()=>{let e=this.needle(),t=this.prop();if(!e||[t.name,t.prop].some(t=>t.toLowerCase().includes(e)))return null;let n=this.store(),r=this.directive();return Aj(this.rootPath(),this.rootValue(),e=>n.level(e,r),e)});rootOpen=Q(()=>!!this.matches()?.length||this.store().isOpen(this.rootPath(),this.directive()));rows=Q(()=>{let e=this.root();if(!e)return[];let t=this.store(),n=this.directive(),r=this.matches(),i=new Set,a=new Set;for(let e of r??[]){a.add(wj(e));for(let t=2;t<=e.length;t++)i.add(wj(e.slice(0,t)))}let o=this.prop(),s=this.writes()&&n===void 0,c=[],l=(e,o,d,f,p,m)=>{let{children:h,more:g}=xj(e);for(let e of h){let h=[...o,e.key],g=wj(h);if(r&&!m&&!i.has(g))continue;let _=yj(e.value),ee=wj(h,n);if(!_){let t=p&&Oj(e.value)?Ej(h):null;c.push({id:ee,kind:`leaf`,depth:f,path:h,label:e.label,text:Wj(e.value),edit:s&&t&&p?{name:Tj(h,[...d]),prop:t,value:e.value,edit:p}:void 0});continue}let te=!!r&&!m&&i.has(g)&&!a.has(g)||t.isOpen(h,n);if(c.push({id:ee,kind:`node`,depth:f,path:h,label:e.label,text:Cj(_),container:_,open:te}),!te)continue;let ne=t.level(h,n)??(_.collapsed?void 0:e.value),re=[...d,_.kind];ne===void 0?t.errors().has(ee)?c.push({...u(h,f+1,`error`),text:t.errors().get(ee)}):c.push(u(h,f+1,`loading`)):l(ne,h,re,f+1,kj(p,_),m||a.has(g))}g>0&&(!r||m)&&c.push({...u(o,f,`more`),more:g,listed:h.length})},u=(e,t,r)=>({id:`${wj(e,n)}:${r}`,kind:r,depth:t,path:e,label:``,text:``});return l(this.rootValue(),this.rootPath(),[e.kind],0,s?kj(o.editInside??null,e):null,!r),c});readWhole=async()=>{let e=await this.store().read(this.rootPath(),uj.depth,uj.limit);return e.ok?Gj(e.value)?{value:e.value}:{error:`Too large to edit as a whole. Open it to edit the values inside.`}:{error:e.error??`The page did not read it.`}};summaryOf(e){return Cj(e)}toggleRoot(){this.pendingMore=null,this.store().toggle(this.rootPath(),this.directive(),!1)}toggle(e){this.pendingMore=null,this.store().toggle(e.path,this.directive(),!!e.container?.collapsed)}more(e){this.pendingMore=new Set(this.rows().map(e=>e.id)),this.store().more(e.path,this.directive(),e.listed??0)}focusNear(e){let t=this.host.nativeElement,n=Array.from(t.querySelectorAll(`#${this.listId} > li`)),r=e=>e?.querySelector(`button:not([disabled]), input, textarea, [tabindex="0"]`);(n.slice(e).map(r).find(Boolean)??n.slice(0,e).reverse().map(r).find(Boolean)??t.querySelector(`.root > .toggle`))?.focus()}step(e){return Math.min(100,e.more??0)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-value-tree`]],inputs:{prop:[1,`prop`],store:[1,`store`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],directive:[1,`directive`],query:[1,`query`]},decls:2,vars:1,consts:[[3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`root`],[`type`,`button`,1,`toggle`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m9 6 6 6-6 6`],[1,`summary`,`mono`],[1,`whole`,3,`bare`,`prop`,`componentId`,`pageId`,`rpc`,`writes`,`readDraft`],[1,`entries`,3,`id`],[1,`entry`,3,`padding-left`],[1,`entry`],[`type`,`button`,1,`toggle`],[`type`,`button`,1,`more`],[`role`,`status`,1,`muted`],[`role`,`alert`,1,`error`],[1,`key`,`mono`],[1,`leaf-edit`,3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`leaf`,`mono`],[`type`,`button`,1,`more`,3,`click`],[1,`muted`]],template:function(e,t){if(e&1&&M(0,Vj,8,12)(1,Hj,1,5,`app-prop-value`,0),e&2){let e;N((e=t.root())?0:1,e)}},dependencies:[cj],styles:[`[_nghost-%COMP%] { +}`]})},Tj=1e3,Ej={depth:5,limit:100},Dj=`[redacted]`;function Oj(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function kj(e){return Oj(e)&&typeof e.$more==`number`&&Object.keys(e).length===1}function Aj(e){return Oj(e)&&typeof e.$collapsed==`string`&&typeof e.size==`number`&&Object.keys(e).length===2}function jj(e){return e===`Array`?`array`:e===`Map`?`map`:e===`Set`?`set`:`object`}function Mj(e){return e.$type===`Map`&&Array.isArray(e.entries)}function Nj(e){return e.$type===`Set`&&Array.isArray(e.values)}function Pj(e){return Object.keys(e).filter(e=>e!==`$type`&&e!==`$more`)}function Fj(e){if(!e||typeof e!=`object`)return null;if(Aj(e))return e.size<=0?null:{kind:jj(e.$collapsed),type:e.$collapsed,size:e.size,collapsed:!0};if(kj(e))return null;if(Array.isArray(e)){let t=e.at(-1),n=kj(t)?t.$more:0,r=e.length-+!!n+n;return r?{kind:`array`,type:`Array`,size:r,collapsed:!1}:null}let t=e;if(Mj(t)||Nj(t)){let e=typeof t.size==`number`?t.size:0,n=Mj(t)?`map`:`set`;return e?{kind:n,type:n===`map`?`Map`:`Set`,size:e,collapsed:!1}:null}let n=typeof t.$more==`number`?t.$more:0,r=Pj(t).length+n,i=typeof t.$type==`string`?t.$type:`Object`;return r?{kind:`object`,type:i,size:r,collapsed:!1}:null}function Ij(e){if(typeof e==`string`)return JSON.stringify(e);let t=Fj(e);if(t)return zj(t);try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function Lj(e){let t=Fj(e);if(!t||t.collapsed)return{children:[],more:0};if(Array.isArray(e)){let n=(kj(e.at(-1))?e.slice(0,-1):e).map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:n,more:t.size-n.length}}let n=e;if(t.kind===`map`){let e=n.entries.map((e,t)=>{let[n,r]=Array.isArray(e)?e:[void 0,e];return{key:String(t),label:Ij(n),value:r}});return{children:e,more:Math.max(0,t.size-e.length)}}if(t.kind===`set`){let e=n.values.map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:e,more:Math.max(0,t.size-e.length)}}return{children:Pj(n).map(e=>({key:e,label:e,value:n[e]})),more:typeof n.$more==`number`?n.$more:0}}function Rj(e,t,n){return`${e} ${e===1?t:n}`}function zj(e){let t={array:Rj(e.size,`item`,`items`),object:Rj(e.size,`key`,`keys`),map:Rj(e.size,`entry`,`entries`),set:Rj(e.size,`value`,`values`)}[e.kind];return`${e.type} (${t})`}function Bj(e,t){return JSON.stringify(t===void 0?e:[t,...e])}function Vj(e,t){return e.map((e,n)=>n===0?e:(t?t[n-1]!==`object`:/^\d+$/.test(e))?`[${e}]`:`.${e}`).join(``)}function Hj(e){return e.every(e=>e&&e===e.trim()&&!/[.[\]]/.test(e))?e.join(`.`):null}var Uj=/^\[(Getter|Unreadable|Circular|Truncated|Function\b.*|Promise)\]$/;function Wj(e){return e===null||typeof e==`boolean`?!0:typeof e==`number`?Number.isFinite(e):typeof e==`string`&&e!==Dj&&!Uj.test(e)&&!e.endsWith(`…`)}function Gj(e,t){return!e||t.kind===`map`||t.kind===`set`||e===`signal`&&t.kind===`object`&&t.type!==`Object`?null:e}function Kj(e,t,n,r,i=500){let a=[],o=r.trim().toLowerCase();if(!o)return a;let s=new Set,c=(e,t)=>{let r=Bj(e);if(!(s.has(r)||a.length>=i)){s.add(r);for(let r of Lj(t).children){let t=[...e,r.key];if(r.label.toLowerCase().includes(o)&&a.push(t),!Fj(r.value))continue;let i=n(t)??(Fj(r.value)?.collapsed?void 0:r.value);i!==void 0&&c(t,i)}}};return c(e,n(e)??t),a}var qj=(e,t)=>t.id;function Jj(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){E(e);let t=G().$implicit;return D(G(3).toggle(t))}),O(),L(1,`svg`,3),z(2,`path`,4),R(),gs(),L(3,`span`,14),J(4),R(),L(5,`span`,5),J(6),R()()}if(e&2){let e=G().$implicit;j(`aria-expanded`,e.open)(`aria-label`,e.label+`: `+e.text),A(4),X(``,e.label,`:`),A(2),Y(e.text)}}function Yj(e,t){if(e&1&&z(0,`app-prop-value`,15),e&2){let e=G(5);I(`prop`,t)(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}function Xj(e,t){if(e&1&&(L(0,`span`,16),J(1),R()),e&2){let e=G(2).$implicit;A(),Y(e.text)}}function Zj(e,t){if(e&1&&(L(0,`span`,14),J(1),R(),M(2,Yj,1,5,`app-prop-value`,15)(3,Xj,2,1,`span`,16)),e&2){let e,t=G().$implicit;A(),X(``,t.label,`:`),A(),N((e=t.edit)?2:3,e)}}function Qj(e,t){if(e&1){let e=H();L(0,`button`,17),U(`click`,function(){E(e);let t=G().$implicit;return D(G(3).more(t))}),J(1),L(2,`span`,18),J(3),R()()}if(e&2){let e=G().$implicit,t=G(3);A(),X(` Show `,t.step(e),` more `),A(2),X(`(`,e.more,` not listed)`)}}function $j(e,t){e&1&&(L(0,`span`,12),J(1,`Reading from the page…`),R())}function eM(e,t){if(e&1&&(L(0,`span`,13),J(1),R()),e&2){let e=G().$implicit;A(),Y(e.text)}}function tM(e,t){if(e&1&&(L(0,`li`,9),M(1,Jj,7,4,`button`,10)(2,Zj,4,2)(3,Qj,4,2,`button`,11)(4,$j,2,0,`span`,12)(5,eM,2,1,`span`,13),R()),e&2){let e,n=t.$implicit;K(`padding-left`,n.depth*14,`px`),A(),N((e=n.kind)===`node`?1:e===`leaf`?2:e===`more`?3:e===`loading`?4:e===`error`?5:-1)}}function nM(e,t){if(e&1&&(L(0,`ul`,7),P(1,tM,6,3,`li`,8,qj),R()),e&2){let e=G(2);I(`id`,e.listId),j(`aria-label`,e.prop().name+` entries`),A(),F(e.rows())}}function rM(e,t){if(e&1){let e=H();L(0,`div`,1)(1,`button`,2),U(`click`,function(){return E(e),D(G().toggleRoot())}),O(),L(2,`svg`,3),z(3,`path`,4),R(),gs(),L(4,`span`,5),J(5),R()(),z(6,`app-prop-value`,6),R(),M(7,nM,3,2,`ul`,7)}if(e&2){let e=t,n=G();A(),j(`aria-expanded`,n.rootOpen())(`aria-controls`,n.rootOpen()?n.listId:null)(`aria-label`,n.prop().name+`: `+n.summaryOf(e)),A(4),Y(n.summaryOf(e)),A(),I(`bare`,!0)(`prop`,n.prop())(`componentId`,n.componentId())(`pageId`,n.pageId())(`rpc`,n.rpc())(`writes`,n.writes())(`readDraft`,n.readWhole),A(),N(n.rootOpen()?7:-1)}}function iM(e,t){if(e&1&&z(0,`app-prop-value`,0),e&2){let e=G();I(`prop`,e.prop())(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}var aM=0;function oM(e){if(e===void 0)return`undefined`;try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function sM(e){if(Array.isArray(e))return e.every(sM);if(e&&typeof e==`object`){let t=e;return![`$collapsed`,`$more`,`$type`].some(e=>Object.hasOwn(t,e))&&Object.values(t).every(sM)}return Wj(e)}var cM=class e{prop=$.required();store=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);directive=$(void 0);query=$(``);listId=`value-tree-${++aM}`;host=w(Fl);pendingMore=null;constructor(){uy(()=>{let e=this.rows(),t=this.pendingMore;if(!t)return;let n=e.findIndex(e=>(e.kind===`leaf`||e.kind===`node`)&&!t.has(e.id));if(n<0)return;this.pendingMore=null;let r=document.activeElement;r&&r!==document.body&&r.isConnected||this.focusNear(n)})}rootPath=Q(()=>[this.prop().prop]);rootValue=Q(()=>this.store().level(this.rootPath(),this.directive())??this.prop().value);root=Q(()=>Fj(this.rootValue()));needle=Q(()=>this.query().trim().toLowerCase());matches=Q(()=>{let e=this.needle(),t=this.prop();if(!e||[t.name,t.prop].some(t=>t.toLowerCase().includes(e)))return null;let n=this.store(),r=this.directive();return Kj(this.rootPath(),this.rootValue(),e=>n.level(e,r),e)});rootOpen=Q(()=>!!this.matches()?.length||this.store().isOpen(this.rootPath(),this.directive()));rows=Q(()=>{let e=this.root();if(!e)return[];let t=this.store(),n=this.directive(),r=this.matches(),i=new Set,a=new Set;for(let e of r??[]){a.add(Bj(e));for(let t=2;t<=e.length;t++)i.add(Bj(e.slice(0,t)))}let o=this.prop(),s=this.writes()&&n===void 0,c=[],l=(e,o,d,f,p,m)=>{let{children:h,more:g}=Lj(e);for(let e of h){let h=[...o,e.key],g=Bj(h);if(r&&!m&&!i.has(g))continue;let _=Fj(e.value),ee=Bj(h,n);if(!_){let t=p&&Wj(e.value)?Hj(h):null;c.push({id:ee,kind:`leaf`,depth:f,path:h,label:e.label,text:oM(e.value),edit:s&&t&&p?{name:Vj(h,[...d]),prop:t,value:e.value,edit:p}:void 0});continue}let te=!!r&&!m&&i.has(g)&&!a.has(g)||t.isOpen(h,n);if(c.push({id:ee,kind:`node`,depth:f,path:h,label:e.label,text:zj(_),container:_,open:te}),!te)continue;let ne=t.level(h,n)??(_.collapsed?void 0:e.value),re=[...d,_.kind];ne===void 0?t.errors().has(ee)?c.push({...u(h,f+1,`error`),text:t.errors().get(ee)}):c.push(u(h,f+1,`loading`)):l(ne,h,re,f+1,Gj(p,_),m||a.has(g))}g>0&&(!r||m)&&c.push({...u(o,f,`more`),more:g,listed:h.length})},u=(e,t,r)=>({id:`${Bj(e,n)}:${r}`,kind:r,depth:t,path:e,label:``,text:``});return l(this.rootValue(),this.rootPath(),[e.kind],0,s?Gj(o.editInside??null,e):null,!r),c});readWhole=async()=>{let e=await this.store().read(this.rootPath(),Ej.depth,Ej.limit);return e.ok?sM(e.value)?{value:e.value}:{error:`Too large to edit as a whole. Open it to edit the values inside.`}:{error:e.error??`The page did not read it.`}};summaryOf(e){return zj(e)}toggleRoot(){this.pendingMore=null,this.store().toggle(this.rootPath(),this.directive(),!1)}toggle(e){this.pendingMore=null,this.store().toggle(e.path,this.directive(),!!e.container?.collapsed)}more(e){this.pendingMore=new Set(this.rows().map(e=>e.id)),this.store().more(e.path,this.directive(),e.listed??0)}focusNear(e){let t=this.host.nativeElement,n=Array.from(t.querySelectorAll(`#${this.listId} > li`)),r=e=>e?.querySelector(`button:not([disabled]), input, textarea, [tabindex="0"]`);(n.slice(e).map(r).find(Boolean)??n.slice(0,e).reverse().map(r).find(Boolean)??t.querySelector(`.root > .toggle`))?.focus()}step(e){return Math.min(100,e.more??0)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-value-tree`]],inputs:{prop:[1,`prop`],store:[1,`store`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],directive:[1,`directive`],query:[1,`query`]},decls:2,vars:1,consts:[[3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`root`],[`type`,`button`,1,`toggle`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m9 6 6 6-6 6`],[1,`summary`,`mono`],[1,`whole`,3,`bare`,`prop`,`componentId`,`pageId`,`rpc`,`writes`,`readDraft`],[1,`entries`,3,`id`],[1,`entry`,3,`padding-left`],[1,`entry`],[`type`,`button`,1,`toggle`],[`type`,`button`,1,`more`],[`role`,`status`,1,`muted`],[`role`,`alert`,1,`error`],[1,`key`,`mono`],[1,`leaf-edit`,3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`leaf`,`mono`],[`type`,`button`,1,`more`,3,`click`],[1,`muted`]],template:function(e,t){if(e&1&&M(0,rM,8,12)(1,iM,1,5,`app-prop-value`,0),e&2){let e;N((e=t.root())?0:1,e)}},dependencies:[wj],styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1965,7 +1965,7 @@ button.edit[_ngcontent-%COMP%] { .more[_ngcontent-%COMP%] { transition: none; } -}`]})};function qj(e,t){return e.length>t.length&&e.startsWith(`${t.slice(0,-1)},`)}var Jj=class{target={rpc:null,pageId:null,componentId:null};fetched=k(new Map);pushed=k({});open=k(new Set);loading=k(new Set);errors=k(new Map);limits=new Map;generation=0;follow(e,t){let n=e.componentId===this.target.componentId&&e.pageId===this.target.pageId;this.target=e,n||(this.generation++,this.fetched.set(new Map),this.open.set(new Set),this.loading.set(new Set),this.errors.set(new Map),this.limits.clear()),this.pushed.set(t??{})}level(e,t){let n=wj(e,t),r=this.pushed();return Object.hasOwn(r,n)?r[n]:this.fetched().get(n)}isOpen(e,t){return this.open().has(wj(e,t))}toggle(e,t,n){let r=wj(e,t),i=new Set(this.open());if(i.has(r)){for(let e of i)(e===r||qj(e,r))&&i.delete(e);this.open.set(i),this.send({path:e,directive:t,forget:!0});return}i.add(r),this.open.set(i),n&&this.load(e,t,this.limits.get(r)??30)}more(e,t,n){let r=wj(e,t),i=Math.min(lj,Math.max(n,this.limits.get(r)??0)+100);this.limits.set(r,i),this.load(e,t,i)}async read(e,t,n){return this.send({path:e,depth:t,limit:n})}async load(e,t,n){let r=wj(e,t),i=this.generation;this.loading.update(e=>new Set(e).add(r));let a=await this.send({path:e,directive:t,limit:n,watch:!0});i===this.generation&&(this.loading.update(e=>{let t=new Set(e);return t.delete(r),t}),this.errors.update(e=>{let t=new Map(e);return a.ok?t.delete(r):t.set(r,a.error??`The page did not read it.`),t}),a.ok&&this.fetched.update(e=>new Map(e).set(r,a.value)))}async send(e){let{rpc:t,pageId:n,componentId:r}=this.target;if(!t||!n||!r)return{error:`No live page to read from.`};let{directive:i,...a}=e;try{return await t.scope(`pangular`).rpc.call(`request-component-value`,{pageId:n,request:{id:r,...a,...i===void 0?{}:{directive:i}}})??{}}catch{return{error:`The devtools server did not answer. Try again.`}}}};function Yj(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(2);A(),X(`: `,e.label())}}function Xj(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(3);A(),X(`: `,e.label())}}function Zj(e,t){if(e&1){let e=H();B(0,`button`,4),W(`click`,function(){return E(e),D(G(2).store(`log`))}),J(1,` Log to console `),M(2,Xj,2,1,`span`,1),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),A(2),N(e.label()?2:-1)}}function Qj(e,t){if(e&1){let e=H();B(0,`button`,0),W(`click`,function(){return E(e),D(G().store())}),J(1,` Store as global `),M(2,Yj,2,1,`span`,1),V(),M(3,Zj,3,2,`button`,2),B(4,`span`,3),J(5),V()}if(e&2){let e=G();qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),A(2),N(e.label()?2:-1),A(),N(e.canLog()?3:-1),A(2),Y(e.message())}}var $j=class e{rpc=$(null);pageId=$(null);target=$.required();label=$(``);canLog=$(!1);staticReport=Q(()=>xE(this.rpc()));busy=k(!1);message=k(``);async store(e=`store`){let t=this.rpc(),n=this.pageId();if(t&&n){this.busy.set(!0),this.message.set(``);try{let r=await t.scope(`pangular`).rpc.call(`request-console-global`,{pageId:n,target:this.target(),...e===`log`?{mode:e}:{}}),i=e===`log`?r?.ok?`Logged in the page console.`:`Not logged.`:r?.ok&&r.name?`Stored as ${r.name}.`:`Not stored.`;this.message.set(r?.message||i)}catch{this.message.set(`Could not reach the page.`)}finally{this.busy.set(!1)}}}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-store-global`]],inputs:{rpc:[1,`rpc`],pageId:[1,`pageId`],target:[1,`target`],label:[1,`label`],canLog:[1,`canLog`]},decls:1,vars:1,consts:[[`type`,`button`,1,`store`,3,`click`,`disabled`],[1,`sr-only`],[`type`,`button`,1,`store`,`log`,3,`disabled`],[`role`,`status`,1,`status`],[`type`,`button`,1,`store`,`log`,3,`click`,`disabled`]],template:function(e,t){e&1&&M(0,Qj,6,4),e&2&&N(t.staticReport()?-1:0)},styles:[`[_nghost-%COMP%] { +}`]})};function lM(e,t){return e.length>t.length&&e.startsWith(`${t.slice(0,-1)},`)}var uM=class{target={rpc:null,pageId:null,componentId:null};fetched=k(new Map);pushed=k({});open=k(new Set);loading=k(new Set);errors=k(new Map);limits=new Map;generation=0;follow(e,t){let n=e.componentId===this.target.componentId&&e.pageId===this.target.pageId;this.target=e,n||(this.generation++,this.fetched.set(new Map),this.open.set(new Set),this.loading.set(new Set),this.errors.set(new Map),this.limits.clear()),this.pushed.set(t??{})}level(e,t){let n=Bj(e,t),r=this.pushed();return Object.hasOwn(r,n)?r[n]:this.fetched().get(n)}isOpen(e,t){return this.open().has(Bj(e,t))}toggle(e,t,n){let r=Bj(e,t),i=new Set(this.open());if(i.has(r)){for(let e of i)(e===r||lM(e,r))&&i.delete(e);this.open.set(i),this.send({path:e,directive:t,forget:!0});return}i.add(r),this.open.set(i),n&&this.load(e,t,this.limits.get(r)??30)}more(e,t,n){let r=Bj(e,t),i=Math.min(Tj,Math.max(n,this.limits.get(r)??0)+100);this.limits.set(r,i),this.load(e,t,i)}async read(e,t,n){return this.send({path:e,depth:t,limit:n})}async load(e,t,n){let r=Bj(e,t),i=this.generation;this.loading.update(e=>new Set(e).add(r));let a=await this.send({path:e,directive:t,limit:n,watch:!0});i===this.generation&&(this.loading.update(e=>{let t=new Set(e);return t.delete(r),t}),this.errors.update(e=>{let t=new Map(e);return a.ok?t.delete(r):t.set(r,a.error??`The page did not read it.`),t}),a.ok&&this.fetched.update(e=>new Map(e).set(r,a.value)))}async send(e){let{rpc:t,pageId:n,componentId:r}=this.target;if(!t||!n||!r)return{error:`No live page to read from.`};let{directive:i,...a}=e;try{return await t.scope(`pangular`).rpc.call(`request-component-value`,{pageId:n,request:{id:r,...a,...i===void 0?{}:{directive:i}}})??{}}catch{return{error:`The devtools server did not answer. Try again.`}}}};function dM(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(2);A(),X(`: `,e.label())}}function fM(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(3);A(),X(`: `,e.label())}}function pM(e,t){if(e&1){let e=H();B(0,`button`,4),W(`click`,function(){return E(e),D(G(2).store(`log`))}),J(1,` Log to console `),M(2,fM,2,1,`span`,1),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),A(2),N(e.label()?2:-1)}}function mM(e,t){if(e&1){let e=H();B(0,`button`,0),W(`click`,function(){return E(e),D(G().store())}),J(1,` Store as global `),M(2,dM,2,1,`span`,1),V(),M(3,pM,3,2,`button`,2),B(4,`span`,3),J(5),V()}if(e&2){let e=G();qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),A(2),N(e.label()?2:-1),A(),N(e.canLog()?3:-1),A(2),Y(e.message())}}var hM=class e{rpc=$(null);pageId=$(null);target=$.required();label=$(``);canLog=$(!1);staticReport=Q(()=>FE(this.rpc()));busy=k(!1);message=k(``);async store(e=`store`){let t=this.rpc(),n=this.pageId();if(t&&n){this.busy.set(!0),this.message.set(``);try{let r=await t.scope(`pangular`).rpc.call(`request-console-global`,{pageId:n,target:this.target(),...e===`log`?{mode:e}:{}}),i=e===`log`?r?.ok?`Logged in the page console.`:`Not logged.`:r?.ok&&r.name?`Stored as ${r.name}.`:`Not stored.`;this.message.set(r?.message||i)}catch{this.message.set(`Could not reach the page.`)}finally{this.busy.set(!1)}}}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-store-global`]],inputs:{rpc:[1,`rpc`],pageId:[1,`pageId`],target:[1,`target`],label:[1,`label`],canLog:[1,`canLog`]},decls:1,vars:1,consts:[[`type`,`button`,1,`store`,3,`click`,`disabled`],[1,`sr-only`],[`type`,`button`,1,`store`,`log`,3,`disabled`],[`role`,`status`,1,`status`],[`type`,`button`,1,`store`,`log`,3,`click`,`disabled`]],template:function(e,t){e&1&&M(0,mM,6,4),e&2&&N(t.staticReport()?-1:0)},styles:[`[_nghost-%COMP%] { display: inline-flex; flex-wrap: wrap; align-items: center; @@ -1985,7 +1985,7 @@ button.edit[_ngcontent-%COMP%] { .status[_ngcontent-%COMP%]:empty { display: none; -}`]})},eM=(e,t)=>t.id;function tM(e,t){if(e&1&&(B(0,`p`,4),J(1),V()),e&2){let e=G(2);A(),X(`The page has more @for blocks than the `,e.length,` listed.`)}}function nM(e,t){e&1&&(B(0,`span`,9),J(1,`@empty showing`),V())}function rM(e,t){e&1&&(B(0,`span`,10),J(1,`@empty`),V())}function iM(e,t){e&1&&(B(0,`span`,10),J(1,`renders nothing`),V())}function aM(e,t){if(e&1){let e=H();B(0,`li`)(1,`button`,6),W(`click`,function(){let t=E(e).$implicit;return D(G(3).showOwner.emit(t))})(`focus`,function(){let t=E(e).$implicit,n=G(3);return D(n.highlight.emit(n.target(t)))})(`blur`,function(){return E(e),D(G(3).highlight.emit(null))})(`mouseenter`,function(){let t=E(e).$implicit,n=G(3);return D(n.highlight.emit(n.target(t)))})(`mouseleave`,function(){return E(e),D(G(3).highlight.emit(null))}),B(2,`span`,7),J(3),V(),B(4,`span`,8),J(5),V(),M(6,nM,2,0,`span`,9)(7,rM,2,0,`span`,10)(8,iM,2,0,`span`,10),B(9,`span`,11),J(10),V()()()}if(e&2){let e=t.$implicit,n=G(3);A(),j(`aria-disabled`,e.owner?null:`true`),A(2),Y(e.owner?.name??`Unknown component`),A(2),Z(` `,e.count,` `,e.count===1?`item`:`items`,` `),A(),N(e.showingEmpty?6:e.hasEmptyBlock?7:e.count===0?8:-1),A(4),Y(n.trackLabel(e))}}function oM(e,t){if(e&1&&(B(0,`section`,1)(1,`h2`,2),J(2,` @for blocks `),B(3,`span`,3),J(4),V()(),M(5,tM,2,1,`p`,4),B(6,`ul`,5),P(7,aM,11,6,`li`,null,eM),V()()),e&2){let e=G(),t=G();A(4),Y(t.truncated()?e.length+`+`:e.length),A(),N(t.truncated()?5:-1),A(2),F(e)}}function sM(e,t){e&1&&M(0,oM,9,2,`section`,1),e&2&&N(t.length?0:-1)}function cM(e,t){e&1&&(B(0,`p`,0),J(1,` @for blocks are listed from Angular 22.0 in development builds. This page's Angular does not report them. `),V())}var lM={$index:`track $index`,item:`track item`,function:`track expression`},uM=class e{blocks=$(void 0);truncated=$(!1);supported=$(null);showOwner=Rv();highlight=Rv();target(e){return e.rootIds[0]??e.owner?.id??null}trackLabel(e){return e.track?lM[e.track]:`track unknown`}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-for-blocks`]],inputs:{blocks:[1,`blocks`],truncated:[1,`truncated`],supported:[1,`supported`]},outputs:{showOwner:`showOwner`,highlight:`highlight`},decls:2,vars:1,consts:[[1,`note`,`for`],[`aria-labelledby`,`ct-for-title`,1,`for`],[`id`,`ct-for-title`,1,`for-title`],[1,`pill`],[1,`note`],[1,`for-list`],[`type`,`button`,1,`for-row`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`count`],[1,`flag`,`empty`],[1,`flag`],[1,`track`,`mono`]],template:function(e,t){if(e&1&&M(0,sM,1,1)(1,cM,2,0,`p`,0),e&2){let e;N((e=t.blocks())?0:t.supported()===!1?1:-1,e)}},styles:[`[_nghost-%COMP%] { +}`]})},gM=(e,t)=>t.id;function _M(e,t){if(e&1&&(B(0,`p`,4),J(1),V()),e&2){let e=G(2);A(),X(`The page has more @for blocks than the `,e.length,` listed.`)}}function vM(e,t){e&1&&(B(0,`span`,9),J(1,`@empty showing`),V())}function yM(e,t){e&1&&(B(0,`span`,10),J(1,`@empty`),V())}function bM(e,t){e&1&&(B(0,`span`,10),J(1,`renders nothing`),V())}function xM(e,t){if(e&1){let e=H();B(0,`li`)(1,`button`,6),W(`click`,function(){let t=E(e).$implicit;return D(G(3).showOwner.emit(t))})(`focus`,function(){let t=E(e).$implicit,n=G(3);return D(n.highlight.emit(n.target(t)))})(`blur`,function(){return E(e),D(G(3).highlight.emit(null))})(`mouseenter`,function(){let t=E(e).$implicit,n=G(3);return D(n.highlight.emit(n.target(t)))})(`mouseleave`,function(){return E(e),D(G(3).highlight.emit(null))}),B(2,`span`,7),J(3),V(),B(4,`span`,8),J(5),V(),M(6,vM,2,0,`span`,9)(7,yM,2,0,`span`,10)(8,bM,2,0,`span`,10),B(9,`span`,11),J(10),V()()()}if(e&2){let e=t.$implicit,n=G(3);A(),j(`aria-disabled`,e.owner?null:`true`),A(2),Y(e.owner?.name??`Unknown component`),A(2),Z(` `,e.count,` `,e.count===1?`item`:`items`,` `),A(),N(e.showingEmpty?6:e.hasEmptyBlock?7:e.count===0?8:-1),A(4),Y(n.trackLabel(e))}}function SM(e,t){if(e&1&&(B(0,`section`,1)(1,`h2`,2),J(2,` @for blocks `),B(3,`span`,3),J(4),V()(),M(5,_M,2,1,`p`,4),B(6,`ul`,5),P(7,xM,11,6,`li`,null,gM),V()()),e&2){let e=G(),t=G();A(4),Y(t.truncated()?e.length+`+`:e.length),A(),N(t.truncated()?5:-1),A(2),F(e)}}function CM(e,t){e&1&&M(0,SM,9,2,`section`,1),e&2&&N(t.length?0:-1)}function wM(e,t){e&1&&(B(0,`p`,0),J(1,` @for blocks are listed from Angular 22.0 in development builds. This page's Angular does not report them. `),V())}var TM={$index:`track $index`,item:`track item`,function:`track expression`},EM=class e{blocks=$(void 0);truncated=$(!1);supported=$(null);showOwner=Rv();highlight=Rv();target(e){return e.rootIds[0]??e.owner?.id??null}trackLabel(e){return e.track?TM[e.track]:`track unknown`}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-for-blocks`]],inputs:{blocks:[1,`blocks`],truncated:[1,`truncated`],supported:[1,`supported`]},outputs:{showOwner:`showOwner`,highlight:`highlight`},decls:2,vars:1,consts:[[1,`note`,`for`],[`aria-labelledby`,`ct-for-title`,1,`for`],[`id`,`ct-for-title`,1,`for-title`],[1,`pill`],[1,`note`],[1,`for-list`],[`type`,`button`,1,`for-row`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`count`],[1,`flag`,`empty`],[1,`flag`],[1,`track`,`mono`]],template:function(e,t){if(e&1&&M(0,CM,1,1)(1,wM,2,0,`p`,0),e&2){let e;N((e=t.blocks())?0:t.supported()===!1?1:-1,e)}},styles:[`[_nghost-%COMP%] { display: block; } @@ -2103,7 +2103,7 @@ button.edit[_ngcontent-%COMP%] { min-width: 0; text-overflow: ellipsis; white-space: nowrap; -}`]})},dM=[`filterInput`],fM=[`propFilterInput`],pM=()=>[],mM=e=>({kind:`component`,id:e}),hM=(e,t)=>t.node.id,gM=(e,t)=>t.outlet+t.route,_M=(e,t)=>t+e,vM=(e,t)=>t.formId,yM=(e,t)=>t.name+t.index,bM=(e,t)=>t.name,xM=(e,t)=>t.token+e,SM=(e,t)=>t.id;function CM(e,t){return this.sourceKey(t)}function wM(e,t){if(e&1){let e=H();L(0,`span`,33),J(1,`Page`),R(),L(2,`app-select`,34),U(`valueChange`,function(t){return E(e),D(G(2).selectPage(t))}),R()}if(e&2){let e=G(2);A(2),I(`options`,e.pageOptions())(`value`,e.page()?.pageId??null)}}function TM(e,t){if(e&1){let e=H();L(0,`button`,35),U(`click`,function(){return E(e),D(G(2).toggleDirectiveHosts())}),O(),L(1,`svg`,13),z(2,`path`,36)(3,`path`,37),R(),J(4,` Directive hosts `),R()}e&2&&j(`aria-pressed`,G(2).showDirectiveHosts())}function EM(e,t){if(e&1){let e=H();L(0,`button`,38),U(`click`,function(){E(e);let t=G(2);return D(t.picking()?t.cancelPick():t.pick())}),O(),L(1,`svg`,13),z(2,`path`,39),R(),J(3),R()}if(e&2){let e=G(2);q(`on`,e.picking()),A(3),X(` `,e.picking()?`Cancel pick`:`Pick component on page`,` `)}}function DM(e,t){if(e&1&&(L(0,`p`,20),J(1),R()),e&2){let e=G(2);A(),Y(e.pickMessage())}}function OM(e,t){if(e&1&&(L(0,`p`,21),J(1),R()),e&2){let e=G(2);A(),Y(e.truncationText())}}function kM(e,t){e&1&&(L(0,`p`,41),J(1,`The filter only searches the components the tree lists.`),R())}function AM(e,t){e&1&&(L(0,`p`,41),J(1,`Directive hosts are hidden, so they are not searched.`),R())}function jM(e,t){if(e&1){let e=H();L(0,`div`,24)(1,`p`,40),J(2),R(),M(3,kM,2,0,`p`,41),M(4,AM,2,0,`p`,41),L(5,`button`,42),U(`click`,function(){return E(e),D(G(2).clearFilter())}),J(6,`Clear filter`),R()()}if(e&2){let e=G(2);A(2),X(`No components match “`,e.filter().trim(),`”`),A(),N(e.page().truncated?3:-1),A(),N(!e.showDirectiveHosts()&&e.page().directiveHostCount?4:-1)}}function MM(e,t){if(e&1){let e=H();L(0,`span`,50),U(`click`,function(t){E(e);let n=G().$implicit;return D(G(2).toggle(n.node.id,t))}),O(),L(1,`svg`,51),z(2,`path`,52),R()()}if(e&2){let e=G().$implicit;q(`open`,e.expanded)}}function NM(e,t){e&1&&z(0,`span`,45)}function PM(e,t){if(e&1&&(L(0,`span`,53),J(1),R(),L(2,`span`,54),J(3),R(),L(4,`span`,23),J(5,`directive host`),R()),e&2){let e=G().$implicit,t=G(2);A(),X(`<`,e.node.tag,`>`),A(),j(`title`,e.node.directives?.join(`, `)),A(),Y(t.hostLabel(e.node))}}function FM(e,t){if(e&1&&(L(0,`span`,55),J(1),R(),L(2,`span`,56),J(3),R()),e&2){let e=G().$implicit;A(),Y(e.node.name),A(2),X(`<`,e.node.tag,`>`)}}function IM(e,t){if(e&1&&(L(0,`span`)(1,`span`,23),J(2,`Hydration: `),R(),J(3),R()),e&2){let e=t,n=G(3);M_(`hyd hyd-`+e),A(3),Y(n.hydrationText(e))}}function LM(e,t){if(e&1&&(L(0,`span`,47),J(1),R()),e&2){let e=t.$implicit;A(),Y(e.route||`/`)}}function RM(e,t){if(e&1&&(L(0,`span`,48),J(1),L(2,`span`,23),J(3),R()()),e&2){let e=t;A(),X(` `,e),A(2),X(` `,e===1?`check`:`checks`,` while recording`)}}function zM(e,t){if(e&1&&(L(0,`span`,49),J(1),L(2,`span`,23),J(3),R()()),e&2){let e=G().$implicit;j(`title`,e.node.directives.join(`, `)),A(),X(` +`,e.node.directives.length,` `),A(2),X(` `,e.node.directives.length===1?`directive`:`directives`,` `)}}function BM(e,t){if(e&1){let e=H();L(0,`div`,43),U(`click`,function(){let t=E(e).$implicit;return D(G(2).select(t.node.id))})(`focus`,function(){let t=E(e).$implicit,n=G(2);return n.focusId.set(t.node.id),D(n.highlight(t.node.id))})(`blur`,function(){return E(e),D(G(2).highlight(null))})(`mouseenter`,function(){let t=E(e).$implicit;return D(G(2).highlight(t.node.id))})(`mouseleave`,function(){return E(e),D(G(2).highlight(null))}),M(1,MM,3,2,`span`,44)(2,NM,1,0,`span`,45),M(3,PM,6,3)(4,FM,4,2),M(5,IM,4,3,`span`,46),P(6,LM,2,1,`span`,47,gM),M(8,RM,4,2,`span`,48),M(9,zM,4,3,`span`,49),R()}if(e&2){let e,n,r=t.$implicit,i=G(2);K(`--%NS%depth`,r.depth),q(`selected`,i.selectedId()===r.node.id)(`dir-host`,r.node.kind===`directive`),j(`aria-level`,r.depth+1)(`aria-expanded`,r.hasChildren?r.expanded:null)(`aria-selected`,i.selectedId()===r.node.id)(`tabindex`,i.rovingId()===r.node.id?0:-1)(`data-id`,r.node.id),A(),N(r.hasChildren?1:2),A(2),N(r.node.kind===`directive`?3:4),A(2),N((e=r.node.hydration)?5:-1,e),A(),F(i.routedById().get(r.node.id)??mv(16,pM)),A(2),N((n=i.cdHosts()[r.node.id])?8:-1,n),A(),N(r.node.kind!==`directive`&&r.node.directives?.length?9:-1)}}function VM(e,t){if(e&1&&(L(0,`li`,64),J(1),R()),e&2){let e=t.$implicit;A(),Y(e)}}function HM(e,t){if(e&1){let e=H();L(0,`div`,66)(1,`button`,42),U(`click`,function(){let t=E(e);return D(G(3).reveal(t.id,!0))}),J(2),R()()}e&2&&(A(2),X(` Show `,t.name,` `))}function UM(e,t){if(e&1&&(L(0,`section`,27)(1,`header`,57)(2,`span`,58),J(3,`directive host`),R(),L(4,`h2`,59),J(5),R(),L(6,`span`,60),J(7),R()(),L(8,`div`,61)(9,`h3`),J(10,` Directives `),L(11,`span`,62),J(12),R()(),L(13,`ul`,63),P(14,VM,2,1,`li`,64,_M),R()(),L(16,`div`,61)(17,`p`,65),J(18,` This element hosts directives but no component. Their inputs are bound in the template of the component that renders it. `),R(),M(19,HM,3,1,`div`,66),R()()),e&2){let e,n=t,r=G(2);A(5),X(`<`,n.tag,`>`),A(2),Y(r.hostLabel(n)),A(5),Y(n.directives?.length??0),A(2),F(n.directives??mv(4,pM)),A(5),N((e=r.ownerOf(n.id))?19:-1,e)}}function WM(e,t){if(e&1&&(L(0,`p`,67),z(1,`app-source-link`,71),R()),e&2){let e=t;A(),I(`file`,e.file)(`line`,e.line)}}function GM(e,t){if(e&1){let e=H();L(0,`div`,72)(1,`button`,42),U(`click`,function(){E(e);let t=G();return D(G(2).revealInElements(t))}),J(2,`Reveal in Elements`),R(),L(3,`button`,42),U(`click`,function(){E(e);let t=G();return D(G(2).openSource(t))}),J(4,`Open source`),R()(),L(5,`p`,73),J(6),R()}if(e&2){let e=G(3);A(6),Y(e.actionMessage())}}function KM(e,t){if(e&1){let e=H();L(0,`button`,75),U(`click`,function(){let t=E(e).$implicit;return D(G(5).showForm.emit(t.formId))}),J(1),R()}if(e&2){let e=t.$implicit;A(),X(` Show `,e.label,` in Forms `)}}function qM(e,t){if(e&1&&(L(0,`div`,68),P(1,KM,2,1,`button`,74,vM),R()),e&2){let e=G(),t=G(3);A(),F(t.formsIn(e.file))}}function JM(e,t){e&1&&M(0,qM,3,0,`div`,68),e&2&&N(G(3).formsIn(t.file).length?0:-1)}function YM(e,t){if(e&1){let e=H();L(0,`div`,68)(1,`button`,42),U(`click`,function(){E(e);let t=G();return D(G(2).openInjector(t))}),J(2,` Show in Injectors `),L(3,`span`,23),J(4),R()()()}if(e&2){let e=G();A(4),X(`: `,e.name)}}function XM(e,t){if(e&1&&z(0,`app-store-global`,69),e&2){let e=G(),t=G(2);I(`rpc`,t.rpc())(`pageId`,t.page()?.pageId)(`target`,hv(4,mM,e.id))(`label`,e.name)}}function ZM(e,t){if(e&1&&(L(0,`dt`),J(1,`Routed`),R(),L(2,`dd`,77),J(3),R()),e&2){let e=t.$implicit;A(3),Z(``,e.route||`/`,` in outlet `,e.outlet)}}function QM(e,t){if(e&1&&(L(0,`span`,10),J(1),R()),e&2){let e=G(4);A(),Z(``,e.shownValues()?.count??0,` of `,e.valueTotal())}}function $M(e,t){if(e&1){let e=H();L(0,`div`,81)(1,`p`,40),J(2),R(),L(3,`p`,41),J(4,` The filter searches names, and the nested keys of values you opened. `),R(),L(5,`button`,42),U(`click`,function(){return E(e),D(G(5).clearPropFilter())}),J(6,`Clear filter`),R()()}if(e&2){let e=G(5);A(2),X(` No inputs, outputs or properties match “`,e.propFilter().trim(),`” `)}}function eN(e,t){if(e&1&&(L(0,`span`,85),J(1),R()),e&2){let e=G().$implicit;A(),X(`(`,e.prop,`)`)}}function tN(e,t){if(e&1&&(L(0,`li`,83)(1,`span`,84),J(2),M(3,eN,2,1,`span`,85),R(),z(4,`app-value-tree`,86),R()),e&2){let e=t.$implicit,n=G(4),r=G(3);A(2),X(` `,e.name,` `),A(),N(e.prop===e.name?-1:3),A(),I(`prop`,e)(`store`,r.values)(`query`,r.propFilter())(`componentId`,n.id)(`pageId`,r.page()?.pageId??null)(`rpc`,r.rpc())(`writes`,r.canEdit())}}function nN(e,t){if(e&1&&(L(0,`ul`,82),P(1,tN,5,9,`li`,83,bM),R()),e&2){let e=G(2);A(),F(e.inputs)}}function rN(e,t){e&1&&(L(0,`p`,65),J(1,`No inputs.`),R())}function iN(e,t){if(e&1&&(L(0,`div`,61)(1,`h3`),J(2,` Inputs `),L(3,`span`,62),J(4),R()(),M(5,nN,3,0,`ul`,82)(6,rN,2,0,`p`,65),R()),e&2){let e=G();A(4),Y(e.inputs.length),A(),N(e.inputs.length?5:6)}}function aN(e,t){if(e&1&&(L(0,`li`,88)(1,`span`,77),J(2),R(),L(3,`span`,89),J(4),R()()),e&2){let e=t.$implicit;q(`on`,e.listened),A(2),Y(e.name),A(2),Y(e.listened?`listened`:`no listener`)}}function oN(e,t){if(e&1&&(L(0,`ul`,63),P(1,aN,5,4,`li`,87,bM),R()),e&2){let e=G(2);A(),F(e.outputs)}}function sN(e,t){e&1&&(L(0,`p`,65),J(1,`No outputs.`),R())}function cN(e,t){if(e&1&&(L(0,`div`,61)(1,`h3`),J(2,` Outputs `),L(3,`span`,62),J(4),R()(),M(5,oN,3,0,`ul`,63)(6,sN,2,0,`p`,65),R()),e&2){let e=G();A(4),Y(e.outputs.length),A(),N(e.outputs.length?5:6)}}function lN(e,t){if(e&1&&(L(0,`span`,90),J(1),R()),e&2){let e=G().$implicit;A(),Y(e.kind)}}function uN(e,t){if(e&1&&(L(0,`li`,83)(1,`span`,84),J(2),M(3,lN,2,1,`span`,90),R(),z(4,`app-value-tree`,86),R()),e&2){let e=t.$implicit,n=G(4),r=G(3);A(2),X(` `,e.name,` `),A(),N(e.kind?3:-1),A(),I(`prop`,e)(`store`,r.values)(`query`,r.propFilter())(`componentId`,n.id)(`pageId`,r.page()?.pageId??null)(`rpc`,r.rpc())(`writes`,r.canEdit())}}function dN(e,t){if(e&1&&(L(0,`ul`,82),P(1,uN,5,9,`li`,83,bM),R()),e&2){let e=G(2);A(),F(e.properties)}}function fN(e,t){e&1&&(L(0,`p`,65),J(1,`No other properties.`),R())}function pN(e,t){if(e&1&&(L(0,`div`,61)(1,`h3`),J(2,` Properties `),L(3,`span`,62),J(4),R()(),M(5,dN,3,0,`ul`,82)(6,fN,2,0,`p`,65),R()),e&2){let e=G();A(4),Y(e.properties.length),A(),N(e.properties.length?5:6)}}function mN(e,t){if(e&1&&(L(0,`li`,64),J(1),R()),e&2){let e=t.$implicit;A(),Y(e)}}function hN(e,t){if(e&1&&(L(0,`div`,61)(1,`h3`),J(2,` DOM listeners `),L(3,`span`,62),J(4),R()(),L(5,`ul`,63),P(6,mN,2,1,`li`,64,Ag),R()()),e&2){let e=G(2);A(4),Y(e.listeners.length),A(2),F(e.listeners)}}function gN(e,t){if(e&1&&(L(0,`li`,83)(1,`span`,84),J(2),R(),z(3,`app-value-tree`,91),R()),e&2){let e=t.$implicit,n=G(2).$implicit,r=G(2),i=G(3);A(2),Y(e.name),A(),I(`prop`,e)(`store`,i.values)(`query`,i.propFilter())(`directive`,n.index)(`componentId`,r.id)(`pageId`,i.page()?.pageId??null)(`rpc`,i.rpc())}}function _N(e,t){if(e&1&&(L(0,`ul`,82),P(1,gN,4,8,`li`,83,bM),R()),e&2){let e=G().$implicit;A(),F(e.inputs)}}function vN(e,t){if(e&1&&(L(0,`li`,88)(1,`span`,77),J(2),R(),L(3,`span`,89),J(4),R()()),e&2){let e=t.$implicit;q(`on`,e.listened),A(2),Y(e.name),A(2),Y(e.listened?`listened`:`no listener`)}}function yN(e,t){if(e&1&&(L(0,`ul`,63),P(1,vN,5,4,`li`,87,bM),R()),e&2){let e=G().$implicit;A(),F(e.outputs)}}function bN(e,t){e&1&&(L(0,`p`,65),J(1,`No inputs or outputs.`),R())}function xN(e,t){if(e&1&&(L(0,`div`,61)(1,`h3`)(2,`span`,77),J(3),R(),L(4,`span`,90),J(5,`directive on host`),R()(),M(6,_N,3,0,`ul`,82),M(7,yN,3,0,`ul`,63),M(8,bN,2,0,`p`,65),R()),e&2){let e=t.$implicit;A(3),Y(e.name),A(3),N(e.inputs.length?6:-1),A(),N(e.outputs.length?7:-1),A(),N(!e.inputs.length&&!e.outputs.length?8:-1)}}function SN(e,t){if(e&1&&(M(0,$M,7,1,`div`,81),M(1,iN,7,2,`div`,61),M(2,cN,7,2,`div`,61),M(3,pN,7,2,`div`,61),M(4,hN,8,1,`div`,61),P(5,xN,9,4,`div`,61,yM)),e&2){let e=t,n=G(),r=G(3);N(r.propQuery()&&!e.count?0:-1),A(),N(!r.propQuery()||e.inputs.length?1:-1),A(),N(!r.propQuery()||e.outputs.length?2:-1),A(),N(!r.propQuery()||e.properties.length?3:-1),A(),N(!r.propQuery()&&n.listeners.length?4:-1),A(),F(e.directives)}}function CN(e,t){if(e&1&&(L(0,`span`,90),J(1),R()),e&2){let e=t.$implicit;A(),Y(e)}}function wN(e,t){if(e&1&&(L(0,`span`,94),J(1,`from `),L(2,`span`,77),J(3),R()()),e&2){let e=G().$implicit;A(3),Y(e.providedByName??`an injector`)}}function TN(e,t){e&1&&(L(0,`span`,95),J(1,`not provided`),R())}function EN(e,t){if(e&1&&(L(0,`li`,92)(1,`span`,93),J(2),R(),P(3,CN,2,1,`span`,90,Ag),M(5,wN,4,1,`span`,94)(6,TN,2,0,`span`,95),R()),e&2){let e=t.$implicit;A(2),Y(e.token),A(),F(e.flags),A(2),N(e.providedBy?5:6)}}function DN(e,t){if(e&1&&(L(0,`ul`,80),P(1,EN,7,2,`li`,92,xM),R()),e&2){let e=G();A(),F(e.dependencies)}}function ON(e,t){e&1&&(L(0,`p`,65),J(1,`Nothing is injected through the constructor or inject().`),R())}function kN(e,t){if(e&1){let e=H();L(0,`dl`,76)(1,`dt`),J(2,`Change detection`),R(),L(3,`dd`),J(4),R(),L(5,`dt`),J(6,`Encapsulation`),R(),L(7,`dd`),J(8),R(),L(9,`dt`),J(10,`Host path`),R(),L(11,`dd`,77),J(12),R(),P(13,ZM,4,2,null,null,gM),R(),L(15,`div`,78)(16,`div`,4),O(),L(17,`svg`,5),z(18,`circle`,6)(19,`path`,7),R(),gs(),L(20,`input`,79,1),U(`input`,function(t){return E(e),D(G(3).propFilter.set(t.target.value))})(`keydown.escape`,function(t){return E(e),D(G(3).clearPropFilter(t))}),R()(),M(22,QM,2,2,`span`,10),L(23,`p`,19),J(24),R()(),M(25,SN,7,5),L(26,`div`,61)(27,`h3`),J(28,` Injected `),L(29,`span`,62),J(30),R()(),M(31,DN,3,0,`ul`,80)(32,ON,2,0,`p`,65),R()}if(e&2){let e,n=t,r=G(),i=G(2);A(4),Y(n.changeDetection??`Unknown`),A(4),Y(n.encapsulation??`Unknown`),A(4),Y(n.path),A(),F(i.routedById().get(r.id)??mv(9,pM)),A(7),I(`value`,i.propFilter()),A(2),N(i.propQuery()?22:-1),A(2),Y(i.propFilterStatus()),A(),N((e=i.shownValues())?25:-1,e),A(5),Y(n.dependencies.length),A(),N(n.dependencies.length?31:32)}}function AN(e,t){e&1&&(L(0,`div`,70),z(1,`span`,96),L(2,`p`,41),J(3,`Reading live values from the page…`),R()())}function jN(e,t){if(e&1&&(L(0,`section`,27)(1,`header`,57)(2,`span`,58),J(3,`component`),R(),L(4,`h2`,59),J(5),R(),L(6,`span`,60),J(7),R(),M(8,WM,2,2,`p`,67),M(9,GM,7,1),M(10,JM,1,1),M(11,YM,5,1,`div`,68),M(12,XM,1,6,`app-store-global`,69),R(),M(13,kN,33,10)(14,AN,4,0,`div`,70),R()),e&2){let e,n,r,i=t,a=G(2);A(5),Y(i.name),A(2),X(`<`,i.tag,`>`),A(),N((e=a.whereOf(i))?8:-1,e),A(),N(a.devtoolsActions()?9:-1),A(),N((n=a.sourceFor(i))?10:-1,n),A(),N(a.canShowInjector()&&!a.staticReport()?11:-1),A(),N(!a.staticReport()&&!a.native()?12:-1),A(),N((r=a.detail())?13:14,r)}}function MN(e,t){e&1&&(L(0,`p`,40),J(1,`The selected component was destroyed`),R(),L(2,`p`,41)(3,`span`,77),J(4),R(),J(5,` is no longer on the page. Select another component to see its live values. `),R()),e&2&&(A(4),Y(t))}function NN(e,t){e&1&&(L(0,`p`,41),J(1,` Select a component to see its live inputs, properties, outputs, change detection and injected services. `),R())}function PN(e,t){if(e&1&&(L(0,`div`,28),M(1,MN,6,1)(2,NN,2,0,`p`,41),R()),e&2){let e,t=G(2);A(),N((e=t.destroyed())?1:2,e)}}function FN(e,t){e&1&&(L(0,`span`,90),J(1,`hydrate never`),R())}function IN(e,t){if(e&1&&(L(0,`span`,90),J(1),R()),e&2){let e=G().$implicit;A(),Y(e.hydration)}}function LN(e,t){if(e&1){let e=H();L(0,`li`)(1,`button`,99),U(`click`,function(){let t=E(e).$implicit;return D(G(3).showOwner(t))})(`focus`,function(){let t=E(e).$implicit;return D(G(3).highlightBlock(t))})(`blur`,function(){return E(e),D(G(3).highlight(null))})(`mouseenter`,function(){let t=E(e).$implicit;return D(G(3).highlightBlock(t))})(`mouseleave`,function(){return E(e),D(G(3).highlight(null))}),L(2,`span`,55),J(3),R(),L(4,`span`,100),J(5),R(),M(6,FN,2,0,`span`,90)(7,IN,2,1,`span`,90),L(8,`span`,101),J(9),R()()()}if(e&2){let e=t.$implicit;A(),j(`aria-disabled`,e.owner?null:`true`),A(2),Y(e.owner?.name??`Unknown component`),A(),M_(`defer-state-`+e.state),A(),Y(e.state),A(),N(e.hydrateNever?6:e.hydration===`not-configured`?-1:7),A(3),Y(e.triggers.join(`, `)||`no triggers`)}}function RN(e,t){if(e&1&&(L(0,`section`,29)(1,`h2`,97),J(2,` Defer blocks `),L(3,`span`,62),J(4),R()(),L(5,`ul`,98),P(6,LN,10,7,`li`,null,SM),R()()),e&2){let e=G(2);A(4),Y(e.deferCount()),A(2),F(e.deferBlocks())}}function zN(e,t){if(e&1){let e=H();L(0,`app-hydration-section`,102),U(`overlay`,function(t){return E(e),D(G(2).setHydrationOverlay(t))})(`showNode`,function(t){return E(e),D(G(2).revealNode(t))})(`highlight`,function(t){return E(e),D(G(2).highlight(t))}),R()}e&2&&I(`report`,G(2).page()?.hydration)}function BN(e,t){if(e&1){let e=H();L(0,`app-cd-recording`,103),U(`showComponent`,function(t){return E(e),D(G(2).showCdComponent(t))}),R()}if(e&2){let e=G(2);I(`page`,e.cdPage())(`pageId`,e.page().pageId)(`rpc`,e.rpc())}}function VN(e,t){if(e&1){let e=H();L(0,`p`,2),J(1,` Every component instance on the page, in the order Angular rendered them. Hover a row to highlight its host in the page, and select it to read its live inputs, properties, outputs and injected services. `),R(),L(2,`div`,3)(3,`div`,4),O(),L(4,`svg`,5),z(5,`circle`,6)(6,`path`,7),R(),gs(),L(7,`input`,8,0),U(`input`,function(t){return E(e),D(G().setFilter(t.target.value))})(`keydown.escape`,function(){return E(e),D(G().setFilter(``))}),R(),L(9,`span`,9),J(10,` Type plain text, a tag such as '; + const card = document.querySelector('app-trip-card')!; + const button = document.querySelector('button')!; + const instance = new TripCard(); + const handler = new ErrorHandler(); + const ng = fakeNg(handler, { + getOwningComponent: (el) => (el === button ? instance : null), + getHostElement: (component) => (component === instance ? card : null), + }); + const h = harness(ng); + button.addEventListener('click', () => handler.handleError(new Error('No seats'))); + button.click(); + await h.collector.push(); + const [group] = h.reports.at(-1)!.errors; + expect(group!.owner).toEqual({ id: elementId(card), name: 'TripCard' }); + expect(elementById(group!.owner!.id)).toBe(card); + expect(card.getAttributeNames()).toEqual([]); + }); + + it('finds the owner from the stack when the error did not come from a listener', async () => { + quiet(); + document.body.innerHTML = + ''; + const list = document.querySelector('app-trip-list')!; + const handler = new ErrorHandler(); + const instance = new TripList(); + const ng = fakeNg(handler, { getComponent: (el) => (el === list ? instance : null) }); + const h = harness(ng); + const error = new Error('Cannot read properties of undefined'); + error.stack = + 'TypeError: x\n at TripList_Template (main.js:1:1)\n at refreshView (core.js:1:1)'; + handler.handleError(error); + await h.collector.push(); + expect(h.reports.at(-1)!.errors[0]!.owner).toEqual({ id: elementId(list), name: 'TripList' }); + }); + + it('logs console calls by level, counts repeats in a row and skips its own messages', async () => { + console.log = () => {}; + quiet(); + const h = harness(); + console.log('Loaded trips', { count: 3 }); + console.log('Loaded trips', { count: 3 }); + console.error('NG0500: During hydration Angular expected
'); + console.log('[pangular] Connected'); + await h.collector.push(); + expect(h.reports.at(-1)!.console).toEqual([ + expect.objectContaining({ id: 1, level: 'log', text: 'Loaded trips {"count":3}', count: 2 }), + expect.objectContaining({ id: 2, level: 'error', code: 'NG0500' }), + ]); + }); + + it(`keeps the last ${MAX_CONSOLE_ENTRIES} console calls and sends only new ones after the first push`, async () => { + console.log = () => {}; + const h = harness(); + for (let i = 0; i < MAX_CONSOLE_ENTRIES + 10; i++) console.log(`line ${i}`); + await h.collector.push(); + const first = h.reports.at(-1)!; + expect(first.console).toHaveLength(MAX_CONSOLE_ENTRIES); + expect(first.console[0]!.text).toBe('line 10'); + expect(first.dropped.console).toBe(10); + console.log('one more'); + await h.collector.push(); + const next = h.reports.at(-1)!; + expect(next.full).toBe(false); + expect(next.console.map((entry) => entry.text)).toEqual(['one more']); + expect(next.firstConsoleId).toBe(12); + }); + + it('skips unchanged pushes, sends a keepalive when due, and resends all when the server forgot the page', async () => { + quiet(); + let clock = 0; + const h = harness(undefined, () => clock); + h.handler.handleError(new Error('once')); + await h.collector.push(); + await h.collector.push(); + expect(h.reports).toHaveLength(1); + clock += 60_000; + await h.collector.push(); + expect(h.reports).toHaveLength(2); + expect(h.reports[1]).toMatchObject({ full: false, errors: [], console: [] }); + h.answer.known = false; + clock += 60_000; + await h.collector.push(); + h.answer.known = true; + await h.collector.push(); + expect(h.reports.at(-1)).toMatchObject({ + full: true, + errors: [expect.objectContaining({ message: 'Error: once' })], + }); + expect(h.reports.every((report) => report.pageId === 'page-1')).toBe(true); + }); + + it('forgets the page on leave, stays quiet until it resumes, and restores everything on stop', async () => { + quiet(); + const before = console.error; + const h = harness(); + h.collector.leave(); + expect(h.calls.at(-1)).toEqual({ name: 'forget-errors-page', args: ['page-1'] }); + h.handler.handleError(new Error('while away')); + await h.collector.push(); + expect(h.reports).toHaveLength(0); + h.collector.resume(); + await h.collector.push(); + expect(h.reports.at(-1)).toMatchObject({ full: true }); + h.collector.stop(); + expect(console.error).toBe(before); + expect(consoleTapInfo().listeners).toBe(0); + const swallow = (event: Event) => event.preventDefault(); + window.addEventListener('error', swallow); + window.dispatchEvent(new ErrorEvent('error', { error: new Error('after stop') })); + window.removeEventListener('error', swallow); + await h.collector.push(); + expect(h.reports.at(-1)!.errors.map((e) => e.message)).not.toContain('Error: after stop'); + }); +}); diff --git a/packages/devtools/src/__tests__/errors-real.test.ts b/packages/devtools/src/__tests__/errors-real.test.ts new file mode 100644 index 00000000..db00e1f1 --- /dev/null +++ b/packages/devtools/src/__tests__/errors-real.test.ts @@ -0,0 +1,152 @@ +// @vitest-environment jsdom +import '@angular/compiler'; +import { + Component, + ErrorHandler, + Injectable, + computed, + provideZonelessChangeDetection, + signal, + type ApplicationRef, +} from '@angular/core'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { elementById } from '../element-id.ts'; +import { attachErrors, type ErrorsDebugNg } from '../errors-collector.ts'; +import type { ErrorsReport } from '../rpc/errors-tools.ts'; + +class TripCard { + readonly seats = signal(3); + book(): void { + throw new Error('No seats left on trip 42'); + } + /** Writes a signal inside a computed, which Angular refuses with NG0600. */ + recount(): void { + computed(() => this.seats.set(2))(); + } +} +Component({ + selector: 'app-trip-card', + template: ` + `, +})(TripCard); + +class TripsApp {} +Component({ + selector: 'app-root', + imports: [TripCard], + template: `

Trips

`, +})(TripsApp); + +const handled: unknown[] = []; +class RecordingHandler extends ErrorHandler { + override handleError(error: unknown): void { + handled.push(error); + } +} +Injectable()(RecordingHandler); + +const settle = async (app: ApplicationRef) => { + for (let i = 0; i < 3; i++) { + await new Promise((resolve) => setTimeout(resolve, 0)); + app.tick(); + } +}; + +function harness() { + const reports: ErrorsReport[] = []; + const my = { + rpc: { + call: async (name: string, report: unknown) => { + if (name === 'push-errors') reports.push(report as ErrorsReport); + return { known: true }; + }, + }, + }; + const ng = () => (globalThis as { ng?: ErrorsDebugNg }).ng; + return { reports, collector: attachErrors(my, 'real-page', ng) }; +} + +describe('the errors collector with a real app', () => { + let app: ApplicationRef | null = null; + let stop = () => {}; + afterEach(() => { + stop(); + app?.destroy(); + app = null; + handled.length = 0; + document.body.innerHTML = ''; + vi.restoreAllMocks(); + }); + + it("wraps the default ErrorHandler, keeps it logging, and links the template's component", async () => { + const logged = vi.spyOn(console, 'error').mockImplementation(() => {}); + document.body.innerHTML = ''; + app = await bootstrapApplication(TripsApp, { providers: [provideZonelessChangeDetection()] }); + await settle(app); + const { reports, collector } = harness(); + stop = collector.stop; + await collector.push(); + expect(reports.at(-1)?.handler).toBe('wrapped'); + + document.querySelector('button')!.click(); + await collector.push(); + + // Angular's own handler still ran and logged the error. + expect(logged).toHaveBeenCalledWith('ERROR', expect.any(Error)); + const [group] = reports.at(-1)!.errors; + expect(group).toMatchObject({ + message: 'Error: No seats left on trip 42', + count: 1, + sources: ['handler'], + owner: { name: 'TripCard' }, + }); + expect(elementById(group!.owner!.id)).toBe(document.querySelector('app-trip-card')); + // The console log has the handler's line too. + expect(reports.at(-1)!.console.map((entry) => entry.level)).toContain('error'); + }); + + it('reads the code of a real RuntimeError and links its reference page', async () => { + vi.spyOn(console, 'error').mockImplementation(() => {}); + document.body.innerHTML = ''; + app = await bootstrapApplication(TripsApp, { providers: [provideZonelessChangeDetection()] }); + await settle(app); + const { reports, collector } = harness(); + stop = collector.stop; + document.querySelector('button.recount')!.click(); + await collector.push(); + expect(reports.at(-1)!.errors[0]).toMatchObject({ + code: 'NG0600', + docUrl: 'https://angular.dev/errors/NG0600', + owner: { name: 'TripCard' }, + }); + }); + + it('keeps a custom ErrorHandler running and restores it on stop', async () => { + document.body.innerHTML = ''; + app = await bootstrapApplication(TripsApp, { + providers: [ + provideZonelessChangeDetection(), + { provide: ErrorHandler, useClass: RecordingHandler }, + ], + }); + await settle(app); + const { reports, collector } = harness(); + await collector.push(); + expect(reports.at(-1)?.handler).toBe('wrapped'); + + stop = collector.stop; + document.querySelector('button')!.click(); + document.querySelector('button')!.click(); + await collector.push(); + expect(handled).toHaveLength(2); + expect(reports.at(-1)!.errors[0]).toMatchObject({ count: 2, owner: { name: 'TripCard' } }); + + const handler = app.injector.get(ErrorHandler) as RecordingHandler; + expect(Object.hasOwn(handler, 'handleError')).toBe(true); + collector.stop(); + expect(Object.hasOwn(handler, 'handleError')).toBe(false); + document.querySelector('button')!.click(); + expect(handled).toHaveLength(3); + }); +}); diff --git a/packages/devtools/src/__tests__/errors-tools.test.ts b/packages/devtools/src/__tests__/errors-tools.test.ts new file mode 100644 index 00000000..acd427b1 --- /dev/null +++ b/packages/devtools/src/__tests__/errors-tools.test.ts @@ -0,0 +1,223 @@ +import { createHostContext } from 'devframe/node'; +import { describe, expect, it } from 'vitest'; +import pangular, { createPangular } from '../devframe.ts'; +import { + explainErrorText, + mergeErrorsReport, + staleErrorPages, + toErrorsReport, + type ErrorGroup, + type ErrorsReport, + type ErrorsState, +} from '../rpc/errors-tools.ts'; + +const JWT = ['eyJhbGciOiJIUzI1NiJ9', 'eyJzdWIiOiIxMjM0NSJ9', 'c2lnbmF0dXJlc2ln'].join('.'); + +async function boot(definition = pangular) { + const host = { + mountStatic: () => {}, + resolveOrigin: () => 'http://localhost', + getStorageDir: () => '', + }; + const ctx = await createHostContext({ cwd: process.cwd(), mode: 'dev', host: host as never }); + await definition.setup(ctx as never); + const call = (name: string, payload: unknown) => + ctx.rpc.invokeLocal(`pangular:${name}` as never, ...([payload] as never)); + const invoke = async (id: string, args: Record = {}) => + ((await ctx.agent.invoke(`pangular:${id}`, args)) as { markdown: string }).markdown; + const state = async () => + ( + await ( + ctx.rpc as unknown as { + sharedState: { get: (key: string) => Promise<{ value: () => ErrorsState }> }; + } + ).sharedState.get('pangular:errors') + ).value(); + return { ctx, call, invoke, state }; +} + +const group = (extra: Partial = {}): ErrorGroup => ({ + id: 'e1', + message: 'Error: No seats left', + name: 'Error', + count: 2, + firstAt: Date.now() - 10_000, + lastAt: Date.now() - 1_000, + sources: ['handler'], + stack: 'Error: No seats left\n at _TripCard.book (main.js:10:5)', + owner: { id: 'cabc-3', name: 'TripCard' }, + ...extra, +}); + +const report = (extra: Partial = {}): ErrorsReport => ({ + pageId: 'tab1', + full: true, + url: '/trips', + title: 'Trips', + handler: 'wrapped', + errors: [group()], + console: [ + { id: 1, level: 'log', text: 'Loaded trips', at: Date.now() - 5_000, count: 3 }, + { + id: 2, + level: 'warn', + text: 'NG0913: image is too large', + at: Date.now(), + count: 1, + code: 'NG0913', + }, + ], + dropped: { errors: 0, console: 0 }, + ...extra, +}); + +describe('errors reports on the server', () => { + it('keeps one entry per page and merges partial reports into it', async () => { + const { call, state } = await boot(); + expect(await call('push-errors', report())).toEqual({ known: true }); + expect(await call('push-errors', report({ pageId: 'tab2' }))).toEqual({ known: true }); + await call( + 'push-errors', + report({ + full: false, + errors: [group({ count: 5 })], + console: [{ id: 3, level: 'error', text: 'boom', at: Date.now(), count: 1 }], + firstConsoleId: 2, + }), + ); + const value = await state(); + expect(Object.keys(value.pages).sort()).toEqual(['tab1', 'tab2']); + expect(value.pages['tab1']!.errors['e1']!.count).toBe(5); + expect(Object.keys(value.pages['tab1']!.console)).toEqual(['2', '3']); + expect(value.pages['tab2']!.errors['e1']!.count).toBe(2); + }); + + it('asks for the whole report when it does not know the page', async () => { + const { call } = await boot(); + expect(await call('push-errors', report({ full: false }))).toEqual({ known: false }); + }); + + it('forgets a page on forget-errors-page and when it stops reporting', async () => { + const { call, state } = await boot(); + await call('push-errors', report()); + await call('forget-errors-page', 'tab1'); + expect((await state()).pages).toEqual({}); + const merged: ErrorsState = { pages: {} }; + mergeErrorsReport(merged, toErrorsReport(report())!, 1000); + expect(staleErrorPages(merged, 1000 + 14_000, () => 15_000)).toEqual([]); + expect(staleErrorPages(merged, 1000 + 16_000, () => 15_000)).toEqual(['tab1']); + }); + + it('masks and caps what a page sends, and rebuilds the reference link itself', () => { + const checked = toErrorsReport({ + ...report(), + errors: [ + group({ + message: `Bearer ${JWT} ${'y'.repeat(2000)}`, + code: 'NG0100', + docUrl: 'https://evil.example/NG0100', + }), + { id: 'e2', message: 'not a code', code: '