From f6358bf1246809675da6494e54e7af5291516033 Mon Sep 17 00:00:00 2001 From: Matt Gros <3311227+mpge@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:43:15 -0400 Subject: [PATCH 1/3] fix(plugin): install window.route stub for non-Laravel hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 77 components in this package call Ziggy's route(name, params) helper, which is Laravel-specific. Non-Laravel hosts (Rails, Django, NestJS, Phoenix, etc.) don't ship Ziggy, so the calls fail with a bare ReferenceError deep inside component renders, giving the host developer zero hint about the underlying cause. Install a safety stub on window.route in EscalatedPlugin.install() that throws a descriptive error naming the missing dependency. Laravel hosts with Ziggy already loaded are left untouched; we only install the stub when window.route is undefined. This is not a functional Ziggy shim — full route() compat across 77 call sites is a separate, larger effort — but it makes the missing-dependency failure mode actionable. --- src/plugin.js | 24 +++++++++++++++++++++++ tests/plugin.test.js | 45 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/plugin.js b/src/plugin.js index 6e2030f..a83b244 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -17,6 +17,8 @@ import { markRaw } from 'vue'; */ export const EscalatedPlugin = { install(app, options = {}) { + installRouteShim(); + if (options.layout) { app.provide('escalated-layout', markRaw(options.layout)); } @@ -38,6 +40,28 @@ export const EscalatedPlugin = { }, }; +// 77 components in this package call the Ziggy `route()` helper (Laravel's +// named-route URL generator). Laravel hosts ship Ziggy and get `window.route` +// for free; other host frameworks (Rails, Django, NestJS, Rails, Phoenix, …) +// don't, and the call sites would otherwise throw a bare ReferenceError deep +// inside a component render with no hint at the cause. +// +// Install a stub that throws an informative error instead, so the host app's +// first failing request points at the actual missing dependency. Laravel hosts +// that already have Ziggy loaded are left alone. +function installRouteShim() { + if (typeof window === 'undefined') return; + if (typeof window.route === 'function') return; + + window.route = function escalatedRouteShimMissing(name) { + throw new Error( + `[escalated] window.route('${name}') called, but no \`route()\` helper is installed on this host. ` + + `The escalated agent/admin UI depends on Laravel's Ziggy-style \`route(name, params)\` helper. ` + + `Install Ziggy (on Laravel hosts) or register a compatible shim on window.route before mounting the app.`, + ); + }; +} + const themeDefaults = { primary: '#4f46e5', primaryHover: null, diff --git a/tests/plugin.test.js b/tests/plugin.test.js index 8e6d57e..320ee44 100644 --- a/tests/plugin.test.js +++ b/tests/plugin.test.js @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { createApp } from 'vue'; import { EscalatedPlugin } from '../src/plugin.js'; @@ -159,6 +159,49 @@ describe('EscalatedPlugin', () => { }); }); +describe('route() helper shim', () => { + let originalRoute; + + beforeEach(() => { + originalRoute = window.route; + delete window.route; + }); + + afterEach(() => { + if (originalRoute === undefined) { + delete window.route; + } else { + window.route = originalRoute; + } + }); + + it('installs a window.route stub on non-Laravel hosts', () => { + expect(typeof window.route).toBe('undefined'); + installPlugin(); + expect(typeof window.route).toBe('function'); + }); + + it('the stub throws a descriptive error when called', () => { + installPlugin(); + + expect(() => window.route('escalated.admin.saved-views.update', 1)).toThrow( + /window\.route\('escalated\.admin\.saved-views\.update'\)/, + ); + expect(() => window.route('x')).toThrow(/Install Ziggy/); + }); + + it('does not overwrite an existing window.route from a Laravel host', () => { + const existing = vi.fn(() => '/from-ziggy'); + window.route = existing; + + installPlugin(); + + expect(window.route).toBe(existing); + expect(window.route('some.name')).toBe('/from-ziggy'); + expect(existing).toHaveBeenCalledWith('some.name'); + }); +}); + describe('darken() utility (tested indirectly via theme)', () => { beforeEach(() => { document.documentElement.style.removeProperty('--esc-primary-hover'); From 0d54e455bef76a4be832b05224524766577a001d Mon Sep 17 00:00:00 2001 From: Matt Gros <3311227+mpge@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:53:54 -0400 Subject: [PATCH 2/3] docs(plugin): fix duplicate 'Rails' in route shim comment --- src/plugin.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugin.js b/src/plugin.js index a83b244..f624a9f 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -42,9 +42,10 @@ export const EscalatedPlugin = { // 77 components in this package call the Ziggy `route()` helper (Laravel's // named-route URL generator). Laravel hosts ship Ziggy and get `window.route` -// for free; other host frameworks (Rails, Django, NestJS, Rails, Phoenix, …) -// don't, and the call sites would otherwise throw a bare ReferenceError deep -// inside a component render with no hint at the cause. +// for free; other host frameworks (Rails, Django, NestJS, Phoenix, Symfony, +// Adonis, Go, .NET, Spring, WordPress) don't, and the call sites would +// otherwise throw a bare ReferenceError deep inside a component render with +// no hint at the cause. // // Install a stub that throws an informative error instead, so the host app's // first failing request points at the actual missing dependency. Laravel hosts From cf42338785ec97ed148447e30da6935ae9860f3e Mon Sep 17 00:00:00 2001 From: Matt Gros <3311227+mpge@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:54:49 -0400 Subject: [PATCH 3/3] docs(changelog): record route-shim fix under [Unreleased] --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d9fb3e..222a708 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to `@escalated-dev/escalated` will be documented in this file. +## [Unreleased] + +### Fixed +- Install a `window.route` safety stub in `EscalatedPlugin.install()` on hosts that haven't provided their own. Non-Laravel hosts previously saw bare `ReferenceError: route is not defined` errors when any of the 77 components that call Ziggy's `route(name, params)` helper rendered. The stub throws a descriptive error naming the missing dependency instead. Laravel hosts with Ziggy loaded are untouched. + ## [0.7.0] - 2026-04-05 ### Added