@scayle/storefront-devtools 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +222 -0
- package/dist/_chunks/clipboard-DrVHc2QA.mjs +61 -0
- package/dist/_chunks/diff-DzJ5arJj.mjs +169 -0
- package/dist/_chunks/panel-uV5ITqhY.mjs +51 -0
- package/dist/_chunks/redact-DmIF-iyk.mjs +96 -0
- package/dist/_chunks/useStore-Db8RZW8T.mjs +10 -0
- package/dist/group.d.ts +42 -0
- package/dist/group.d.ts.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +178 -0
- package/dist/inertia/client/index.d.mts +13 -0
- package/dist/inertia/client/index.d.ts +7 -0
- package/dist/inertia/client/index.d.ts.map +1 -0
- package/dist/inertia/client/index.mjs +694 -0
- package/dist/inertia/core/capture.d.ts +15 -0
- package/dist/inertia/core/capture.d.ts.map +1 -0
- package/dist/inertia/core/correlator.d.ts +91 -0
- package/dist/inertia/core/correlator.d.ts.map +1 -0
- package/dist/inertia/core/diagnostics.d.ts +10 -0
- package/dist/inertia/core/diagnostics.d.ts.map +1 -0
- package/dist/inertia/core/diff.d.ts +33 -0
- package/dist/inertia/core/diff.d.ts.map +1 -0
- package/dist/inertia/core/events-tab.d.ts +20 -0
- package/dist/inertia/core/events-tab.d.ts.map +1 -0
- package/dist/inertia/core/feature-info.d.ts +14 -0
- package/dist/inertia/core/feature-info.d.ts.map +1 -0
- package/dist/inertia/core/features.d.ts +27 -0
- package/dist/inertia/core/features.d.ts.map +1 -0
- package/dist/inertia/core/history-capture.d.ts +15 -0
- package/dist/inertia/core/history-capture.d.ts.map +1 -0
- package/dist/inertia/core/interceptors.d.ts +69 -0
- package/dist/inertia/core/interceptors.d.ts.map +1 -0
- package/dist/inertia/core/markdown.d.ts +10 -0
- package/dist/inertia/core/markdown.d.ts.map +1 -0
- package/dist/inertia/core/network.d.ts +34 -0
- package/dist/inertia/core/network.d.ts.map +1 -0
- package/dist/inertia/core/protocol.d.ts +38 -0
- package/dist/inertia/core/protocol.d.ts.map +1 -0
- package/dist/inertia/core/request-tree.d.ts +18 -0
- package/dist/inertia/core/request-tree.d.ts.map +1 -0
- package/dist/inertia/core/response.d.ts +39 -0
- package/dist/inertia/core/response.d.ts.map +1 -0
- package/dist/inertia/core/session.d.ts +18 -0
- package/dist/inertia/core/session.d.ts.map +1 -0
- package/dist/inertia/core/store.d.ts +40 -0
- package/dist/inertia/core/store.d.ts.map +1 -0
- package/dist/inertia/core/types.d.ts +112 -0
- package/dist/inertia/core/types.d.ts.map +1 -0
- package/dist/inertia/core/url.d.ts +11 -0
- package/dist/inertia/core/url.d.ts.map +1 -0
- package/dist/inertia/plugin.d.ts +11 -0
- package/dist/inertia/plugin.d.ts.map +1 -0
- package/dist/inertia/renderer/index.d.mts +16 -0
- package/dist/inertia/renderer/index.mjs +771 -0
- package/dist/inject.d.ts +12 -0
- package/dist/inject.d.ts.map +1 -0
- package/dist/orpc/client/index.d.mts +13 -0
- package/dist/orpc/client/index.d.ts +7 -0
- package/dist/orpc/client/index.d.ts.map +1 -0
- package/dist/orpc/client/index.mjs +502 -0
- package/dist/orpc/core/capture.d.ts +32 -0
- package/dist/orpc/core/capture.d.ts.map +1 -0
- package/dist/orpc/core/classify.d.ts +14 -0
- package/dist/orpc/core/classify.d.ts.map +1 -0
- package/dist/orpc/core/curl.d.ts +11 -0
- package/dist/orpc/core/curl.d.ts.map +1 -0
- package/dist/orpc/core/markdown.d.ts +12 -0
- package/dist/orpc/core/markdown.d.ts.map +1 -0
- package/dist/orpc/core/orpc-error.d.ts +18 -0
- package/dist/orpc/core/orpc-error.d.ts.map +1 -0
- package/dist/orpc/core/serialize.d.ts +12 -0
- package/dist/orpc/core/serialize.d.ts.map +1 -0
- package/dist/orpc/core/session.d.ts +15 -0
- package/dist/orpc/core/session.d.ts.map +1 -0
- package/dist/orpc/core/store.d.ts +50 -0
- package/dist/orpc/core/store.d.ts.map +1 -0
- package/dist/orpc/core/types.d.ts +67 -0
- package/dist/orpc/core/types.d.ts.map +1 -0
- package/dist/orpc/core/url.d.ts +12 -0
- package/dist/orpc/core/url.d.ts.map +1 -0
- package/dist/orpc/plugin.d.ts +10 -0
- package/dist/orpc/plugin.d.ts.map +1 -0
- package/dist/orpc/renderer/index.d.mts +16 -0
- package/dist/orpc/renderer/index.mjs +457 -0
- package/dist/resource-center/client/index.mjs +21 -0
- package/dist/resource-center/client.d.ts +3 -0
- package/dist/resource-center/client.d.ts.map +1 -0
- package/dist/resource-center/plugin.d.ts +12 -0
- package/dist/resource-center/plugin.d.ts.map +1 -0
- package/dist/shared/clipboard.d.ts +9 -0
- package/dist/shared/clipboard.d.ts.map +1 -0
- package/dist/shared/redact.d.ts +27 -0
- package/dist/shared/redact.d.ts.map +1 -0
- package/dist/shared/safe-clone.d.ts +46 -0
- package/dist/shared/safe-clone.d.ts.map +1 -0
- package/dist/shared/session-storage.d.ts +18 -0
- package/dist/shared/session-storage.d.ts.map +1 -0
- package/dist/shared/use-window-store.d.ts +18 -0
- package/dist/shared/use-window-store.d.ts.map +1 -0
- package/dist/storefront/plugin.d.ts +9 -0
- package/dist/storefront/plugin.d.ts.map +1 -0
- package/dist/storefront/renderer/index.d.mts +16 -0
- package/dist/storefront/renderer/index.mjs +124 -0
- package/dist/vue-devtools/client/index.mjs +4912 -0
- package/dist/vue-devtools/client.d.ts +2 -0
- package/dist/vue-devtools/client.d.ts.map +1 -0
- package/dist/vue-devtools/plugin.d.ts +14 -0
- package/dist/vue-devtools/plugin.d.ts.map +1 -0
- package/dist/vue-devtools/ui/assets/css-8QJvnqUH.js +1 -0
- package/dist/vue-devtools/ui/assets/css-CaJ9TzKE.js +1 -0
- package/dist/vue-devtools/ui/assets/diff-woXpYk--.js +1 -0
- package/dist/vue-devtools/ui/assets/html-BHDw6EPc.js +1 -0
- package/dist/vue-devtools/ui/assets/html-GueGcY0x.js +1 -0
- package/dist/vue-devtools/ui/assets/index-Dby9TIQH.js +156 -0
- package/dist/vue-devtools/ui/assets/index-sSkqWPzY.css +1 -0
- package/dist/vue-devtools/ui/assets/javascript-BzbQS41l.js +1 -0
- package/dist/vue-devtools/ui/assets/javascript-Yelw-5ZN.js +1 -0
- package/dist/vue-devtools/ui/assets/json-B88Oqtu5.js +1 -0
- package/dist/vue-devtools/ui/assets/json-CaljABEy.js +1 -0
- package/dist/vue-devtools/ui/assets/shellscript-CLZ0U2zV.js +1 -0
- package/dist/vue-devtools/ui/assets/typescript-Utq2Cl8c.js +1 -0
- package/dist/vue-devtools/ui/assets/typescript-j_1H8WHN.js +1 -0
- package/dist/vue-devtools/ui/assets/vitesse-dark-BZCL-v6S.js +1 -0
- package/dist/vue-devtools/ui/assets/vitesse-light-VbXTXTou.js +1 -0
- package/dist/vue-devtools/ui/assets/vue-B1Tf5CHw.js +1 -0
- package/dist/vue-devtools/ui/assets/vue-html-CGMs_6qn.js +1 -0
- package/dist/vue-devtools/ui/assets/yaml-rwi0_p6S.js +1 -0
- package/dist/vue-devtools/ui/index.html +13 -0
- package/package.json +101 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @scayle/storefront-devtools
|
|
2
|
+
|
|
3
|
+
## 0.2.0-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- First release of `@scayle/storefront-devtools`, a dev-only Vite plugin that adds Storefront Application V3 panels to the Vite DevTools dock:
|
|
8
|
+
|
|
9
|
+
- **Inertia.js panel**: every visit your app makes, correlated into one request per navigation. Shows the response body and headers, the Inertia protocol details (partial reload keys, asset version, redirects), and a lifecycle timeline, with diagnostics for common mistakes like a missing partial-reload prop.
|
|
10
|
+
- **oRPC panel**: every call to your `/api` endpoint, decoded from its wire format back to typed input and output. Groups calls by procedure, classifies failures, and tracks per-procedure timing.
|
|
11
|
+
- **Storefront context panel**: a read-only view of the resolved shop, country, locale, and session for the page you're looking at.
|
|
12
|
+
- **Resource Center**: the Storefront documentation, embedded in the dock so you don't have to leave the app to look something up.
|
|
13
|
+
- **Vue panel**: the component tree and timeline you'd otherwise get from a separate `vite-plugin-vue-devtools` install.
|
|
14
|
+
|
|
15
|
+
Add `storefrontDevtools()` to your `vite.config.ts` plugins array and nothing else. The plugin only runs on the dev server and drops out of production builds automatically.
|
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
<h1 align="center">
|
|
4
|
+
SCAYLE Storefront DevTools
|
|
5
|
+
</h1>
|
|
6
|
+
|
|
7
|
+
<h4 align="center">
|
|
8
|
+
<a href="https://scayle.dev">Documentation</a> |
|
|
9
|
+
<a href="https://www.scayle.com/">Website</a>
|
|
10
|
+
</h4>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
The SCAYLE <strong>Storefront DevTools</strong> package wires the Vite DevTools dock into the Storefront Application V3, with an Inertia.js inspector, an oRPC call inspector, a Storefront context viewer, a Resource Center, and Vue DevTools, behind a single Vite plugin call.
|
|
14
|
+
</p>
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="#"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="SCAYLE's Storefront DevTools is released under the MIT license." /></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
## Overview
|
|
20
|
+
|
|
21
|
+
`@scayle/storefront-devtools` is a dev-only Vite plugin. It hosts the Vite DevTools dock and registers a **SCAYLE Storefront** dock group, plus a **Vue** group:
|
|
22
|
+
|
|
23
|
+
- **Inertia.js panel**: every visit your app makes, correlated into one request per navigation. Shows the response body and headers, the Inertia protocol details (partial reload keys, asset version, redirects), and a lifecycle timeline, with diagnostics for common mistakes like a missing partial-reload prop. The [Inertia.js panel](#inertiajs-panel) section covers it in depth.
|
|
24
|
+
- **oRPC panel**: every call to your `/api` endpoint, decoded from its wire format back to typed input and output. Groups calls by procedure, classifies failures, and tracks per-procedure timing. The [oRPC panel](#orpc-panel) section covers it in depth.
|
|
25
|
+
- **Storefront context panel**: a read-only view of the resolved shop, country, locale, and session for the page you're looking at, read from the Inertia page the SDK ships. The [Storefront context panel](#storefront-context-panel) section covers it.
|
|
26
|
+
- **Resource Center**: the Storefront documentation, embedded in the dock so you don't have to leave the app to look something up.
|
|
27
|
+
- **Vue panel**: the component tree and timeline you'd otherwise get from a separate `vite-plugin-vue-devtools` install, mounted in the same dock.
|
|
28
|
+
|
|
29
|
+
The plugin runs only on the dev server and drops out of production builds with no environment flag needed — see "Production safety" below for exactly why.
|
|
30
|
+
|
|
31
|
+
## Why not the browser Network tab?
|
|
32
|
+
|
|
33
|
+
The browser's Network tab is the right tool for raw HTTP. These panels exist for what it structurally cannot show.
|
|
34
|
+
|
|
35
|
+
- **Inertia visits often have no network footprint.** The initial page load embeds the page object in the HTML, so it is never an XHR. Client-side history navigations, prefetch cache hits, and `preserveState` updates produce no request at all. The Network tab has no row for any of these. The panel captures them from Inertia's DOM events and history, so they are visible.
|
|
36
|
+
- **The panel diffs and correlates across visits.** It shows a structural props diff between consecutive visits, links a deferred-prop reload to the parent visit that triggered it, and renders the lifecycle event timeline. The Network tab shows one request at a time with no memory of the last one.
|
|
37
|
+
- **oRPC bodies on the wire are not your arguments.** Every oRPC call is a `POST /api` carrying a `{ json, meta }` envelope. The Network tab shows that envelope raw and cannot reconstruct the `Date`, `Map`, `Set`, or `BigInt` values it encodes, because JSON has no way to represent them. The panel decodes the envelope to the typed value your handler actually received.
|
|
38
|
+
- **oRPC calls are indistinguishable in the Network tab.** They are all POSTs to the same `/api` URL, so you cannot tell `basket/add` from `wishlist/remove` without opening each one and reading the body. The panel groups by procedure, aggregates per-procedure timing, and classifies each failure as validation, server, or network.
|
|
39
|
+
|
|
40
|
+
Where it overlaps the Network tab (the per-call HTTP view of a single oRPC request), the panels do not try to replace it. Use the Network tab for the raw transaction, the panels for the framework-level meaning.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
The package ships with Storefront Application V3 by default. To add it manually:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pnpm add -D @scayle/storefront-devtools
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Integration
|
|
51
|
+
|
|
52
|
+
The package is consumed only from the Storefront Application V3 `vite.config.ts`. No other application code changes are required: the dock client and the Inertia and oRPC capture clients are injected into the application's client entry automatically.
|
|
53
|
+
|
|
54
|
+
Import the default export and spread it into the `plugins` array, after `@vitejs/plugin-vue`:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// vite.config.ts
|
|
58
|
+
import { defineConfig } from 'vite'
|
|
59
|
+
import vue from '@vitejs/plugin-vue'
|
|
60
|
+
import storefrontDevtools from '@scayle/storefront-devtools'
|
|
61
|
+
import storefrontBuild from '@scayle/storefront-build'
|
|
62
|
+
|
|
63
|
+
export default defineConfig({
|
|
64
|
+
plugins: [
|
|
65
|
+
vue(),
|
|
66
|
+
// The Vite DevTools dock with the SCAYLE Storefront panels.
|
|
67
|
+
...storefrontDevtools(),
|
|
68
|
+
storefrontBuild({
|
|
69
|
+
serverEntry: './src/server/index.ts',
|
|
70
|
+
ssrEntry: './src/client/ssr.ts',
|
|
71
|
+
indexEntry: './src/client/index.html',
|
|
72
|
+
}),
|
|
73
|
+
// ...other plugins
|
|
74
|
+
],
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`storefrontDevtools()` returns an array of Vite plugins, so it must be spread. It also provides the Vue DevTools panel itself, so no separate `vite-plugin-vue-devtools` is needed.
|
|
79
|
+
|
|
80
|
+
### Dev server path exclusion
|
|
81
|
+
|
|
82
|
+
The dock and its assets are served by Vite under `/__devtools/` and `/__storefront-devtools/`. The Storefront Application V3 serves pages through a Hono dev server with a country-prefix redirect, which would otherwise catch those paths and rewrite them. `@scayle/storefront-build` already excludes the DevTools mount paths from the Hono dev server, so no extra configuration is needed when both packages are present.
|
|
83
|
+
|
|
84
|
+
`storefrontDevtools()` takes no options. It always registers the Inertia.js, oRPC, Storefront context, Resource Center, and Vue panels, and always injects into the Storefront Application V3's own client entry (`src/client/main.ts`).
|
|
85
|
+
|
|
86
|
+
## Opening the dock
|
|
87
|
+
|
|
88
|
+
Run the Storefront Application V3 dev server (`pnpm dev`) and open the app. A floating launcher appears on the page. Open it, then open the **SCAYLE Storefront** group to reach the **Inertia.js**, **oRPC**, **Storefront**, and **Resource Center** entries, or the **Vue** group for the component tree and timeline.
|
|
89
|
+
|
|
90
|
+
The launcher is injected into the client entry (not the HTML) because the Storefront Application V3 composes its HTML through the SSR renderer, so Vite's `transformIndexHtml` hook never fires. The same mechanism injects every panel's capture client.
|
|
91
|
+
|
|
92
|
+
## Security: how the dock authenticates the browser
|
|
93
|
+
|
|
94
|
+
The dock's browser side and the Vite dev server talk over a WebSocket RPC channel (`@devframes/hub`, using `crossws` as its transport abstraction). That channel is not limited to rendering our panels — `@vitejs/devtools` ships its own built-in RPC surface with real capabilities on the developer's machine, most notably **`vite:core:open-in-editor`** (opens an arbitrary file path in the developer's editor) and a terminals feed. This package sets `builtinDevTools: false`, which drops the upstream Terminals/Messages/Inspector docks and their UI, but the underlying RPC declarations are part of `@vitejs/devtools` itself, not something a consumer can un-register from the wire protocol. Two independent gates protect this channel:
|
|
95
|
+
|
|
96
|
+
- **Origin allowlist.** `@vitejs/devtools` only accepts WebSocket connections whose `Origin` header matches a built-in loopback allowlist (`localhost`, `127.0.0.1`, and similar). This check is a **plain string match, not a DNS or hosts-file resolution** — a custom dev hostname that resolves to loopback via `/etc/hosts` or a local DNS override (e.g. `dev-my-app.example.com`) is invisible to it and gets rejected by default. If your setup needs a non-default hostname (a reverse proxy, a tunnel, a custom `/etc/hosts` entry), list it explicitly via `devtools: { allowedOrigins: ['https://dev-my-app.example.com'] }` in the app's Vite config.
|
|
97
|
+
- **One-time client authorization.** On top of the origin check, `@vitejs/devtools` gates the RPC connection behind a one-time code by default (`clientAuth: true`). On first connection from a new browser, the `pnpm dev` terminal prints `devframe auth code <code>` and a magic-link URL (`...#devframe_otp=<code>`); enter the code in the dock's prompt, or open the printed URL, to authorize that browser. Until then, the dock stays unauthorized — this is expected, not a connection failure.
|
|
98
|
+
|
|
99
|
+
**Disabling the authorization gate.** Setting `devtools: { clientAuth: false }` (or the `VITE_DEVTOOLS_DISABLE_CLIENT_AUTH=true` env var) skips the one-time-code prompt. Per `@vitejs/devtools`'s own documentation: _"if you disable client authentication, any browsers can connect to the devtools and access to your server and filesystem (including other devices, if you open server `host` option to LAN or WAN)."_ Only disable this in an environment where every request already reaches only a trusted developer (never with `server.host` bound to a LAN/WAN interface), and never in anything resembling a shared or production-adjacent environment.
|
|
100
|
+
|
|
101
|
+
**Production safety.** `storefrontDevtools()` always registers its plugins, with no `import.meta.env.PROD` check on our side — the safety comes from `@vitejs/devtools` itself. The plugin that actually opens the WebSocket RPC server does so from Vite's `configureServer` hook, which Vite only ever calls during `vite dev`/`vite serve`, never during `vite build`. A production build and its runtime output carry no RPC server, no WebSocket endpoint, and none of the injected capture/launcher code reachable from a deployed Storefront Application V3.
|
|
102
|
+
|
|
103
|
+
## How it works
|
|
104
|
+
|
|
105
|
+
The package has two halves, both running in the host page's browser context, connected through a `window` global. There is no iframe between them: the Inertia panel mounts directly into the dock's panel element (a custom-render entry) and reads the capture store off `window`.
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
host page (browser)
|
|
109
|
+
injected client (into the app's client entry) dock custom-render
|
|
110
|
+
DOM-event capture (inertia:*) Vue panel
|
|
111
|
+
-> Correlator -> RequestRecords reads & mounted into the dock DOM
|
|
112
|
+
history-capture (pushState/replaceState) ───────▶ subscribes to the store
|
|
113
|
+
network timing (PerformanceObserver)
|
|
114
|
+
-> DevToolsStore on window
|
|
115
|
+
window.__STOREFRONT_DEVTOOLS_STORE__
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Capture (host page)
|
|
119
|
+
|
|
120
|
+
On load, the injected client builds a `DevToolsStore`, stashes it at `window.__STOREFRONT_DEVTOOLS_STORE__`, and wires three non-invasive sources into it:
|
|
121
|
+
|
|
122
|
+
- **DOM events** — `document.addEventListener` over the Inertia 3.x `inertia:*` events. Each event's detail is safely serialized (depth-limited, functions and abort signals stripped) and fed to the store. No `router.on()` patching.
|
|
123
|
+
- **Network timing** — a `PerformanceObserver` over resource-timing entries, matched to in-flight requests by URL.
|
|
124
|
+
- **Client-side history** — a `history.pushState` / `replaceState` patch that detects client visits (`router.push` / `router.replace`) that bypass the normal Inertia event lifecycle.
|
|
125
|
+
|
|
126
|
+
Every handler is wrapped so the devtools can never crash the host application.
|
|
127
|
+
|
|
128
|
+
### Correlation
|
|
129
|
+
|
|
130
|
+
A correlator groups the raw events into one `RequestRecord` per logical visit, matching events by a visit fingerprint plus an active-visit pointer. It handles deferred prop reloads, prefetch cache hits, POST→redirect flows, 409 asset-version mismatches, and the initial page load. Records are kept in a bounded buffer (200), and a compact summary of the previous session is persisted to `sessionStorage` so requests from before a reload remain visible.
|
|
131
|
+
|
|
132
|
+
### oRPC capture
|
|
133
|
+
|
|
134
|
+
The oRPC panel follows the same shape with its own store on `window.__STOREFRONT_DEVTOOLS_ORPC_STORE__`. Its injected client patches `window.fetch` once on load. Each request whose path starts with `/api` is recorded as one `OrpcCall`: the procedure name (the path after `/api`), the JSON input read from the request body, and on response the JSON output, the status, the duration, and any error. Every other fetch passes through untouched, and the original response or rejection always reaches the app unchanged, so the patch can never break a real request. The store caps the buffer at 200, classifies each failure as validation, server, or network, and persists a previous-session summary like the Inertia store. The wire JSON is captured as-is, not the decoded oRPC values.
|
|
135
|
+
|
|
136
|
+
### Storefront context
|
|
137
|
+
|
|
138
|
+
Unlike the Inertia and oRPC panels, the Storefront context panel has no capture client of its own: it reads the live Inertia page directly from the Inertia panel's store (`window.__STOREFRONT_DEVTOOLS_STORE__`), so it only shows data that store has already captured.
|
|
139
|
+
|
|
140
|
+
### Mounting a panel into the dock
|
|
141
|
+
|
|
142
|
+
Every custom-render panel (Inertia, oRPC, Storefront context) mounts through a shared `mountPanel()` helper, not a naive `dom:panel:mounted` listener. The dock's `@devframes/hub-ui` runtime switches to a panel entry and assigns its DOM element (which internally fires `dom:panel:mounted`) _before_ it `import()`s the panel's renderer module, so a listener registered inside the renderer never sees that event fire. `mountPanel()` checks the panel element synchronously first, falling back to the event listener only if it isn't set yet — the same pattern `@devframes/hub-ui` uses internally for its own iframe entries.
|
|
143
|
+
|
|
144
|
+
## Panels
|
|
145
|
+
|
|
146
|
+
### Inertia.js panel
|
|
147
|
+
|
|
148
|
+
This panel is the reason the package exists. Inertia drives navigation over XHR and swaps page props without a full reload, so the browser network tab shows you raw JSON and nothing about the visit itself. The panel reads the Inertia lifecycle directly and shows you the visit.
|
|
149
|
+
|
|
150
|
+
It opens on the **Requests** tab and has a second **Page** tab. A top bar carries **Pause** and **Clear**.
|
|
151
|
+
|
|
152
|
+
**Requests tab.** The left side lists every visit as it happens: method, URL, visit type, timing, and a badge for any diagnostics. Filter the list by type (full, partial, deferred, prefetch, redirect, client) or type a string into the URL box to narrow it. Deferred reloads nest under the visit that triggered them, so you can see which page kicked off which background load. When the buffer fills past 200 visits a footer tells you how many older ones rolled off. Reload the page and a collapsible **Previous session** block keeps the visits from before the reload, which matters because a full reload normally wipes the list. Use this tab to answer "did that click even fire a visit, and what kind."
|
|
153
|
+
|
|
154
|
+
Select a visit and the right side opens its detail across four tabs:
|
|
155
|
+
|
|
156
|
+
- **Response** — the response props actually captured for that visit, each tagged with how it arrived (full, partial, deferred, merged, prepended, or deep-merged), plus a note for any prop you requested via `only` that the response omitted, and a count of props carried over unchanged from the previous page. A **Show changes since last page** toggle switches to a before/after diff instead, marking added keys, removed keys, and changed values. This is where you confirm a partial or deferred reload returned the prop you asked for, or spot a prop that changed when it should not have.
|
|
157
|
+
- **Headers** — the request and response headers actually sent and received for that visit, as a table. Credential-bearing headers (`authorization`, `cookie`, and similar) are redacted before they are ever stored.
|
|
158
|
+
- **Network** — the Inertia protocol view of the request: asset version, the `only` / `except` partial-reload keys, the `errorBag` name, reset keys, plus resource timing and transfer size when the browser recorded them. Use it to verify a partial reload sent the right `only` set, or to see how long a visit actually took on the wire.
|
|
159
|
+
- **Events** — a lifecycle timeline (`before`, `start`, `success`, `finish`, and the rest) with each step's offset in milliseconds from the first event, color-coded by outcome. Below it, every captured event with its full payload as a collapsible tree. This is where you debug a visit that hung, was canceled, or fired events in an order you did not expect.
|
|
160
|
+
|
|
161
|
+
The detail header also carries **Copy as Markdown**, which copies the visit (header, features, error, and the raw page JSON) to your clipboard for pasting into an issue or an AI chat.
|
|
162
|
+
|
|
163
|
+
Above the tabs, the detail shows an overview (method, URL, type, status, component, duration, and the redirect URL on a 409), the active **feature badges**, and any **diagnostics**.
|
|
164
|
+
|
|
165
|
+
**Feature badges** mark the Inertia features active on a visit: partial reload, deferred props, the merge / deep-merge / prepend strategies, scroll regions, once props, prefetch, cached (a prefetch hit that skipped the network), flash data, remembered state, encrypted history, and clear-history. Click a badge to expand its description and a link to the matching Inertia docs, so you do not need to remember what each one means.
|
|
166
|
+
|
|
167
|
+
**Diagnostics** flag common mistakes on a visit: an asset-version mismatch that forced a 409 reload, a canceled or interrupted visit, a partial-reload prop you requested but the response omitted, validation errors dropped because an `only` option left out `errors`, deferred props that failed to load, and a same-URL history replace. Each links to the relevant docs.
|
|
168
|
+
|
|
169
|
+
**Page tab.** The current page props as a collapsible tree, with the page-level feature badges. Use it to inspect the props your component is rendering right now, separate from any one visit.
|
|
170
|
+
|
|
171
|
+
**Pause** stops capture so a busy page stops flooding the list while you read a visit. Resume picks up new visits from that point. **Clear** empties the list. Your active tab and list filter persist across panel reopens, the URL search does not.
|
|
172
|
+
|
|
173
|
+
### oRPC panel
|
|
174
|
+
|
|
175
|
+
The Storefront Application V3 mutates state through oRPC calls to `/api`: add to basket, toggle wishlist, apply a promotion, run a search. In the browser network tab these all look like identical POSTs to `/api`, with the procedure buried in the request body. This panel reads them as oRPC calls and labels each by its procedure.
|
|
176
|
+
|
|
177
|
+
It opens on the **Calls** tab and has a second **Stats** tab. A top bar carries **Pause** and **Clear**.
|
|
178
|
+
|
|
179
|
+
**Calls tab.** The left side lists every oRPC call as it fires: method, procedure (`basket/add`, `wishlist/remove`, and so on), a status badge colored green for success, amber for a validation error, red for a server or network error, and the duration. Filter the list by domain (the first path segment, `basket`, `wishlist`, `search`) or type a string into the box to match the procedure. A collapsible **Previous session** block keeps the calls from before a reload.
|
|
180
|
+
|
|
181
|
+
Select a call and the right side opens its detail across two tabs:
|
|
182
|
+
|
|
183
|
+
- **Data** — the request input as a collapsible tree, and the success output as a collapsible tree, or, when the call failed, the **Error** with its oRPC code, status, message, and data. A streaming response shows a note instead of a buffered body.
|
|
184
|
+
- **Headers** — the request and response headers actually sent and received for that call, as a table. Credential-bearing headers and sensitive input fields (passwords, tokens, and similar) are redacted before they are ever stored.
|
|
185
|
+
|
|
186
|
+
The overview above the tabs shows the procedure, method, URL, status, duration, and the error kind when the call failed.
|
|
187
|
+
|
|
188
|
+
The detail header carries **Copy as curl**, which copies the call as a runnable `curl` command with the JSON body, for replaying the request in a terminal or pasting into an issue.
|
|
189
|
+
|
|
190
|
+
**Stats tab.** A table of every procedure with its call count, average duration, and last duration. Sort by count to find the chatty procedure a page fires ten times, or by average to find the slow one. Use it to answer "which call is making this page feel slow."
|
|
191
|
+
|
|
192
|
+
**Pause** stops capture while you read a call. **Clear** empties the list.
|
|
193
|
+
|
|
194
|
+
### Storefront context panel
|
|
195
|
+
|
|
196
|
+
A read-only view of the resolved shop, country, locale, and session for the current page, plus the config public fields the SDK exposes to the client. It never renders secrets or the full session token, only what the Inertia page props already contain. Use it to confirm which shop/country/locale the app resolved for a request without hunting through page props by hand.
|
|
197
|
+
|
|
198
|
+
### Resource Center
|
|
199
|
+
|
|
200
|
+
A plain iframe that embeds the Storefront documentation in the dock, so you can look something up without leaving the app or hunting for a tab.
|
|
201
|
+
|
|
202
|
+
### Vue
|
|
203
|
+
|
|
204
|
+
The Vue DevTools component tree and timeline, in a **Vue** dock group alongside the SCAYLE Storefront group. It runs as a standalone iframe app (not a custom-render panel like the others) connected to the host page over a `BroadcastChannel` RPC bridge, so it works without the dock owning an `<iframe>` element the applet controls directly. Replaces a separate `vite-plugin-vue-devtools` install.
|
|
205
|
+
|
|
206
|
+
Click-to-inspect (clicking a rendered element to jump to its component in the tree) is not included: it needs `vite-plugin-vue-inspector` wired into the app's own Vite config, which this package does not add.
|
|
207
|
+
|
|
208
|
+
## Architecture notes
|
|
209
|
+
|
|
210
|
+
Each panel that captures live app state (Inertia, oRPC) separates a framework-agnostic core (plain TypeScript, no Vue) from its Vue panel. The Inertia panel lives in `src/inertia/core` and `src/inertia/panel`. The oRPC panel mirrors it in `src/orpc/core` and `src/orpc/panel`. Both reuse shared panel UI (`TreeView`, the clipboard helper, panel styles) and shared capture-side generics (a `window`-store polling hook, a `sessionStorage` persistence helper) from `src/shared/`. The core handles capture, classification, diffing, diagnostics, and persistence, and the panel renders it. The panel styles are dark-mode only and are injected into the dock's shadow root, so they never leak into the host application.
|
|
211
|
+
|
|
212
|
+
## Upstream stability
|
|
213
|
+
|
|
214
|
+
`@vitejs/devtools`, `@vitejs/devtools-kit`, `@devframes/hub`, and `@devframes/hub-ui` are all pre-1.0 (`0.x`) releases. There is no published semver stability guarantee for 0.x versions of these packages — any minor version can carry a breaking change with no deprecation window, and neither project's changelog consistently flags every breaking change as such. If you upgrade any of them:
|
|
215
|
+
|
|
216
|
+
- Check `@vitejs/devtools`'s peer range against the Vite version this repository pins — `@vitejs/devtools` 0.6.x and 0.7.x have shipped outside `vite`'s own declared peer range for `@vitejs/devtools` at times, so a newer devtools version is not automatically compatible with an older (or even the current) pinned Vite.
|
|
217
|
+
- `@devframes/hub`/`@devframes/hub-ui` resolve as transitive dependencies of `@vitejs/devtools`, so a routine `pnpm update` (or a fresh install after a range widens) can move them independently of any `@vitejs/devtools` version bump you intended.
|
|
218
|
+
- Re-run `pnpm exec vitest run`, `pnpm run build`, `pnpm run verify-packaging`, and a live check of all five panels in the dock after any bump — the unit tests do not exercise the dock's actual runtime, only this package's own capture/classification logic.
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
|
|
222
|
+
MIT
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { t as e } from "./panel-uV5ITqhY.mjs";
|
|
2
|
+
import { Fragment as t, computed as n, createBlock as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, defineComponent as s, normalizeStyle as c, openBlock as l, ref as u, renderList as d, resolveComponent as f, toDisplayString as p, withKeys as m, withModifiers as h } from "vue";
|
|
3
|
+
//#region src/shared/TreeView.vue?vue&type=script&setup=true&lang.ts
|
|
4
|
+
var g = { class: "sf-dt-tree" }, _ = [
|
|
5
|
+
"role",
|
|
6
|
+
"tabindex",
|
|
7
|
+
"aria-expanded"
|
|
8
|
+
], v = { class: "sf-dt-tree-caret" }, y = { class: "sf-dt-tree-key" }, b = { class: "sf-dt-tree-preview" }, x = /*#__PURE__*/ e(/* @__PURE__ */ s({
|
|
9
|
+
name: "TreeView",
|
|
10
|
+
__name: "TreeView",
|
|
11
|
+
props: {
|
|
12
|
+
label: {},
|
|
13
|
+
value: {},
|
|
14
|
+
depth: {}
|
|
15
|
+
},
|
|
16
|
+
setup(e) {
|
|
17
|
+
let s = e, x = n(() => s.depth ?? 0), S = u(!1), C = n(() => Array.isArray(s.value) ? "array" : s.value !== null && typeof s.value == "object" ? "object" : "primitive"), w = n(() => C.value === "array" ? s.value.map((e, t) => [String(t), e]) : C.value === "object" ? Object.entries(s.value) : []), T = n(() => C.value === "array" ? `Array(${s.value.length})` : C.value === "object" ? `{ ${Object.keys(s.value).length} }` : E(s.value));
|
|
18
|
+
function E(e) {
|
|
19
|
+
return typeof e == "string" ? `"${e}"` : String(e);
|
|
20
|
+
}
|
|
21
|
+
return (n, s) => {
|
|
22
|
+
let u = f("TreeView", !0);
|
|
23
|
+
return l(), a("div", g, [o("div", {
|
|
24
|
+
class: "sf-dt-tree-row",
|
|
25
|
+
style: c({ paddingLeft: `${x.value * 16}px` }),
|
|
26
|
+
role: C.value === "primitive" ? void 0 : "button",
|
|
27
|
+
tabindex: C.value === "primitive" ? void 0 : 0,
|
|
28
|
+
"aria-expanded": C.value === "primitive" ? void 0 : S.value,
|
|
29
|
+
onClick: s[0] ||= (e) => C.value !== "primitive" && (S.value = !S.value),
|
|
30
|
+
onKeydown: [s[1] ||= m((e) => C.value !== "primitive" && (S.value = !S.value), ["enter"]), s[2] ||= m(h((e) => C.value !== "primitive" && (S.value = !S.value), ["prevent"]), ["space"])]
|
|
31
|
+
}, [
|
|
32
|
+
o("span", v, p(C.value === "primitive" ? "" : S.value ? "▾" : "▸"), 1),
|
|
33
|
+
o("span", y, p(e.label) + ":", 1),
|
|
34
|
+
o("span", b, p(T.value), 1)
|
|
35
|
+
], 44, _), S.value && C.value !== "primitive" ? (l(!0), a(t, { key: 0 }, d(w.value, ([e, t]) => (l(), r(u, {
|
|
36
|
+
key: e,
|
|
37
|
+
label: e,
|
|
38
|
+
value: t,
|
|
39
|
+
depth: x.value + 1
|
|
40
|
+
}, null, 8, [
|
|
41
|
+
"label",
|
|
42
|
+
"value",
|
|
43
|
+
"depth"
|
|
44
|
+
]))), 128)) : i("", !0)]);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}), [["__scopeId", "data-v-dcfacad6"]]), S = { class: "sf-dt-header-table" }, C = { scope: "row" }, w = /*#__PURE__*/ e(/* @__PURE__ */ s({
|
|
48
|
+
name: "HeaderTable",
|
|
49
|
+
__name: "HeaderTable",
|
|
50
|
+
props: { headers: {} },
|
|
51
|
+
setup(e) {
|
|
52
|
+
return (n, r) => (l(), a("table", S, [o("tbody", null, [(l(!0), a(t, null, d(e.headers, (e, t) => (l(), a("tr", { key: t }, [o("th", C, p(t), 1), o("td", null, p(e), 1)]))), 128))])]));
|
|
53
|
+
}
|
|
54
|
+
}), [["__scopeId", "data-v-d6d30a99"]]);
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/shared/clipboard.ts
|
|
57
|
+
function T(e) {
|
|
58
|
+
typeof navigator < "u" && navigator.clipboard && navigator.clipboard.writeText(e);
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { w as n, x as r, T as t };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
//#region src/inertia/core/features.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
return typeof e == "object" && !!e && Object.keys(e).length > 0;
|
|
4
|
+
}
|
|
5
|
+
function t(t) {
|
|
6
|
+
let n = [], r = null;
|
|
7
|
+
return e(t.deferredProps) ? r = t.deferredProps : e(t.initialDeferredProps) && (r = t.initialDeferredProps), r && n.push({
|
|
8
|
+
type: "deferred",
|
|
9
|
+
label: "DEFERRED",
|
|
10
|
+
details: { groups: r }
|
|
11
|
+
}), t.mergeProps?.length && n.push({
|
|
12
|
+
type: "merge",
|
|
13
|
+
label: "MERGE",
|
|
14
|
+
details: { props: t.mergeProps }
|
|
15
|
+
}), t.prependProps?.length && n.push({
|
|
16
|
+
type: "prepend",
|
|
17
|
+
label: "PREPEND",
|
|
18
|
+
details: { props: t.prependProps }
|
|
19
|
+
}), t.deepMergeProps?.length && n.push({
|
|
20
|
+
type: "deep-merge",
|
|
21
|
+
label: "DEEP MERGE",
|
|
22
|
+
details: { props: t.deepMergeProps }
|
|
23
|
+
}), e(t.scrollProps) && n.push({
|
|
24
|
+
type: "scroll",
|
|
25
|
+
label: "SCROLL",
|
|
26
|
+
details: { props: t.scrollProps }
|
|
27
|
+
}), e(t.onceProps) && n.push({
|
|
28
|
+
type: "once",
|
|
29
|
+
label: "ONCE",
|
|
30
|
+
details: { props: t.onceProps }
|
|
31
|
+
}), t.encryptHistory && n.push({
|
|
32
|
+
type: "encrypted",
|
|
33
|
+
label: "ENCRYPTED"
|
|
34
|
+
}), t.clearHistory && n.push({
|
|
35
|
+
type: "clear-history",
|
|
36
|
+
label: "CLEAR HISTORY"
|
|
37
|
+
}), e(t.flash) && n.push({
|
|
38
|
+
type: "flash",
|
|
39
|
+
label: "FLASH",
|
|
40
|
+
details: { flash: t.flash }
|
|
41
|
+
}), e(t.rememberedState) && n.push({
|
|
42
|
+
type: "remember",
|
|
43
|
+
label: "REMEMBER",
|
|
44
|
+
details: { keys: Object.keys(t.rememberedState) }
|
|
45
|
+
}), n;
|
|
46
|
+
}
|
|
47
|
+
function n(e, n) {
|
|
48
|
+
let r = [];
|
|
49
|
+
return e.type === "partial" && r.push({
|
|
50
|
+
type: "partial",
|
|
51
|
+
label: "PARTIAL"
|
|
52
|
+
}), r.push(...t(n)), e.type === "prefetch" && r.push({
|
|
53
|
+
type: "prefetch",
|
|
54
|
+
label: "PREFETCH"
|
|
55
|
+
}), !e.events.some((e) => e.name === "inertia:start") && e.startedAt > 0 && e.type !== "client" && r.push({
|
|
56
|
+
type: "cached",
|
|
57
|
+
label: "CACHED"
|
|
58
|
+
}), r;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/inertia/core/diff.ts
|
|
62
|
+
function r(e, t) {
|
|
63
|
+
if (!e && !t) return [];
|
|
64
|
+
if (!e) return Object.entries(t).map(([e, t]) => ({
|
|
65
|
+
type: "added",
|
|
66
|
+
key: e,
|
|
67
|
+
newValue: t
|
|
68
|
+
}));
|
|
69
|
+
if (!t) return Object.entries(e).map(([e, t]) => ({
|
|
70
|
+
type: "removed",
|
|
71
|
+
key: e,
|
|
72
|
+
oldValue: t
|
|
73
|
+
}));
|
|
74
|
+
let n = /* @__PURE__ */ new Set([...Object.keys(e), ...Object.keys(t)]), r = [];
|
|
75
|
+
for (let a of n) {
|
|
76
|
+
let n = a in e, o = a in t, s = e[a], c = t[a];
|
|
77
|
+
n ? o ? r.push(i(a, s, c)) : r.push({
|
|
78
|
+
type: "removed",
|
|
79
|
+
key: a,
|
|
80
|
+
oldValue: s
|
|
81
|
+
}) : r.push({
|
|
82
|
+
type: "added",
|
|
83
|
+
key: a,
|
|
84
|
+
newValue: c
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return r.toSorted((e, t) => {
|
|
88
|
+
let n = {
|
|
89
|
+
added: 0,
|
|
90
|
+
removed: 1,
|
|
91
|
+
changed: 2,
|
|
92
|
+
nested: 3,
|
|
93
|
+
unchanged: 4
|
|
94
|
+
}, r = n[e.type] - n[t.type];
|
|
95
|
+
return r === 0 ? e.key.localeCompare(t.key) : r;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function i(e, t, n) {
|
|
99
|
+
if (o(t) && o(n)) {
|
|
100
|
+
let i = r(t, n), a = i.some((e) => e.type !== "unchanged");
|
|
101
|
+
return {
|
|
102
|
+
type: a ? "nested" : "unchanged",
|
|
103
|
+
key: e,
|
|
104
|
+
newValue: n,
|
|
105
|
+
children: a ? i : void 0
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return Array.isArray(t) && Array.isArray(n) ? a(e, t, n) : s(t, n) ? {
|
|
109
|
+
type: "unchanged",
|
|
110
|
+
key: e,
|
|
111
|
+
newValue: n
|
|
112
|
+
} : {
|
|
113
|
+
type: "changed",
|
|
114
|
+
key: e,
|
|
115
|
+
oldValue: t,
|
|
116
|
+
newValue: n
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function a(e, t, n) {
|
|
120
|
+
let r = Math.max(t.length, n.length), a = [];
|
|
121
|
+
for (let e = 0; e < r; e++) {
|
|
122
|
+
let r = `[${e}]`;
|
|
123
|
+
e >= t.length ? a.push({
|
|
124
|
+
type: "added",
|
|
125
|
+
key: r,
|
|
126
|
+
newValue: n[e]
|
|
127
|
+
}) : e >= n.length ? a.push({
|
|
128
|
+
type: "removed",
|
|
129
|
+
key: r,
|
|
130
|
+
oldValue: t[e]
|
|
131
|
+
}) : a.push(i(r, t[e], n[e]));
|
|
132
|
+
}
|
|
133
|
+
return a.every((e) => e.type === "unchanged") ? {
|
|
134
|
+
type: "unchanged",
|
|
135
|
+
key: e,
|
|
136
|
+
newValue: n
|
|
137
|
+
} : {
|
|
138
|
+
type: "nested",
|
|
139
|
+
key: e,
|
|
140
|
+
newValue: n,
|
|
141
|
+
children: a
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function o(e) {
|
|
145
|
+
return typeof e == "object" && !!e && !Array.isArray(e);
|
|
146
|
+
}
|
|
147
|
+
function s(e, t) {
|
|
148
|
+
return c(e, t, /* @__PURE__ */ new WeakSet());
|
|
149
|
+
}
|
|
150
|
+
function c(e, t, n) {
|
|
151
|
+
if (e === t) return !0;
|
|
152
|
+
if (e === null || t === null || typeof e != typeof t) return !1;
|
|
153
|
+
if (typeof e == "object") {
|
|
154
|
+
if (n.has(e) || n.has(t)) return !1;
|
|
155
|
+
n.add(e), n.add(t);
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
if (Array.isArray(e) && Array.isArray(t)) return e.length === t.length && e.every((e, r) => c(e, t[r], n));
|
|
159
|
+
if (o(e) && o(t)) {
|
|
160
|
+
let r = Object.keys(e), i = Object.keys(t);
|
|
161
|
+
return r.length === i.length && r.every((r) => c(e[r], t[r], n));
|
|
162
|
+
}
|
|
163
|
+
return !1;
|
|
164
|
+
} finally {
|
|
165
|
+
typeof e == "object" && (n.delete(e), n.delete(t));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//#endregion
|
|
169
|
+
export { t as i, r as n, n as r, s as t };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createApp as e, onUnmounted as t, shallowRef as n } from "vue";
|
|
2
|
+
//#region \0virtual:css-injected-by-js
|
|
3
|
+
function r(e) {
|
|
4
|
+
if (typeof globalThis < "u") {
|
|
5
|
+
globalThis.__VITE_CSS_INJECT_OPTS__ = e || {};
|
|
6
|
+
for (var t = globalThis.__VITE_CSS_QUEUE__ || [], n = globalThis.__VITE_CSS_EXECUTED__ || [], r = 0; r < n.length; r++) n[r](e || {});
|
|
7
|
+
for (var r = 0; r < t.length; r++) t[r](e || {}), n.push(t[r]);
|
|
8
|
+
globalThis.__VITE_CSS_QUEUE__ = [], globalThis.__VITE_CSS_EXECUTED__ = n;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/shared/mount-panel.ts
|
|
13
|
+
function i(t, n) {
|
|
14
|
+
let i, a;
|
|
15
|
+
function o(t) {
|
|
16
|
+
if (t === a) return;
|
|
17
|
+
i?.unmount();
|
|
18
|
+
let o = t.getRootNode();
|
|
19
|
+
r({ target: o instanceof ShadowRoot ? o : document.head }), i = e(n), i.mount(t), a = t;
|
|
20
|
+
}
|
|
21
|
+
t.current.events.on("dom:panel:mounted", o);
|
|
22
|
+
let s = t.current.domElements.panel;
|
|
23
|
+
s && o(s);
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/shared/use-window-store.ts
|
|
27
|
+
var a = 250;
|
|
28
|
+
function o(e) {
|
|
29
|
+
let r = n(null), i, o;
|
|
30
|
+
function s(e) {
|
|
31
|
+
r.value = e.getState(), i = e.subscribe((e) => {
|
|
32
|
+
r.value = e;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
let c = e();
|
|
36
|
+
return c ? s(c) : o = setInterval(() => {
|
|
37
|
+
let t = e();
|
|
38
|
+
t && (clearInterval(o), o = void 0, s(t));
|
|
39
|
+
}, a), t(() => {
|
|
40
|
+
i?.(), o && clearInterval(o);
|
|
41
|
+
}), r;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region \0plugin-vue:export-helper
|
|
45
|
+
var s = (e, t) => {
|
|
46
|
+
let n = e.__vccOpts || e;
|
|
47
|
+
for (let [e, r] of t) n[e] = r;
|
|
48
|
+
return n;
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { o as n, i as r, s as t };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
function e(e) {
|
|
2
|
+
return {
|
|
3
|
+
save(t) {
|
|
4
|
+
if (typeof sessionStorage < "u") try {
|
|
5
|
+
sessionStorage.setItem(e, JSON.stringify(t));
|
|
6
|
+
} catch {}
|
|
7
|
+
},
|
|
8
|
+
load() {
|
|
9
|
+
if (typeof sessionStorage > "u") return null;
|
|
10
|
+
try {
|
|
11
|
+
let t = sessionStorage.getItem(e);
|
|
12
|
+
if (!t) return null;
|
|
13
|
+
let n = JSON.parse(t);
|
|
14
|
+
return Date.now() - n.savedAt > 3e5 ? (sessionStorage.removeItem(e), null) : n;
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
clear() {
|
|
20
|
+
typeof sessionStorage < "u" && sessionStorage.removeItem(e);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
var t = /* @__PURE__ */ new Set(["cancelToken", "signal"]);
|
|
25
|
+
function n(e) {
|
|
26
|
+
if (e instanceof Date) return e.toISOString();
|
|
27
|
+
if (e instanceof URL || e instanceof RegExp) return e.toString();
|
|
28
|
+
if (e instanceof Error) return {
|
|
29
|
+
message: e.message,
|
|
30
|
+
name: e.name,
|
|
31
|
+
stack: e.stack
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function r(e, n, r, a) {
|
|
35
|
+
if (Array.isArray(e)) return e.map((e) => i(e, a, n - 1, r));
|
|
36
|
+
if (e instanceof Set) return Array.from(e, (e) => i(e, a, n - 1, r));
|
|
37
|
+
if (e instanceof Map) {
|
|
38
|
+
let t = {};
|
|
39
|
+
for (let [o, s] of e) t[String(o)] = i(s, a, n - 1, r);
|
|
40
|
+
return t;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
let o = {};
|
|
44
|
+
for (let [s, c] of Object.entries(e)) typeof c == "function" || t.has(s) || (o[s] = a.redactKey?.(s) ? "[redacted]" : i(c, a, n - 1, r));
|
|
45
|
+
return o;
|
|
46
|
+
} catch {
|
|
47
|
+
return String(e);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function i(e, t = {}, i = 10, a = /* @__PURE__ */ new Set()) {
|
|
51
|
+
if (typeof e != "object" || !e) return e;
|
|
52
|
+
if (i <= 0) return "[too deep]";
|
|
53
|
+
if (a.has(e)) return "[circular]";
|
|
54
|
+
let o = n(e);
|
|
55
|
+
if (o !== void 0) return o;
|
|
56
|
+
a.add(e);
|
|
57
|
+
try {
|
|
58
|
+
return r(e, i, a, t);
|
|
59
|
+
} finally {
|
|
60
|
+
a.delete(e);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function a(e) {
|
|
64
|
+
if (e == null) return {};
|
|
65
|
+
if (typeof e != "object") return { value: e };
|
|
66
|
+
try {
|
|
67
|
+
let t = {};
|
|
68
|
+
for (let [n, r] of Object.entries(e)) t[n] = i(r);
|
|
69
|
+
return t;
|
|
70
|
+
} catch {
|
|
71
|
+
return {};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/shared/redact.ts
|
|
76
|
+
var o = /password|passphrase|secret|token|credential|authorization|apikey|api_key/i, s = { "auth.exchangeAuthCode": /* @__PURE__ */ new Set(["code"]) }, c = /* @__PURE__ */ new Set([
|
|
77
|
+
"authorization",
|
|
78
|
+
"cookie",
|
|
79
|
+
"proxy-authorization",
|
|
80
|
+
"x-api-key",
|
|
81
|
+
"x-auth-token"
|
|
82
|
+
]);
|
|
83
|
+
function l(e) {
|
|
84
|
+
return o.test(e);
|
|
85
|
+
}
|
|
86
|
+
function u(e) {
|
|
87
|
+
let t = s[e];
|
|
88
|
+
return (e) => l(e) || (t?.has(e) ?? !1);
|
|
89
|
+
}
|
|
90
|
+
function d(e) {
|
|
91
|
+
let t = {};
|
|
92
|
+
for (let [n, r] of Object.entries(e)) c.has(n) || l(n) || (t[n] = r);
|
|
93
|
+
return t;
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
export { a, i, l as n, e as o, d as r, u as t };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { n as e } from "./panel-uV5ITqhY.mjs";
|
|
2
|
+
//#region src/inertia/panel/useStore.ts
|
|
3
|
+
function t() {
|
|
4
|
+
return e(() => window.__STOREFRONT_DEVTOOLS_STORE__);
|
|
5
|
+
}
|
|
6
|
+
function n() {
|
|
7
|
+
return window.__STOREFRONT_DEVTOOLS_STORE__;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { t as n, n as t };
|