@buoy-gg/vue 0.0.0-stage → 7.0.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +58 -0
- package/README.md +101 -2
- package/lib/disabled/highlights.d.ts +7 -0
- package/lib/disabled/highlights.mjs +1 -0
- package/lib/disabled/index.d.ts +10 -0
- package/lib/disabled/index.mjs +1 -0
- package/lib/disabled/pinia.d.ts +5 -0
- package/lib/disabled/pinia.mjs +1 -0
- package/lib/disabled/register.d.ts +4 -0
- package/lib/disabled/register.mjs +1 -0
- package/lib/disabled/router.d.ts +4 -0
- package/lib/disabled/router.mjs +1 -0
- package/lib/highlights.d.ts +87 -0
- package/lib/highlights.mjs +1 -0
- package/lib/index.d.ts +81 -0
- package/lib/index.mjs +1 -0
- package/lib/nuxt-plugin.mjs +1 -0
- package/lib/nuxt.d.ts +44 -0
- package/lib/nuxt.mjs +3 -0
- package/lib/pinia.d.ts +45 -0
- package/lib/pinia.mjs +1 -0
- package/lib/register.d.ts +2 -0
- package/lib/register.mjs +1 -0
- package/lib/router.d.ts +41 -0
- package/lib/router.mjs +1 -0
- package/package.json +96 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
PROPRIETARY SOFTWARE LICENSE
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present Buoy. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and its source code are proprietary and confidential.
|
|
6
|
+
|
|
7
|
+
NOTICE: This is NOT open source software. This software is licensed,
|
|
8
|
+
not sold, and is protected by copyright laws and international treaties.
|
|
9
|
+
|
|
10
|
+
TERMS AND CONDITIONS:
|
|
11
|
+
|
|
12
|
+
1. LICENSE GRANT
|
|
13
|
+
Subject to the terms of this Agreement and payment of applicable fees,
|
|
14
|
+
Buoy grants you a limited, non-exclusive, non-transferable license
|
|
15
|
+
to use the compiled software packages in your applications.
|
|
16
|
+
|
|
17
|
+
2. RESTRICTIONS
|
|
18
|
+
You may NOT:
|
|
19
|
+
- Copy, modify, or distribute the source code
|
|
20
|
+
- Reverse engineer, decompile, or disassemble the software
|
|
21
|
+
- Remove or alter any proprietary notices or labels
|
|
22
|
+
- Sublicense, rent, lease, or lend the software
|
|
23
|
+
- Use the software to create competing products
|
|
24
|
+
- Share access credentials with unauthorized parties
|
|
25
|
+
|
|
26
|
+
3. OWNERSHIP
|
|
27
|
+
React Buoy retains all right, title, and interest in the software,
|
|
28
|
+
including all intellectual property rights. This license does not
|
|
29
|
+
grant you any rights to trademarks or service marks.
|
|
30
|
+
|
|
31
|
+
4. TERMINATION
|
|
32
|
+
This license is effective until terminated. Your rights under this
|
|
33
|
+
license will terminate automatically without notice if you fail to
|
|
34
|
+
comply with any of its terms. Upon termination, you must cease all
|
|
35
|
+
use and destroy all copies of the software.
|
|
36
|
+
|
|
37
|
+
5. DISCLAIMER OF WARRANTIES
|
|
38
|
+
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
|
39
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
40
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
|
|
41
|
+
|
|
42
|
+
6. LIMITATION OF LIABILITY
|
|
43
|
+
IN NO EVENT SHALL BUOY BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
|
|
44
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN
|
|
45
|
+
CONNECTION WITH THIS LICENSE OR THE USE OF THE SOFTWARE.
|
|
46
|
+
|
|
47
|
+
7. GOVERNING LAW
|
|
48
|
+
This Agreement shall be governed by and construed in accordance with
|
|
49
|
+
the laws of the United States, without regard to its conflict of
|
|
50
|
+
law provisions.
|
|
51
|
+
|
|
52
|
+
For licensing inquiries and subscription information:
|
|
53
|
+
- Website: https://buoy.gg
|
|
54
|
+
- Email: AustinLovesWorking@gmail.com
|
|
55
|
+
|
|
56
|
+
Unauthorized reproduction or distribution of this software, or any
|
|
57
|
+
portion of it, may result in severe civil and criminal penalties,
|
|
58
|
+
and will be prosecuted to the maximum extent possible under the law.
|
package/README.md
CHANGED
|
@@ -1,3 +1,102 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Buoy for Vue and Nuxt
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Buoy runs in Vue 3.3 and up, built with Vite, as a beta.
|
|
4
|
+
It runs in Nuxt 4 too.
|
|
5
|
+
Your app stays all Vue.
|
|
6
|
+
Buoy uses React for its own screens and brings it along.
|
|
7
|
+
The full guide is the [Vue page](https://buoy.gg/buoy/latest/docs/web/vue).
|
|
8
|
+
|
|
9
|
+
## Install and sign in
|
|
10
|
+
|
|
11
|
+
Run these from your app folder:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install --save-dev @buoy-gg/core @buoy-gg/vue @buoy-gg/network
|
|
15
|
+
npx --package=@buoy-gg/core buoy login
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Add more tools the same way.
|
|
19
|
+
Use the same version for all Buoy packages.
|
|
20
|
+
`buoy login` writes `VITE_BUOY_KEY` to a file Git ignores.
|
|
21
|
+
|
|
22
|
+
## Set up in Vue
|
|
23
|
+
|
|
24
|
+
Add the Vite plugin:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// vite.config.ts
|
|
28
|
+
import vue from '@vitejs/plugin-vue';
|
|
29
|
+
import { buoy } from '@buoy-gg/core/vite';
|
|
30
|
+
|
|
31
|
+
export default defineConfig({ plugins: [vue(), buoy()] });
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Add the Buoy plugin to your app:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { buoy } from '@buoy-gg/vue';
|
|
38
|
+
|
|
39
|
+
createApp(App).use(router).use(pinia).use(buoy).mount('#app');
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That's all.
|
|
43
|
+
The Vite plugin finds your tools and adds the early hook.
|
|
44
|
+
It leaves Buoy out of prod builds.
|
|
45
|
+
`app.use(buoy)` reads your key and starts Buoy when your app mounts.
|
|
46
|
+
It finds Vue Router, Pinia and Vue Query by itself.
|
|
47
|
+
It stops Buoy when your app unmounts.
|
|
48
|
+
|
|
49
|
+
## Set up in Nuxt
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// nuxt.config.ts
|
|
53
|
+
export default defineNuxtConfig({ modules: ['@buoy-gg/vue/nuxt'] });
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That's all.
|
|
57
|
+
Pass options with the `buoy` key, as plain data.
|
|
58
|
+
For options with functions, set `buoy: { setup: false }`.
|
|
59
|
+
Then call `nuxtApp.vueApp.use(buoy, options)` in your own client plugin.
|
|
60
|
+
|
|
61
|
+
## Options
|
|
62
|
+
|
|
63
|
+
`app.use(buoy, options)` takes the same options as `mountBuoy` from `@buoy-gg/core/web`, plus these:
|
|
64
|
+
|
|
65
|
+
| Option | What it does |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `load` | Loads app settings with Buoy. Use a dev check so prod drops the file |
|
|
68
|
+
| `modules` | Your own tool list, in place of the plugin's |
|
|
69
|
+
| `enableInRelease` | Starts Buoy in a release build too. Set `buoy({ enableInRelease: true })` as well |
|
|
70
|
+
| `onMount` | Called with the stop function once Buoy is up |
|
|
71
|
+
| `onDestroy` | Called when Buoy stops |
|
|
72
|
+
|
|
73
|
+
`startBuoy(options)` starts Buoy with no Vue app.
|
|
74
|
+
Pass `router`, `pinia` and `queryClient` yourself.
|
|
75
|
+
|
|
76
|
+
## Pinia and refs
|
|
77
|
+
|
|
78
|
+
Pinia stores show in the Zustand tool by themselves.
|
|
79
|
+
To show a plain `ref` or `reactive`, wrap it:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { buoyVueRef } from '@buoy-gg/vue/pinia';
|
|
83
|
+
|
|
84
|
+
app.use(buoy, { zustandStores: { count: buoyVueRef(count) } });
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
You can read and edit them in the tool.
|
|
88
|
+
An edit keeps the fields you did not change.
|
|
89
|
+
|
|
90
|
+
## Entry points
|
|
91
|
+
|
|
92
|
+
| Import | Holds |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `@buoy-gg/vue` | `buoy`, `startBuoy` |
|
|
95
|
+
| `@buoy-gg/vue/register` | The early hook. The Vite plugin adds it for you |
|
|
96
|
+
| `@buoy-gg/vue/router` | `connectBuoyRouter`, for a router link by hand |
|
|
97
|
+
| `@buoy-gg/vue/pinia` | `watchPiniaStores`, `buoyVueRef` |
|
|
98
|
+
| `@buoy-gg/vue/highlights` | `connectBuoyHighlights`, for Highlight by hand |
|
|
99
|
+
| `@buoy-gg/vue/nuxt` | The Nuxt module |
|
|
100
|
+
|
|
101
|
+
Each app entry has a `buoy-disabled` build that does nothing.
|
|
102
|
+
The Vite plugin picks it for prod builds.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BuoyHighlightController, VueInstance } from '../highlights';
|
|
2
|
+
export declare function componentName(_instance: VueInstance): string;
|
|
3
|
+
export declare function hostElements(_instance: VueInstance): HTMLElement[];
|
|
4
|
+
export declare function connectBuoyHighlights(_controller: BuoyHighlightController): () => void;
|
|
5
|
+
export declare function elementComponentName(_element: Element): string | undefined;
|
|
6
|
+
export declare function elementComponentSource(_element: Element): undefined;
|
|
7
|
+
export declare function onVueRender(_listener?: (instance: VueInstance) => void): () => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(n){return"Anonymous"}function o(n){return[]}function t(n){return()=>{}}function u(n){}function r(n){}function c(n){return()=>{}}export{e as componentName,t as connectBuoyHighlights,u as elementComponentName,r as elementComponentSource,o as hostElements,c as onVueRender};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BuoyOptions, BuoyVueApp } from '../index';
|
|
2
|
+
/** The buoy-disabled build condition keeps no loader and no tools. */
|
|
3
|
+
export declare const buoy: {
|
|
4
|
+
install(_app: BuoyVueApp, _options?: BuoyOptions): void;
|
|
5
|
+
};
|
|
6
|
+
export default buoy;
|
|
7
|
+
export declare function startBuoy(_options?: BuoyOptions): () => void;
|
|
8
|
+
export declare function isBuoyDevBuild(): boolean;
|
|
9
|
+
export declare function findQueryClient(_app: BuoyVueApp): unknown;
|
|
10
|
+
export declare function appLinks(_app: BuoyVueApp): Pick<BuoyOptions, 'router' | 'pinia' | 'queryClient'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var t={install(n,e={}){}},u=t;function a(n={}){return()=>{}}function s(){return false}function i(n){}function r(n){return{}}export{r as appLinks,t as buoy,u as default,i as findQueryClient,s as isBuoyDevBuild,a as startBuoy};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BuoyPinia, BuoyPiniaStore, BuoyStoreApi } from '../pinia';
|
|
2
|
+
export declare function plainCopy<T>(value: T): T;
|
|
3
|
+
export declare function piniaStoreApi(_store: BuoyPiniaStore): BuoyStoreApi<Record<string, unknown>>;
|
|
4
|
+
export declare function watchPiniaStores(_pinia: BuoyPinia, _zustand: unknown): () => void;
|
|
5
|
+
export declare function buoyVueRef<T extends object>(_source: T): BuoyStoreApi<unknown>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e={getState:()=>({}),getInitialState:()=>({}),setState:()=>{},subscribe:()=>()=>{}};function n(t){return t}function a(t){return e}function i(t,u){return()=>{}}function r(t){return e}export{r as buoyVueRef,a as piniaStoreApi,n as plainCopy,i as watchPiniaStores};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function r(e={}){return false}export{r as registerBrowserNetwork};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BuoyVueRouter } from '../router';
|
|
2
|
+
export declare function vueRouteTemplate(pattern: string): string;
|
|
3
|
+
export declare function vueRoutePaths(_router: Pick<BuoyVueRouter, 'getRoutes'>): string[];
|
|
4
|
+
export declare function connectBuoyRouter(_router: BuoyVueRouter): () => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(t){return t}function u(t){return[]}function n(t){return()=>{}}export{n as connectBuoyRouter,u as vueRoutePaths,e as vueRouteTemplate};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** The parts of a Vue 3 component instance Highlight reads. All are Vue's own and may be missing. */
|
|
2
|
+
export interface VueInstance {
|
|
3
|
+
uid?: number;
|
|
4
|
+
type?: {
|
|
5
|
+
name?: string;
|
|
6
|
+
__name?: string;
|
|
7
|
+
__file?: string;
|
|
8
|
+
};
|
|
9
|
+
subTree?: VueVNode | null;
|
|
10
|
+
parent?: VueInstance | null;
|
|
11
|
+
isMounted?: boolean;
|
|
12
|
+
isUnmounted?: boolean;
|
|
13
|
+
isDeactivated?: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface VueVNode {
|
|
16
|
+
el?: Node | null;
|
|
17
|
+
anchor?: Node | null;
|
|
18
|
+
type?: unknown;
|
|
19
|
+
children?: unknown;
|
|
20
|
+
component?: VueInstance | null;
|
|
21
|
+
target?: Element | null;
|
|
22
|
+
}
|
|
23
|
+
export interface VueRenderBatch {
|
|
24
|
+
host: HTMLElement;
|
|
25
|
+
name: string;
|
|
26
|
+
count: number;
|
|
27
|
+
}
|
|
28
|
+
export interface BuoyHighlightController {
|
|
29
|
+
isEnabled(): boolean;
|
|
30
|
+
subscribe(listener: (enabled: boolean) => void): () => void;
|
|
31
|
+
connectRenderSource(available: boolean): {
|
|
32
|
+
recordRenders(renders: VueRenderBatch[]): void;
|
|
33
|
+
disconnect(): void;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** A component's display name: its `name`, the SFC name Vue sets in dev, or its file name. */
|
|
37
|
+
export declare function componentName(instance: VueInstance): string;
|
|
38
|
+
/**
|
|
39
|
+
* The elements a component put on the page, for its boxes. Elements only, and
|
|
40
|
+
* only ones still on the page. A fragment gives every element between its
|
|
41
|
+
* start and end markers. A Teleport gives what it moved to its target. A
|
|
42
|
+
* component whose root is another component gives that one's elements.
|
|
43
|
+
*/
|
|
44
|
+
export declare function hostElements(instance: VueInstance, depth?: number): HTMLElement[];
|
|
45
|
+
/**
|
|
46
|
+
* Hear each real component render. Vue also sends "updated" when a slot
|
|
47
|
+
* runs, naming the component that wrote the slot even though it didn't
|
|
48
|
+
* render. A real render gives the component a new `subTree`, so an event that
|
|
49
|
+
* leaves it the same is skipped, as are events during a first mount. Each
|
|
50
|
+
* component's tree is noted from the first call on; the early hook calls
|
|
51
|
+
* this at once, so components made before Highlight turns on are known too.
|
|
52
|
+
*/
|
|
53
|
+
export declare function onVueRender(listener?: (instance: VueInstance) => void): () => void;
|
|
54
|
+
/**
|
|
55
|
+
* Feed Vue updates to Highlight Updates. Vue tells its dev hook about each
|
|
56
|
+
* component it updated; Buoy counts those while Highlight is on, and finds
|
|
57
|
+
* the names and boxes in the next animation frame, after Vue has finished.
|
|
58
|
+
* Only real renders count (see onVueRender).
|
|
59
|
+
*/
|
|
60
|
+
export declare function connectBuoyHighlights(controller: BuoyHighlightController): () => void;
|
|
61
|
+
/**
|
|
62
|
+
* The app component an element belongs to, for Buoy's screen tools
|
|
63
|
+
* (describeScreen, hitTest). In dev, Vue marks each element with the
|
|
64
|
+
* component that rendered it.
|
|
65
|
+
*/
|
|
66
|
+
/**
|
|
67
|
+
* The component behind a page element and the components around it, with the
|
|
68
|
+
* file each one lives in. Vue sets `__file` on SFCs in dev builds. Same shape
|
|
69
|
+
* as Buoy's React component source; Vue has no line numbers to give.
|
|
70
|
+
*/
|
|
71
|
+
/** One component in the chain, in the shape Buoy's component source tool returns. */
|
|
72
|
+
export interface VueComponentSourceEntry {
|
|
73
|
+
name: string;
|
|
74
|
+
source?: {
|
|
75
|
+
fileName: string;
|
|
76
|
+
};
|
|
77
|
+
memo: false;
|
|
78
|
+
forwardRef: false;
|
|
79
|
+
reason?: string;
|
|
80
|
+
}
|
|
81
|
+
export declare function elementComponentSource(element: Element): {
|
|
82
|
+
found: true;
|
|
83
|
+
component: VueComponentSourceEntry;
|
|
84
|
+
owners: VueComponentSourceEntry[];
|
|
85
|
+
} | undefined;
|
|
86
|
+
export declare function elementComponentName(element: Element): string | undefined;
|
|
87
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var H=Symbol.for("buoy.vue.hook"),M=2500;function _(){let e=globalThis;return e[H]??={listeners:new Set,wrappers:new WeakMap,armed:false}}function g(e,t){for(let n of _().listeners)try{n(e,t)}catch(r){console.error("[Buoy]",r)}}function u(e){let{wrappers:t}=_(),n=t.get(e);if(n&&e.emit===n)return true;let r=e.emit,o=function(l,...i){return g(l,i),r?.apply(this??e,[l,...i])};try{Object.defineProperty(e,"emit",{configurable:true,enumerable:true,get:()=>o,set:l=>{l!==o&&(r=l)}})}catch{let l=e.on;if(typeof l!="function")return false;for(let i of["component:added","component:updated","component:removed","perf:start","perf:end","app:init","app:unmount"])l.call(e,i,(...s)=>g(i,s))}return t.set(e,o),true}function b(){let e=new Map;return{enabled:false,apps:[],events:e,on(t,n){return e.has(t)||e.set(t,[]),e.get(t).push(n),()=>this.off(t,n)},once(t,n){let r=(...o)=>{this.off(t,r),n(...o)};this.on(t,r)},off(t,n){let r=e.get(t),o=r?.indexOf(n)??-1;r&&o!==-1&&r.splice(o,1)},emit(t,...n){for(let r of[...e.get(t)??[]])r(...n)}}}function B(){return typeof window>"u"||!window.HTMLElement?false:!window.navigator?.userAgent?.includes("jsdom")}function D(){let e=globalThis,t=_(),n=e.__VUE_DEVTOOLS_GLOBAL_HOOK__;if(n){u(n),t.armed=true;return}if(t.armed)return;if(t.armed=true,!B()){let r=b();u(r),e.__VUE_DEVTOOLS_GLOBAL_HOOK__=r;return}(e.__VUE_DEVTOOLS_HOOK_REPLAY__||=[]).push(r=>{u(r)}),setTimeout(()=>{if(e.__VUE_DEVTOOLS_GLOBAL_HOOK__){u(e.__VUE_DEVTOOLS_GLOBAL_HOOK__);return}let r=b();u(r),e.__VUE_DEVTOOLS_GLOBAL_HOOK__=r;let o=e.__VUE_DEVTOOLS_HOOK_REPLAY__??[];e.__VUE_DEVTOOLS_HOOK_REPLAY__=[];for(let l of o)try{l(r)}catch(i){console.error("[Buoy]",i)}},M)}function K(e){D();let{listeners:t}=_();return t.add(e),()=>{t.delete(e)}}var m=new Set(["BaseTransition","Transition","TransitionGroup","KeepAlive","Suspense","Teleport"]);function f(e){let t=e.type??{};return t.name?t.name:t.__name?t.__name:t.__file?.split(/[\\/]/).pop()?.replace(/\.\w+$/,"")||"Anonymous"}var O=e=>typeof HTMLElement<"u"&&e instanceof HTMLElement&&e.isConnected;function U(e){return!!(e&&typeof e=="object"&&e.__isTeleport)}function h(e,t=0){let n=e.subTree;return!n||t>20?[]:w(n,t)}function w(e,t){if(e.component)return h(e.component,t+1);if(U(e.type))return(Array.isArray(e.children)?e.children:[]).flatMap(o=>w(o,t+1));let n=e.el;if(!n)return[];if(e.anchor&&e.anchor!==n){let o=[];for(let l=n;l&&o.length<20&&(O(l)&&o.push(l),l!==e.anchor);l=l.nextSibling);return o}if(O(n))return[n];let r=n.parentElement;return n.nodeType===3&&O(r)?[r]:[]}var y=new WeakMap,R=Symbol.for("buoy.vue.renders");function G(){let e=globalThis;return e[R]??={trees:new WeakMap,listeners:new Set,installed:false}}function v(e){let t=G();return t.installed||(t.installed=true,K((n,r)=>{if(n!=="component:added"&&n!=="component:updated")return;let o=r[3];if(!o||typeof o!="object"||r[0]?._instance?.type?.devtools?.hide)return;let l=o.subTree,i=t.trees.has(o),s=t.trees.get(o)!==l;if(t.trees.set(o,l),!(n==="component:added"||!o.isMounted||i&&!s))for(let c of t.listeners)c(o)})),e?(t.listeners.add(e),()=>{t.listeners.delete(e)}):()=>{}}function P(e){let t=y.get(e);if(!t){let o=e.connectRenderSource(true),l=new Map,i,s=e.isEnabled(),c=false,S=()=>{if(i=void 0,c||!s){l.clear();return}let a=new Map;for(let[p,E]of l){if(p.isUnmounted||p.isDeactivated)continue;let L=f(p);if(!m.has(L))for(let d of h(p)){let T=a.get(d);T?T.count+=E:a.set(d,{host:d,name:L,count:E})}}l.clear(),a.size&&o.recordRenders([...a.values()])},V=v(a=>{s&&(l.set(a,(l.get(a)??0)+1),i??=requestAnimationFrame(S))}),A=e.subscribe(a=>{s=a,a||l.clear()});t={users:0,stop:()=>{c=true,V(),A(),i!==void 0&&cancelAnimationFrame(i),l.clear(),o.disconnect()}},y.set(e,t)}t.users++;let n=false,r=t;return()=>{n||(n=true,--r.users===0&&(r.stop(),y.delete(e)))}}function C(e){let t;for(let r=e;r&&!t;r=r.parentElement)t=r.__vueParentComponent;let n=[];for(let r=0;t&&r<200&&n.length<7;r++,t=t.parent??void 0){let o=f(t);if(m.has(o)||!t.parent&&!t.type?.__file)continue;let l=t.type?.__file;n.push({name:o,...l?{source:{fileName:l}}:{reason:"It comes from a library, so it has no file in the app."},memo:false,forwardRef:false})}if(n.length)return{found:true,component:n[0],owners:n.slice(1)}}function k(e){for(let t=e;t;t=t.parentElement){let n=t.__vueParentComponent;for(;n&&m.has(f(n));)n=n.parent??void 0;if(n)return f(n)}}export{f as componentName,P as connectBuoyHighlights,k as elementComponentName,C as elementComponentSource,h as hostElements,v as onVueRender};
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** A tool's browser module, as its `/web` entry exports it. */
|
|
2
|
+
type Modules = Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* Buoy's props, kept here so a Vue app's TypeScript never loads the React
|
|
5
|
+
* types behind @buoy-gg/core. The common ones are named; the rest of
|
|
6
|
+
* `FloatingDevTools`' props pass through as they are.
|
|
7
|
+
*/
|
|
8
|
+
export interface BuoyMountOptions {
|
|
9
|
+
environment?: 'local' | 'dev' | 'qa' | 'staging' | 'prod';
|
|
10
|
+
userRole?: 'admin' | 'internal' | 'user';
|
|
11
|
+
/** Defaults to VITE_BUOY_KEY, which `buoy login` writes. */
|
|
12
|
+
licenseKey?: string;
|
|
13
|
+
/** The app's TanStack Query client. Found from VueQueryPlugin when left out. */
|
|
14
|
+
queryClient?: unknown;
|
|
15
|
+
/** Stores for the Zustand tool: vanilla Zustand stores, or buoyVueRef() wrappers. */
|
|
16
|
+
zustandStores?: Record<string, unknown>;
|
|
17
|
+
/** Custom tools made with createWebTool. */
|
|
18
|
+
apps?: unknown[];
|
|
19
|
+
requiredEnvVars?: unknown[];
|
|
20
|
+
requiredStorageKeys?: unknown[];
|
|
21
|
+
externalSync?: boolean | {
|
|
22
|
+
socketURL?: string;
|
|
23
|
+
deviceName?: string;
|
|
24
|
+
enableInRelease?: boolean;
|
|
25
|
+
};
|
|
26
|
+
sentryGetClient?: () => unknown;
|
|
27
|
+
[prop: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
export interface BuoyOptions extends BuoyMountOptions {
|
|
30
|
+
/** Start in a release build as well. App access rules still apply. */
|
|
31
|
+
enableInRelease?: boolean;
|
|
32
|
+
/** The tools to load. Defaults to every tool the buoy() Vite plugin found. */
|
|
33
|
+
modules?: Modules | (() => Promise<Modules>);
|
|
34
|
+
/** The app's Vue Router. Found on the app when Buoy is installed with app.use(). */
|
|
35
|
+
router?: unknown;
|
|
36
|
+
/** The app's Pinia. Found on the app when Buoy is installed with app.use(). */
|
|
37
|
+
pinia?: unknown;
|
|
38
|
+
/**
|
|
39
|
+
* Load app settings and links with Buoy, such as `apps` or `zustandStores`.
|
|
40
|
+
* Use a dev-only dynamic import here so a production build leaves them out.
|
|
41
|
+
*/
|
|
42
|
+
load?: () => Promise<Omit<BuoyOptions, 'load' | 'enableInRelease'>>;
|
|
43
|
+
/** Called once Buoy is mounted. The stop function is safe to call twice. */
|
|
44
|
+
onMount?: (stop: () => void) => void;
|
|
45
|
+
/** Called when Buoy stops, to remove app hooks the loader added. */
|
|
46
|
+
onDestroy?: () => void;
|
|
47
|
+
}
|
|
48
|
+
/** Whether Buoy starts by default: the phone app's debug flag in a Capacitor shell, otherwise a dev build. */
|
|
49
|
+
export declare function isBuoyDevBuild(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Mount Buoy with no Vue app. Pass `queryClient`, `router` and `pinia`
|
|
52
|
+
* yourself. Returns a stop function that is safe to call before Buoy has
|
|
53
|
+
* finished loading.
|
|
54
|
+
*/
|
|
55
|
+
export declare function startBuoy(options?: BuoyOptions): () => void;
|
|
56
|
+
/** The parts of a Vue 3 app Buoy reads. `_context` and `_container` are Vue's own. */
|
|
57
|
+
export interface BuoyVueApp {
|
|
58
|
+
mount(...args: unknown[]): unknown;
|
|
59
|
+
unmount(...args: unknown[]): unknown;
|
|
60
|
+
onUnmount?: (fn: () => void) => void;
|
|
61
|
+
config: {
|
|
62
|
+
globalProperties: Record<string, unknown>;
|
|
63
|
+
};
|
|
64
|
+
_context?: {
|
|
65
|
+
provides?: Record<string | symbol, unknown>;
|
|
66
|
+
};
|
|
67
|
+
_container?: unknown;
|
|
68
|
+
}
|
|
69
|
+
/** The Query client the app provided: VueQueryPlugin puts it in provides, under a key the app may change. */
|
|
70
|
+
export declare function findQueryClient(app: BuoyVueApp): unknown;
|
|
71
|
+
/** The router, Pinia and Query client the app installed. Read after mount, so plugin order doesn't matter. */
|
|
72
|
+
export declare function appLinks(app: BuoyVueApp): Pick<BuoyOptions, 'router' | 'pinia' | 'queryClient'>;
|
|
73
|
+
/**
|
|
74
|
+
* Buoy for a Vue app: `createApp(App).use(buoy).mount('#app')`. It finds the
|
|
75
|
+
* app's router, Pinia and Vue Query client when the app mounts, so it can go
|
|
76
|
+
* anywhere in the `use` chain. It renders nothing in the app.
|
|
77
|
+
*/
|
|
78
|
+
export declare const buoy: {
|
|
79
|
+
install(app: BuoyVueApp, options?: BuoyOptions): void;
|
|
80
|
+
};
|
|
81
|
+
export default buoy;
|
package/lib/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function N(){try{return import.meta.env.VITE_BUOY_KEY||void 0}catch{return}}function B(){if(typeof window>"u")return false;let e=window.Capacitor,t=false;try{t=e?.isNativePlatform?.()===true}catch{t=false}return t?e?.DEBUG===true:typeof __DEV__<"u"?!!__DEV__:process.env.NODE_ENV!=="production"}function O(e={}){if(typeof window>"u"||typeof document>"u")return()=>{};let{enableInRelease:t,modules:o,router:n,pinia:c,onMount:p,onDestroy:r,load:l,...h}=e;if(!B()&&!t)return()=>{};let g=globalThis;g.__BUOY_FRAMEWORK__!=="nuxt"&&(g.__BUOY_FRAMEWORK__="vue");let i=false,_,s=[];r&&s.push(r);let v=()=>{for(let u of s.splice(0).reverse())try{u()}catch(a){console.error("[Buoy]",a)}},E=async u=>{let a=await u();typeof a=="function"&&(i?a():s.push(a))};(async()=>{let u=l?await l():{},{modules:a,onDestroy:w,onMount:k,router:S,pinia:Y,...$}=u;if(w){if(i){w();return}s.push(w)}if(i)return;let y={...h,...$},m=a??o,f=typeof m=="function"?await m():m??(await import("@buoy-gg/core/web/installed-tools")).installedTools;if(i)return;let R=f["highlight-updates"]?.HighlightUpdatesController;if(R){let{connectBuoyHighlights:x}=await import("@buoy-gg/vue/highlights");if(i)return;try{s.push(x(R))}catch(I){console.warn("[Buoy] Highlight Updates already has a render source, so Vue updates are not shown.",I)}}let d={router:S??n,pinia:Y??c};if(d.router&&f["route-events"]&&(await E(async()=>(await import("@buoy-gg/vue/router")).connectBuoyRouter(d.router)),i))return;let U={...y.zustandStores??{}};if(d.pinia&&f.zustand&&(await E(async()=>(await import("@buoy-gg/vue/pinia")).watchPiniaStores(d.pinia,f.zustand)),i))return;let{mountBuoy:q}=await import("@buoy-gg/core/web");if(i)return;let C=y.queryClient,D=y.licenseKey??N();_=q({...y,modules:f,...Object.keys(U).length?{zustandStores:U}:{},...C?{queryClient:C}:{},...D?{licenseKey:D}:{}}),p?.(b)})().catch(u=>{v(),console.error("[Buoy] Buoy did not start.",u)});function b(){if(i)return;i=true;let u=_;_=void 0,u?.(),v()}return b}function K(e){let t=e._context?.provides;if(t)for(let o of Reflect.ownKeys(t)){let n=t[o];if(n&&typeof n.getQueryCache=="function")return n}}function V(e){let t=e.config.globalProperties,o={};t.$router&&(o.router=t.$router),t.$pinia&&(o.pinia=t.$pinia);let n=K(e);return n&&(o.queryClient=n),o}var z=Symbol.for("buoy.vue.installed"),M={install(e,t={}){if(typeof window>"u"||!B()&&!t.enableInRelease)return;let o=e;if(o[z])return;o[z]=true;let n,c=()=>{if(n)return;let r=V(e);n=O({...r,...t})},p=()=>{let r=n;n=void 0,r?.()};if(e._container)c();else{let r=e.mount;e.mount=function(...l){let h=r.apply(this??e,l);return c(),h}}if(typeof e.onUnmount=="function")e.onUnmount(p);else{let r=e.unmount;e.unmount=function(...l){return p(),r.apply(this??e,l)}}}},P=M;export{V as appLinks,M as buoy,P as default,K as findQueryClient,B as isBuoyDevBuild,O as startBuoy};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{defineNuxtPlugin as o,useRuntimeConfig as i}from"#app";import{buoy as p}from"@buoy-gg/vue";var s=o(e=>{let u=i().public.buoy??{};e.vueApp.use(p,{...u})});export{s as default};
|
package/lib/nuxt.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Options for `modules: [['@buoy-gg/vue/nuxt', { ... }]]` or the `buoy` key in nuxt.config. */
|
|
2
|
+
export interface BuoyNuxtOptions {
|
|
3
|
+
/** Keep Buoy in a production build. App access rules still apply. */
|
|
4
|
+
enableInRelease?: boolean;
|
|
5
|
+
/** Installed tools to leave out, by package name, such as `['tv-remote']`. */
|
|
6
|
+
exclude?: string[];
|
|
7
|
+
/** Props for Buoy, the same as `app.use(buoy, options)` takes. They must be plain data. */
|
|
8
|
+
options?: Record<string, unknown>;
|
|
9
|
+
/**
|
|
10
|
+
* Set to false to call `nuxtApp.vueApp.use(buoy, options)` in your own
|
|
11
|
+
* client plugin, for options that aren't plain data (a `load` function).
|
|
12
|
+
* The module still adds the Vite plugin and the early hook.
|
|
13
|
+
*/
|
|
14
|
+
setup?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** The parts of a Nuxt instance the module uses. */
|
|
17
|
+
interface NuxtLike {
|
|
18
|
+
options: {
|
|
19
|
+
dev: boolean;
|
|
20
|
+
plugins: (string | {
|
|
21
|
+
src: string;
|
|
22
|
+
mode?: 'client' | 'server' | 'all';
|
|
23
|
+
})[];
|
|
24
|
+
runtimeConfig: {
|
|
25
|
+
public: Record<string, unknown>;
|
|
26
|
+
};
|
|
27
|
+
buoy?: BuoyNuxtOptions;
|
|
28
|
+
};
|
|
29
|
+
hook(name: 'vite:extendConfig', fn: (config: {
|
|
30
|
+
plugins?: unknown[];
|
|
31
|
+
}, env: {
|
|
32
|
+
isClient: boolean;
|
|
33
|
+
}) => void): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Buoy for Nuxt: `modules: ['@buoy-gg/vue/nuxt']`. In the browser build only,
|
|
37
|
+
* it adds the buoy() Vite plugin, puts Buoy's early hook on the first line of
|
|
38
|
+
* Nuxt's client entry (before Nuxt makes the Vue app), and adds a client
|
|
39
|
+
* plugin that runs `app.use(buoy)`. The server build gets none of it. In a
|
|
40
|
+
* production build, Buoy's imports resolve to their disabled builds unless
|
|
41
|
+
* `enableInRelease` is set.
|
|
42
|
+
*/
|
|
43
|
+
export default function buoyNuxt(inline: BuoyNuxtOptions, nuxt: NuxtLike): void;
|
|
44
|
+
export {};
|
package/lib/nuxt.mjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{buoy as u}from"@buoy-gg/core/vite";var r=/[\\/]nuxt[\\/]dist[\\/]app[\\/]entry(?:\.async)?\.js$/;function i(s={},e){let n={...e.options.buoy,...s},t=!!n.enableInRelease;if(!e.options.dev&&!t){e.hook("vite:extendConfig",o=>{o.plugins??=[],o.plugins.push(u({exclude:n.exclude,register:false}))});return}e.options.runtimeConfig.public.buoy={...n.options??{},...t?{enableInRelease:t}:{}},n.setup!==false&&e.options.plugins.push({src:new URL("./nuxt-plugin.mjs",import.meta.url).pathname,mode:"client"}),e.hook("vite:extendConfig",(o,{isClient:l})=>{l&&(o.plugins??=[],o.plugins.push(u({exclude:n.exclude,enableInRelease:t,register:false}),{name:"buoy-nuxt-early-hook",enforce:"pre",transform(a,p){if(r.test(p.split("?")[0]??""))return{code:`import '@buoy-gg/vue/register';
|
|
2
|
+
globalThis.__BUOY_FRAMEWORK__ = 'nuxt';
|
|
3
|
+
${a}`,map:null}}}))})}i.meta={name:"@buoy-gg/vue/nuxt",configKey:"buoy"};export{i as default};
|
package/lib/pinia.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** The parts of a Pinia store the bridge reads. */
|
|
2
|
+
export interface BuoyPiniaStore {
|
|
3
|
+
$id: string;
|
|
4
|
+
$state: Record<string, unknown>;
|
|
5
|
+
$patch(mutate: (state: Record<string, unknown>) => void): void;
|
|
6
|
+
$subscribe(callback: () => void, options?: {
|
|
7
|
+
detached?: boolean;
|
|
8
|
+
flush?: 'sync' | 'pre' | 'post';
|
|
9
|
+
}): () => void;
|
|
10
|
+
}
|
|
11
|
+
/** The parts of Pinia the store link reads. `_s` is Pinia's own map of live stores. */
|
|
12
|
+
export interface BuoyPinia {
|
|
13
|
+
_s: Map<string, BuoyPiniaStore>;
|
|
14
|
+
use(plugin: (context: {
|
|
15
|
+
store: BuoyPiniaStore;
|
|
16
|
+
}) => void): void;
|
|
17
|
+
}
|
|
18
|
+
/** What Buoy's Zustand tool reads and writes. */
|
|
19
|
+
export interface BuoyStoreApi<T> {
|
|
20
|
+
getState(): T;
|
|
21
|
+
getInitialState(): T;
|
|
22
|
+
setState(partial: Partial<T> | ((state: T) => Partial<T>), replace?: boolean): void;
|
|
23
|
+
subscribe(listener: (state: T, previous: T) => void): () => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A plain copy. Buoy keeps old states by reference, so it must never see the
|
|
27
|
+
* live store. Refs and reactive objects are unwrapped at every depth: a setup
|
|
28
|
+
* store keeps refs in its raw state, and `toRaw` alone only unwraps the top.
|
|
29
|
+
*/
|
|
30
|
+
export declare function plainCopy<T>(value: T, seen?: WeakMap<object, unknown>): T;
|
|
31
|
+
/**
|
|
32
|
+
* One Pinia store as a store the Zustand tool can read and edit. The same
|
|
33
|
+
* contract as @buoy-gg/solid's store bridge: a read returns a plain copy,
|
|
34
|
+
* kept until the store changes; after a full replace, `getState()` returns
|
|
35
|
+
* the object handed in, which is how a Time Machine restore checks it took.
|
|
36
|
+
*/
|
|
37
|
+
export declare function piniaStoreApi(store: BuoyPiniaStore): BuoyStoreApi<Record<string, unknown>>;
|
|
38
|
+
/**
|
|
39
|
+
* Show every Pinia store in the Zustand tool, by its id. Stores that exist
|
|
40
|
+
* now are added at once; Pinia makes the rest the first time the app uses
|
|
41
|
+
* them, and they are added then.
|
|
42
|
+
*/
|
|
43
|
+
export declare function watchPiniaStores(pinia: BuoyPinia, zustand: unknown): () => void;
|
|
44
|
+
/** A `ref` or `reactive` as a store for the Zustand tool. A bare value shows as `{ value }`. */
|
|
45
|
+
export declare function buoyVueRef<T extends object>(source: T): BuoyStoreApi<unknown>;
|
package/lib/pinia.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isRef as v,toRaw as $,watch as A}from"vue";function y(t,u=new WeakMap){let r=t;for(;v(r);)r=r.value;if(r===null||typeof r!="object")return r;let e=$(r);if(e instanceof Date)return new Date(e.getTime());if(u.has(e))return u.get(e);if(Array.isArray(e)){let n=[];u.set(e,n);for(let f of e)n.push(y(f,u));return n}let a={};u.set(e,a);for(let n of Object.keys(e))a[n]=y(e[n],u);return a}function d(t){let u=new Set,r=()=>y(t.$state),e=r(),a=e,n=false,f,i=(l,p)=>{for(let o of[...u])o(l,p)},w=()=>f?e:e=r(),g=()=>{f=t.$subscribe(()=>{if(n)return;let l=e;e=r(),i(e,l)},{detached:true,flush:"sync"})};return{getState:w,getInitialState:()=>a,setState(l,p){let o=w(),c=typeof l=="function"?l(o):l;if(c===null||typeof c!="object"||Array.isArray(c))return;let b=p?c:{...o,...c};n=true;try{t.$patch(h=>{for(let s of Object.keys(b))h[s]=y(b[s]);if(!p)return;let S=$(h);for(let s of Object.keys(S))s in b||(v(S[s])?h[s]=void 0:delete h[s])})}finally{n=false}let j=o;e=b,i(e,j)},subscribe(l){return u.add(l),f||g(),()=>{u.delete(l),u.size||(f?.(),f=void 0)}}}}function k(t,u){let r=u?.watchStores;if(typeof r!="function")return()=>{};let e=[],a=new WeakSet,n=true,f=i=>{!n||a.has(i)||(a.add(i),e.push(r({[i.$id]:Object.assign(d(i),{buoyLibrary:"pinia"})})))};for(let i of t._s.values())f(i);return t.use(({store:i})=>{f(i)}),()=>{if(n){n=false;for(let i of e.splice(0))i()}}}function O(t){let u=a=>a!==null&&typeof a=="object"&&!Array.isArray(a),r=v(t)&&!u($(t.value)),e={get $state(){return r?{value:t.value}:v(t)?t.value:t}};return d({$id:"ref",get $state(){return e.$state},$patch(a){if(r){let n={value:t.value};a(n),t.value=n.value;return}a(e.$state)},$subscribe:a=>A(t,a,{deep:true,flush:"sync"})})}export{O as buoyVueRef,d as piniaStoreApi,y as plainCopy,k as watchPiniaStores};
|
package/lib/register.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"@buoy-gg/core/web/register-network";var w=Symbol.for("buoy.vue.hook"),g=2500;function p(){let t=globalThis;return t[w]??={listeners:new Set,wrappers:new WeakMap,armed:false}}function d(t,e){for(let r of p().listeners)try{r(t,e)}catch(o){console.error("[Buoy]",o)}}function _(t){let{wrappers:e}=p(),r=e.get(t);if(r&&t.emit===r)return true;let o=t.emit,n=function(s,...i){return d(s,i),o?.apply(this??t,[s,...i])};try{Object.defineProperty(t,"emit",{configurable:true,enumerable:true,get:()=>n,set:s=>{s!==n&&(o=s)}})}catch{let s=t.on;if(typeof s!="function")return false;for(let i of["component:added","component:updated","component:removed","perf:start","perf:end","app:init","app:unmount"])s.call(t,i,(...a)=>d(i,a))}return e.set(t,n),true}function c(){let t=new Map;return{enabled:false,apps:[],events:t,on(e,r){return t.has(e)||t.set(e,[]),t.get(e).push(r),()=>this.off(e,r)},once(e,r){let o=(...n)=>{this.off(e,o),r(...n)};this.on(e,o)},off(e,r){let o=t.get(e),n=o?.indexOf(r)??-1;o&&n!==-1&&o.splice(n,1)},emit(e,...r){for(let o of[...t.get(e)??[]])o(...r)}}}function L(){return typeof window>"u"||!window.HTMLElement?false:!window.navigator?.userAgent?.includes("jsdom")}function O(){let t=globalThis,e=p(),r=t.__VUE_DEVTOOLS_GLOBAL_HOOK__;if(r){_(r),e.armed=true;return}if(e.armed)return;if(e.armed=true,!L()){let o=c();_(o),t.__VUE_DEVTOOLS_GLOBAL_HOOK__=o;return}(t.__VUE_DEVTOOLS_HOOK_REPLAY__||=[]).push(o=>{_(o)}),setTimeout(()=>{if(t.__VUE_DEVTOOLS_GLOBAL_HOOK__){_(t.__VUE_DEVTOOLS_GLOBAL_HOOK__);return}let o=c();_(o),t.__VUE_DEVTOOLS_GLOBAL_HOOK__=o;let n=t.__VUE_DEVTOOLS_HOOK_REPLAY__??[];t.__VUE_DEVTOOLS_HOOK_REPLAY__=[];for(let s of n)try{s(o)}catch(i){console.error("[Buoy]",i)}},g)}function h(t){O();let{listeners:e}=p();return e.add(t),()=>{e.delete(t)}}var y=new Set(["BaseTransition","Transition","TransitionGroup","KeepAlive","Suspense","Teleport"]);function m(t){let e=t.type??{};return e.name?e.name:e.__name?e.__name:e.__file?.split(/[\\/]/).pop()?.replace(/\.\w+$/,"")||"Anonymous"}var T=Symbol.for("buoy.vue.renders");function S(){let t=globalThis;return t[T]??={trees:new WeakMap,listeners:new Set,installed:false}}function b(t){let e=S();return e.installed||(e.installed=true,h((r,o)=>{if(r!=="component:added"&&r!=="component:updated")return;let n=o[3];if(!n||typeof n!="object"||o[0]?._instance?.type?.devtools?.hide)return;let s=n.subTree,i=e.trees.has(n),a=e.trees.get(n)!==s;if(e.trees.set(n,s),!(r==="component:added"||!n.isMounted||i&&!a))for(let f of e.listeners)f(n)})),t?(e.listeners.add(t),()=>{e.listeners.delete(t)}):()=>{}}function v(t){let e;for(let o=t;o&&!e;o=o.parentElement)e=o.__vueParentComponent;let r=[];for(let o=0;e&&o<200&&r.length<7;o++,e=e.parent??void 0){let n=m(e);if(y.has(n)||!e.parent&&!e.type?.__file)continue;let s=e.type?.__file;r.push({name:n,...s?{source:{fileName:s}}:{reason:"It comes from a library, so it has no file in the app."},memo:false,forwardRef:false})}if(r.length)return{found:true,component:r[0],owners:r.slice(1)}}function V(t){for(let e=t;e;e=e.parentElement){let r=e.__vueParentComponent;for(;r&&y.has(m(r));)r=r.parent??void 0;if(r)return m(r)}}var A=15;function M(){let t=null;return{isSupported:()=>true,start(){t?.();let e=new Map,r=0,o=false,n=(a,f)=>{let l=m(a),u=e.get(l)??{mount:0,updates:0};u[f]+=1,e.set(l,u),o||(o=true,r+=1,queueMicrotask(()=>{o=false}))},s=h((a,f)=>{let l=f[3];a==="component:added"&&l&&typeof l=="object"&&n(l,"mount")}),i=b(a=>n(a,"updates"));t=()=>{s(),i();let a=[...e].map(([l,u])=>({name:l,renders:u.mount+u.updates,totalMs:0,maxMs:0,avgMs:0,causes:{...u.mount?{mount:u.mount}:{},...u.updates?{hooks:u.updates}:{}}})),f={mount:0,hooks:0};for(let l of a)f.mount+=l.causes.mount??0,f.hooks+=l.causes.hooks??0;return{totalCommits:r,totalRenders:a.reduce((l,u)=>l+u.renders,0),capturedDurations:false,totalRenderMs:0,causes:f,topComponents:a.sort((l,u)=>u.renders-l.renders).slice(0,A)}}},stop(){let e=t;return t=null,e?e():null}}}import{registerBrowserNetwork as k}from"@buoy-gg/core/web/register-network";var E=globalThis;E.__BUOY_FRAMEWORK__!=="nuxt"&&(E.__BUOY_FRAMEWORK__="vue");O();b();globalThis[Symbol.for("buoy.dom.componentName")]=V;globalThis[Symbol.for("buoy.dom.componentSource")]=v;globalThis[Symbol.for("buoy.framework.renderCapture")]=M();export{k as registerBrowserNetwork};
|
package/lib/router.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** The parts of a Vue Router location the Routes link reads. */
|
|
2
|
+
export interface BuoyVueRouteLocation {
|
|
3
|
+
path: string;
|
|
4
|
+
fullPath: string;
|
|
5
|
+
name?: string | symbol | null;
|
|
6
|
+
params: Record<string, string | string[] | undefined>;
|
|
7
|
+
query: Record<string, unknown>;
|
|
8
|
+
matched: {
|
|
9
|
+
path: string;
|
|
10
|
+
}[];
|
|
11
|
+
}
|
|
12
|
+
/** The parts of a Vue Router 4 or 5 instance the Routes link reads. */
|
|
13
|
+
export interface BuoyVueRouter {
|
|
14
|
+
afterEach(guard: (to: BuoyVueRouteLocation, from: BuoyVueRouteLocation, failure?: unknown) => unknown): () => void;
|
|
15
|
+
isReady(): Promise<unknown>;
|
|
16
|
+
currentRoute: {
|
|
17
|
+
value: BuoyVueRouteLocation;
|
|
18
|
+
};
|
|
19
|
+
getRoutes(): {
|
|
20
|
+
path: string;
|
|
21
|
+
children?: unknown[];
|
|
22
|
+
}[];
|
|
23
|
+
push(to: string): Promise<unknown>;
|
|
24
|
+
replace(to: string): Promise<unknown>;
|
|
25
|
+
back(): void;
|
|
26
|
+
addRoute?: (...args: never[]) => unknown;
|
|
27
|
+
removeRoute?: (...args: never[]) => unknown;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Vue Router paths in the Routes tool's form. `:id`, `:id?` and `:id(\\d+)`
|
|
31
|
+
* become `[id]`; repeatable `:id+` and `:id*` become `[...id]`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function vueRouteTemplate(pattern: string): string;
|
|
34
|
+
/** Every page path the router knows, as templates. Routes with only children are layouts, not pages. */
|
|
35
|
+
export declare function vueRoutePaths(router: Pick<BuoyVueRouter, 'getRoutes'>): string[];
|
|
36
|
+
/**
|
|
37
|
+
* Report Vue Router page changes to the Routes tool with their names and
|
|
38
|
+
* params, and let the tool's Go button and the MCP navigate through the
|
|
39
|
+
* router. Raw history capture stops adding its own events while this runs.
|
|
40
|
+
*/
|
|
41
|
+
export declare function connectBuoyRouter(router: BuoyVueRouter): () => void;
|
package/lib/router.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{claimBrowserRouteEvents as $,registerBrowserRoutes as d,routeObserver as k}from"@buoy-gg/route-events/web";import{registerBrowserRouter as S}from"@buoy-gg/shared-ui/web/utils";function f(t){return`/${t}`.replace(/\/+/g,"/").replace(/(.)\/$/,"$1").replace(/:(\w+)(\((?:[^()]|\([^()]*\))*\))?([?+*])?/g,(a,r,n,s)=>s==="+"||s==="*"?`[...${r}]`:`[${r}]`)}function h(t){let a=t.getRoutes().filter(r=>!r.children?.length).map(r=>f(r.path));return[...new Set(a)]}function O(t){let a={};for(let[r,n]of Object.entries(t))Array.isArray(n)?a[r]=n.filter(s=>s!=null).map(String):n!=null&&(a[r]=String(n));return a}function E(t){let a=$(),r=d(h(t)),n=()=>{r(),r=d(h(t))},s=e=>{e.catch(()=>{})},b=S({push:e=>s(t.push(e)),replace:e=>s(t.replace(e)),back:()=>t.back(),canGoBack:()=>typeof history<"u"&&!!history.state?.back}),m=[];for(let e of["addRoute","removeRoute"]){let o=t[e];typeof o=="function"&&(t[e]=function(...l){let u=o.apply(this??t,l);return n(),u},m.push(()=>{t[e]=o}))}let g,i,v,c=true,y=e=>{if(!c||e.fullPath===v)return;v=e.fullPath;let o=e.matched[e.matched.length-1]?.path??e.path,l=f(o),u=O(e.query);for(let[P,R]of Object.entries(e.params))R!==void 0&&(u[P]=R);let B=typeof e.name=="string"?e.name:o,p=Date.now();k.emit({pathname:e.path,params:u,segments:l.split("/").filter(Boolean),routeName:B,matchedPath:o,previousPathname:g,timestamp:p,timeSincePrevious:i===void 0?void 0:p-i}),g=e.path,i=p},w=t.afterEach((e,o,l)=>{l||y(e)});return t.isReady().then(()=>y(t.currentRoute.value),()=>{}),()=>{if(c){c=false,w();for(let e of m.splice(0))e();r(),a(),b()}}}export{E as connectBuoyRouter,h as vueRoutePaths,f as vueRouteTemplate};
|
package/package.json
CHANGED
|
@@ -1,6 +1,99 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/vue",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "7.0.76",
|
|
4
|
+
"description": "Run Buoy in a Vue or Nuxt app.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./lib/index.d.ts",
|
|
9
|
+
"buoy-disabled": "./lib/disabled/index.mjs",
|
|
10
|
+
"default": "./lib/index.mjs"
|
|
11
|
+
},
|
|
12
|
+
"./register": {
|
|
13
|
+
"types": "./lib/register.d.ts",
|
|
14
|
+
"buoy-disabled": "./lib/disabled/register.mjs",
|
|
15
|
+
"default": "./lib/register.mjs"
|
|
16
|
+
},
|
|
17
|
+
"./router": {
|
|
18
|
+
"types": "./lib/router.d.ts",
|
|
19
|
+
"buoy-disabled": "./lib/disabled/router.mjs",
|
|
20
|
+
"default": "./lib/router.mjs"
|
|
21
|
+
},
|
|
22
|
+
"./pinia": {
|
|
23
|
+
"types": "./lib/pinia.d.ts",
|
|
24
|
+
"buoy-disabled": "./lib/disabled/pinia.mjs",
|
|
25
|
+
"default": "./lib/pinia.mjs"
|
|
26
|
+
},
|
|
27
|
+
"./highlights": {
|
|
28
|
+
"types": "./lib/highlights.d.ts",
|
|
29
|
+
"buoy-disabled": "./lib/disabled/highlights.mjs",
|
|
30
|
+
"default": "./lib/highlights.mjs"
|
|
31
|
+
},
|
|
32
|
+
"./nuxt": {
|
|
33
|
+
"types": "./lib/nuxt.d.ts",
|
|
34
|
+
"default": "./lib/nuxt.mjs"
|
|
35
|
+
},
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"types": "./lib/index.d.ts",
|
|
39
|
+
"files": [
|
|
40
|
+
"lib",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"sideEffects": [
|
|
44
|
+
"./lib/register.mjs",
|
|
45
|
+
"./lib/disabled/register.mjs"
|
|
46
|
+
],
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"react": "^19.2.0",
|
|
49
|
+
"react-dom": "^19.2.0",
|
|
50
|
+
"react-native-web": "^0.21.2",
|
|
51
|
+
"@buoy-gg/core": "^7.0.76",
|
|
52
|
+
"@buoy-gg/shared-ui": "^7.0.76"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"vue": ">=3.3 <4"
|
|
56
|
+
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"vue-router": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"pinia": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"@tanstack/vue-query": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"@tanstack/react-query": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"@buoy-gg/route-events": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"@buoy-gg/zustand": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"@buoy-gg/highlight-updates": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"nuxt": {
|
|
80
|
+
"optional": true
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"devDependencies": {
|
|
84
|
+
"vue": "3.5.44",
|
|
85
|
+
"vue-router": "5.4.0",
|
|
86
|
+
"pinia": "4.1.0",
|
|
87
|
+
"@tanstack/vue-query": "5.104.5",
|
|
88
|
+
"esbuild": "^0.25.0",
|
|
89
|
+
"jsdom": "^26.1.0",
|
|
90
|
+
"typescript": "~5.8.3",
|
|
91
|
+
"vitest": "^3.2.0",
|
|
92
|
+
"@buoy-gg/zustand": "^7.0.76",
|
|
93
|
+
"@buoy-gg/route-events": "^7.0.76"
|
|
94
|
+
},
|
|
95
|
+
"scripts": {
|
|
96
|
+
"build": "node build.mjs && node ../../scripts/minify-lib.mjs && node ../../scripts/assert-minified.mjs",
|
|
97
|
+
"test": "vitest run --config vitest.config.mjs"
|
|
98
|
+
}
|
|
6
99
|
}
|