@reticlehq/vite-plugin 2.13.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +581 -463
- package/dist/index.d.cts +85 -44
- package/dist/index.d.ts +85 -44
- package/dist/index.js +129 -106
- package/dist/injection-postcondition.d.ts +81 -0
- package/dist/injection-postcondition.js +123 -0
- package/dist/installed.d.ts +2 -1
- package/dist/plugin-name.d.ts +7 -0
- package/dist/plugin-name.js +7 -0
- package/dist/project-id.d.ts +24 -6
- package/dist/project-id.js +67 -22
- package/dist/vitest-browser.d.ts +31 -0
- package/dist/vitest-browser.js +37 -0
- package/dist/watch-ignore.d.ts +18 -0
- package/dist/watch-ignore.js +26 -0
- package/package.json +7 -6
- /package/dist/{ensure-token.d.ts → token/ensure-token.d.ts} +0 -0
- /package/dist/{ensure-token.js → token/ensure-token.js} +0 -0
- /package/dist/{missing-token.d.ts → token/missing-token.d.ts} +0 -0
- /package/dist/{missing-token.js → token/missing-token.js} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { type InjectionWatch } from './injection-postcondition.js';
|
|
2
|
+
export { RETICLE_VITE_PLUGIN_NAME } from './plugin-name.js';
|
|
2
3
|
/**
|
|
3
4
|
* Compile-time global carrying the daemon's pairing token, for connects the plugin does not write
|
|
4
5
|
* itself. The bridge requires the token even on localhost, and nothing in a browser can read the
|
|
@@ -12,6 +13,21 @@ export declare const RETICLE_TOKEN_GLOBAL = "__RETICLE_TOKEN__";
|
|
|
12
13
|
* by the injected <script src> and served by the load hook below.
|
|
13
14
|
*/
|
|
14
15
|
export declare const RETICLE_CONNECT_MODULE = "/@reticle-connect";
|
|
16
|
+
/**
|
|
17
|
+
* The URL the injected `<script src>` must actually point at: `base` + the module id.
|
|
18
|
+
*
|
|
19
|
+
* {@link RETICLE_CONNECT_MODULE} is a SERVER-ROOT path, and emitting it verbatim is only correct
|
|
20
|
+
* when Vite is serving from the root. Under `base: '/playground/'` the browser asked for
|
|
21
|
+
* `/@reticle-connect`, Vite answered 404 with its own "did you mean /playground/@reticle-connect"
|
|
22
|
+
* hint, and the page rendered perfectly while never connecting (#676) — the exact failure shape
|
|
23
|
+
* Reticle exists to catch, in Reticle's own setup path.
|
|
24
|
+
*
|
|
25
|
+
* Vite does not prefix tags returned from `transformIndexHtml`, so the prefix has to be applied
|
|
26
|
+
* here. Only a path base is joined: Vite serves the dev app from the root when `base` is an
|
|
27
|
+
* external URL, so prefixing a CDN origin onto a dev-server module would point the tag off-host.
|
|
28
|
+
*/
|
|
29
|
+
import { type WatchPattern } from './watch-ignore.js';
|
|
30
|
+
export declare function connectModuleUrl(base: string | undefined): string;
|
|
15
31
|
/**
|
|
16
32
|
* The pre-hook, as source for an inline <head> script.
|
|
17
33
|
*
|
|
@@ -73,22 +89,21 @@ export interface ReticleVitePluginOptions {
|
|
|
73
89
|
* Off by default because a body is the one part of a request that routinely carries a card
|
|
74
90
|
* number, a token or a customer's address, and the daemon journals what it is told.
|
|
75
91
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* only `connect()` most apps ever have — had no way to pass it, and calling `connect()` a second
|
|
79
|
-
* time is a no-op. So for every app wired the recommended way, a payload was unreachable: on a
|
|
80
|
-
* real payments dashboard, a refund POSTing `amount: 1187.01` into a paise field (a 100x
|
|
81
|
-
* under-refund) was visible to Playwright's request inspector and invisible here.
|
|
92
|
+
* Exposed HERE because the plugin is the only `connect()` most apps have and a second `connect()`
|
|
93
|
+
* is a no-op, so an SDK option the plugin cannot pass is an option that does not exist.
|
|
82
94
|
*
|
|
83
|
-
* Also settable as `VITE_RETICLE_CAPTURE_BODIES=1
|
|
84
|
-
* session without editing vite.config.
|
|
95
|
+
* Also settable as `VITE_RETICLE_CAPTURE_BODIES=1`.
|
|
85
96
|
*/
|
|
86
97
|
captureNetworkBodies?: boolean;
|
|
87
98
|
/**
|
|
88
|
-
*
|
|
99
|
+
* Retain a FAILED request's response body even with `captureNetworkBodies` off. Default true.
|
|
89
100
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
101
|
+
* Also settable as `VITE_RETICLE_NO_ERROR_BODIES=1`, which turns it OFF -- the inverse of the
|
|
102
|
+
* other env vars, because this is the one that defaults on (#800).
|
|
103
|
+
*/
|
|
104
|
+
captureErrorBodies?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Make Reticle's OWN presenter visible to snapshots and queries. CONTRIBUTORS ONLY.
|
|
92
107
|
*
|
|
93
108
|
* The presenter is hidden from every tool by design — an agent that can drive Reticle's own
|
|
94
109
|
* interface can fabricate its own impact report. The cost is that a HUD change is the only kind of
|
|
@@ -104,9 +119,7 @@ export interface ReticleVitePluginOptions {
|
|
|
104
119
|
* Off by default: the SDK refuses outside localhost so a page on the open internet cannot be
|
|
105
120
|
* instrumented by a bridge it happened to reach. Turn it on for a dev server that CANNOT be served
|
|
106
121
|
* on localhost — a host-based multi-tenant frontend, a white-label app resolving the tenant from
|
|
107
|
-
* the `Host` header, anything with cookie-scoped auth on a custom dev hostname.
|
|
108
|
-
* apps cannot use Reticle at all, because the plugin is the only `connect()` they have and a
|
|
109
|
-
* second, hand-written one is a no-op.
|
|
122
|
+
* the `Host` header, anything with cookie-scoped auth on a custom dev hostname.
|
|
110
123
|
*
|
|
111
124
|
* NOT SUFFICIENT ON ITS OWN — a pairing token is also required. `connectionPolicy` in
|
|
112
125
|
* `@reticlehq/browser` refuses a non-localhost connect with "a pairing token is required outside
|
|
@@ -115,8 +128,7 @@ export interface ReticleVitePluginOptions {
|
|
|
115
128
|
* started daemon is normally all it takes; pass `token` yourself only when the daemon's file is
|
|
116
129
|
* unreachable. A non-loopback BRIDGE additionally has to be `wss://`.
|
|
117
130
|
*
|
|
118
|
-
* Also settable as `VITE_RETICLE_ALLOW_NON_LOCALHOST=1
|
|
119
|
-
* without editing vite.config.
|
|
131
|
+
* Also settable as `VITE_RETICLE_ALLOW_NON_LOCALHOST=1`.
|
|
120
132
|
*/
|
|
121
133
|
allowNonLocalhost?: boolean;
|
|
122
134
|
/**
|
|
@@ -125,28 +137,53 @@ export interface ReticleVitePluginOptions {
|
|
|
125
137
|
*/
|
|
126
138
|
onWarn?: (message: string) => void;
|
|
127
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* The slice of Vite's `UserConfig` the `config` hook reads. Everything is optional AND nullable
|
|
142
|
+
* because that is what Vite declares — a stand-in that is narrower than the real value is not a
|
|
143
|
+
* looser type, it is a stricter one, and it makes the whole plugin unassignable to `Plugin`.
|
|
144
|
+
*/
|
|
145
|
+
export interface ViteUserConfigLike {
|
|
146
|
+
optimizeDeps?: {
|
|
147
|
+
include?: string[] | undefined;
|
|
148
|
+
/** Whichever key the app used — the plugin reads both and writes the one this Vite wants. */
|
|
149
|
+
esbuildOptions?: Record<string, unknown> | undefined;
|
|
150
|
+
rolldownOptions?: Record<string, unknown> | undefined;
|
|
151
|
+
} | undefined;
|
|
152
|
+
define?: Record<string, unknown> | undefined;
|
|
153
|
+
root?: string | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* The app's own watcher config. `watch` is nullable because `null` is how a config switches the
|
|
156
|
+
* watcher off, and `ignored` is `unknown` because Vite's `AnymatchMatcher` is not an array — it is
|
|
157
|
+
* a string, a RegExp, a predicate function, or an array of those. Typing it as an array here is
|
|
158
|
+
* the narrowing that made the whole plugin unassignable to Vite's `Plugin`, and it also invited a
|
|
159
|
+
* runtime defect: see `mergeIgnored`.
|
|
160
|
+
*/
|
|
161
|
+
server?: {
|
|
162
|
+
watch?: {
|
|
163
|
+
ignored?: unknown;
|
|
164
|
+
} | null | undefined;
|
|
165
|
+
} | undefined;
|
|
166
|
+
/**
|
|
167
|
+
* Vitest's block, when this config belongs to a Vitest run. Read ONLY to spot browser mode — see
|
|
168
|
+
* `isVitestBrowserServer`. Typed as `unknown` because it is Vitest's shape, not Vite's, and this
|
|
169
|
+
* plugin has no business asserting anything about the rest of it.
|
|
170
|
+
*/
|
|
171
|
+
test?: unknown;
|
|
172
|
+
}
|
|
128
173
|
/** Structural Vite plugin shape — avoids a hard dependency on `vite` while staying assignable to its `Plugin`. */
|
|
129
174
|
export interface ReticleVitePlugin {
|
|
130
175
|
name: string;
|
|
131
176
|
/**
|
|
132
177
|
* Vite's `config` hook. Used to declare the SDK's CJS runtime deps for pre-bundling — see the
|
|
133
178
|
* implementation for why omitting them makes the whole SDK fail to load on linked setups.
|
|
179
|
+
*
|
|
180
|
+
* METHOD syntax, not a property, and every field it reads is optional-and-nullable. Both halves
|
|
181
|
+
* are load-bearing, and both are the contravariance trap this file's sibling test documents:
|
|
182
|
+
* a property's parameter is checked strictly, so a narrow stand-in REJECTS the wider `UserConfig`
|
|
183
|
+
* Vite actually passes. `server.watch` is where it bit — Vite types it `WatchOptions | null`,
|
|
184
|
+
* `null` being how a config turns the watcher off, and SvelteKit's template does exactly that.
|
|
134
185
|
*/
|
|
135
|
-
config
|
|
136
|
-
optimizeDeps?: {
|
|
137
|
-
include?: string[];
|
|
138
|
-
/** Whichever key the app used — the plugin reads both and writes the one this Vite wants. */
|
|
139
|
-
esbuildOptions?: Record<string, unknown>;
|
|
140
|
-
rolldownOptions?: Record<string, unknown>;
|
|
141
|
-
};
|
|
142
|
-
define?: Record<string, string>;
|
|
143
|
-
root?: string;
|
|
144
|
-
server?: {
|
|
145
|
-
watch?: {
|
|
146
|
-
ignored?: (string | RegExp)[];
|
|
147
|
-
};
|
|
148
|
-
};
|
|
149
|
-
}) => {
|
|
186
|
+
config?(config: ViteUserConfigLike): {
|
|
150
187
|
optimizeDeps: {
|
|
151
188
|
include: string[];
|
|
152
189
|
[optionsKey: string]: unknown;
|
|
@@ -154,7 +191,7 @@ export interface ReticleVitePlugin {
|
|
|
154
191
|
define: Record<string, string>;
|
|
155
192
|
server: {
|
|
156
193
|
watch: {
|
|
157
|
-
ignored:
|
|
194
|
+
ignored: WatchPattern[];
|
|
158
195
|
};
|
|
159
196
|
};
|
|
160
197
|
};
|
|
@@ -172,6 +209,9 @@ export interface ReticleVitePlugin {
|
|
|
172
209
|
configResolved?: (config: {
|
|
173
210
|
root?: string;
|
|
174
211
|
command?: string;
|
|
212
|
+
base?: string;
|
|
213
|
+
/** Vitest's block, read only to spot browser mode. See isVitestBrowserServer. */
|
|
214
|
+
test?: unknown;
|
|
175
215
|
}) => void;
|
|
176
216
|
/** Dev-server hook: keeps the served connect module from outliving the token it was built without. */
|
|
177
217
|
configureServer?: (server: ViteDevServerLike) => void;
|
|
@@ -179,6 +219,9 @@ export interface ReticleVitePlugin {
|
|
|
179
219
|
buildEnd?: () => void;
|
|
180
220
|
/** Runs the dev-mode injection check immediately. Test seam for the deferred timer. */
|
|
181
221
|
checkInjectedForTest?: () => void;
|
|
222
|
+
checkHtmlHookForTest?: () => void;
|
|
223
|
+
/** The post-condition watch itself, so a test drives the real predicate and not a copy of it. */
|
|
224
|
+
injectionWatchForTest?: InjectionWatch;
|
|
182
225
|
}
|
|
183
226
|
/**
|
|
184
227
|
* The slice of Vite's dev server this plugin touches, structurally — so `vite` stays a peer the
|
|
@@ -208,6 +251,9 @@ export interface ViteDevServerLike {
|
|
|
208
251
|
middlewares: {
|
|
209
252
|
use(handler: (req: {
|
|
210
253
|
url?: string | undefined;
|
|
254
|
+
headers?: {
|
|
255
|
+
accept?: string | undefined;
|
|
256
|
+
} | undefined;
|
|
211
257
|
}, res: unknown, next: () => void) => void): void;
|
|
212
258
|
};
|
|
213
259
|
moduleGraph: {
|
|
@@ -235,10 +281,9 @@ export declare function readPairingToken(): string | undefined;
|
|
|
235
281
|
/**
|
|
236
282
|
* The conventional app-side dev module: `registerStore` / `registerCapabilities` live here.
|
|
237
283
|
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
* Convention costs one `existsSync` and leaves their entry untouched.
|
|
284
|
+
* Imported by CONVENTION rather than by patching the app's entry file: the connect is injected into
|
|
285
|
+
* a virtual module, so the alternative is `init` editing `src/main.tsx` — a file the user owns — for
|
|
286
|
+
* something that is opt-in enrichment. Convention costs one `existsSync`.
|
|
242
287
|
*/
|
|
243
288
|
export declare const RETICLE_DEV_MODULE_CANDIDATES: readonly ["src/reticle-dev.ts", "src/reticle-dev.js", "src/reticle-dev.tsx", "src/reticle-dev.jsx"];
|
|
244
289
|
/** The app's dev module, as an importable path — or null when the app has none. */
|
|
@@ -246,14 +291,11 @@ export declare function findDevModule(root: string, exists: (p: string) => boole
|
|
|
246
291
|
/**
|
|
247
292
|
* Which SDK package this app actually has, and whether `install()` applies.
|
|
248
293
|
*
|
|
249
|
-
* The injected connect
|
|
294
|
+
* The injected connect must NOT name `@reticlehq/react` unconditionally. That is right for a React
|
|
250
295
|
* app and fatal for any other: `reticle init` gives a Vue or Svelte codebase the framework-neutral
|
|
251
296
|
* `@reticlehq/browser` — deliberately, because a package named `@reticlehq/react` with `react` in
|
|
252
|
-
* its peers has no business in a Vue app — and the injected import then
|
|
253
|
-
* installed, so nothing connects and the page reports no session with no obvious cause.
|
|
254
|
-
*
|
|
255
|
-
* Measured end to end on a pristine `npm create vite --template vue` app: init wrote every file
|
|
256
|
-
* correctly and the tab never dialled the daemon, because of this one specifier.
|
|
297
|
+
* its peers has no business in a Vue app — and the injected import would then name a package that is
|
|
298
|
+
* not installed, so nothing connects and the page reports no session with no obvious cause.
|
|
257
299
|
*
|
|
258
300
|
* The React kit WINS when both resolve: it is a superset (it re-exports the sensor and adds the
|
|
259
301
|
* adapter), so an app that has it wants component identity. `install()` is the adapter's alone and
|
|
@@ -288,5 +330,4 @@ export declare function connectModuleSource(options: ReticleVitePluginOptions, d
|
|
|
288
330
|
*/
|
|
289
331
|
export declare const JOURNAL_IGNORE: RegExp;
|
|
290
332
|
export declare function reticle(options?: ReticleVitePluginOptions): ReticleVitePlugin;
|
|
291
|
-
export {};
|
|
292
333
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { type InjectionWatch } from './injection-postcondition.js';
|
|
2
|
+
export { RETICLE_VITE_PLUGIN_NAME } from './plugin-name.js';
|
|
2
3
|
/**
|
|
3
4
|
* Compile-time global carrying the daemon's pairing token, for connects the plugin does not write
|
|
4
5
|
* itself. The bridge requires the token even on localhost, and nothing in a browser can read the
|
|
@@ -12,6 +13,21 @@ export declare const RETICLE_TOKEN_GLOBAL = "__RETICLE_TOKEN__";
|
|
|
12
13
|
* by the injected <script src> and served by the load hook below.
|
|
13
14
|
*/
|
|
14
15
|
export declare const RETICLE_CONNECT_MODULE = "/@reticle-connect";
|
|
16
|
+
/**
|
|
17
|
+
* The URL the injected `<script src>` must actually point at: `base` + the module id.
|
|
18
|
+
*
|
|
19
|
+
* {@link RETICLE_CONNECT_MODULE} is a SERVER-ROOT path, and emitting it verbatim is only correct
|
|
20
|
+
* when Vite is serving from the root. Under `base: '/playground/'` the browser asked for
|
|
21
|
+
* `/@reticle-connect`, Vite answered 404 with its own "did you mean /playground/@reticle-connect"
|
|
22
|
+
* hint, and the page rendered perfectly while never connecting (#676) — the exact failure shape
|
|
23
|
+
* Reticle exists to catch, in Reticle's own setup path.
|
|
24
|
+
*
|
|
25
|
+
* Vite does not prefix tags returned from `transformIndexHtml`, so the prefix has to be applied
|
|
26
|
+
* here. Only a path base is joined: Vite serves the dev app from the root when `base` is an
|
|
27
|
+
* external URL, so prefixing a CDN origin onto a dev-server module would point the tag off-host.
|
|
28
|
+
*/
|
|
29
|
+
import { type WatchPattern } from './watch-ignore.js';
|
|
30
|
+
export declare function connectModuleUrl(base: string | undefined): string;
|
|
15
31
|
/**
|
|
16
32
|
* The pre-hook, as source for an inline <head> script.
|
|
17
33
|
*
|
|
@@ -73,22 +89,21 @@ export interface ReticleVitePluginOptions {
|
|
|
73
89
|
* Off by default because a body is the one part of a request that routinely carries a card
|
|
74
90
|
* number, a token or a customer's address, and the daemon journals what it is told.
|
|
75
91
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* only `connect()` most apps ever have — had no way to pass it, and calling `connect()` a second
|
|
79
|
-
* time is a no-op. So for every app wired the recommended way, a payload was unreachable: on a
|
|
80
|
-
* real payments dashboard, a refund POSTing `amount: 1187.01` into a paise field (a 100x
|
|
81
|
-
* under-refund) was visible to Playwright's request inspector and invisible here.
|
|
92
|
+
* Exposed HERE because the plugin is the only `connect()` most apps have and a second `connect()`
|
|
93
|
+
* is a no-op, so an SDK option the plugin cannot pass is an option that does not exist.
|
|
82
94
|
*
|
|
83
|
-
* Also settable as `VITE_RETICLE_CAPTURE_BODIES=1
|
|
84
|
-
* session without editing vite.config.
|
|
95
|
+
* Also settable as `VITE_RETICLE_CAPTURE_BODIES=1`.
|
|
85
96
|
*/
|
|
86
97
|
captureNetworkBodies?: boolean;
|
|
87
98
|
/**
|
|
88
|
-
*
|
|
99
|
+
* Retain a FAILED request's response body even with `captureNetworkBodies` off. Default true.
|
|
89
100
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
101
|
+
* Also settable as `VITE_RETICLE_NO_ERROR_BODIES=1`, which turns it OFF -- the inverse of the
|
|
102
|
+
* other env vars, because this is the one that defaults on (#800).
|
|
103
|
+
*/
|
|
104
|
+
captureErrorBodies?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Make Reticle's OWN presenter visible to snapshots and queries. CONTRIBUTORS ONLY.
|
|
92
107
|
*
|
|
93
108
|
* The presenter is hidden from every tool by design — an agent that can drive Reticle's own
|
|
94
109
|
* interface can fabricate its own impact report. The cost is that a HUD change is the only kind of
|
|
@@ -104,9 +119,7 @@ export interface ReticleVitePluginOptions {
|
|
|
104
119
|
* Off by default: the SDK refuses outside localhost so a page on the open internet cannot be
|
|
105
120
|
* instrumented by a bridge it happened to reach. Turn it on for a dev server that CANNOT be served
|
|
106
121
|
* on localhost — a host-based multi-tenant frontend, a white-label app resolving the tenant from
|
|
107
|
-
* the `Host` header, anything with cookie-scoped auth on a custom dev hostname.
|
|
108
|
-
* apps cannot use Reticle at all, because the plugin is the only `connect()` they have and a
|
|
109
|
-
* second, hand-written one is a no-op.
|
|
122
|
+
* the `Host` header, anything with cookie-scoped auth on a custom dev hostname.
|
|
110
123
|
*
|
|
111
124
|
* NOT SUFFICIENT ON ITS OWN — a pairing token is also required. `connectionPolicy` in
|
|
112
125
|
* `@reticlehq/browser` refuses a non-localhost connect with "a pairing token is required outside
|
|
@@ -115,8 +128,7 @@ export interface ReticleVitePluginOptions {
|
|
|
115
128
|
* started daemon is normally all it takes; pass `token` yourself only when the daemon's file is
|
|
116
129
|
* unreachable. A non-loopback BRIDGE additionally has to be `wss://`.
|
|
117
130
|
*
|
|
118
|
-
* Also settable as `VITE_RETICLE_ALLOW_NON_LOCALHOST=1
|
|
119
|
-
* without editing vite.config.
|
|
131
|
+
* Also settable as `VITE_RETICLE_ALLOW_NON_LOCALHOST=1`.
|
|
120
132
|
*/
|
|
121
133
|
allowNonLocalhost?: boolean;
|
|
122
134
|
/**
|
|
@@ -125,28 +137,53 @@ export interface ReticleVitePluginOptions {
|
|
|
125
137
|
*/
|
|
126
138
|
onWarn?: (message: string) => void;
|
|
127
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* The slice of Vite's `UserConfig` the `config` hook reads. Everything is optional AND nullable
|
|
142
|
+
* because that is what Vite declares — a stand-in that is narrower than the real value is not a
|
|
143
|
+
* looser type, it is a stricter one, and it makes the whole plugin unassignable to `Plugin`.
|
|
144
|
+
*/
|
|
145
|
+
export interface ViteUserConfigLike {
|
|
146
|
+
optimizeDeps?: {
|
|
147
|
+
include?: string[] | undefined;
|
|
148
|
+
/** Whichever key the app used — the plugin reads both and writes the one this Vite wants. */
|
|
149
|
+
esbuildOptions?: Record<string, unknown> | undefined;
|
|
150
|
+
rolldownOptions?: Record<string, unknown> | undefined;
|
|
151
|
+
} | undefined;
|
|
152
|
+
define?: Record<string, unknown> | undefined;
|
|
153
|
+
root?: string | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* The app's own watcher config. `watch` is nullable because `null` is how a config switches the
|
|
156
|
+
* watcher off, and `ignored` is `unknown` because Vite's `AnymatchMatcher` is not an array — it is
|
|
157
|
+
* a string, a RegExp, a predicate function, or an array of those. Typing it as an array here is
|
|
158
|
+
* the narrowing that made the whole plugin unassignable to Vite's `Plugin`, and it also invited a
|
|
159
|
+
* runtime defect: see `mergeIgnored`.
|
|
160
|
+
*/
|
|
161
|
+
server?: {
|
|
162
|
+
watch?: {
|
|
163
|
+
ignored?: unknown;
|
|
164
|
+
} | null | undefined;
|
|
165
|
+
} | undefined;
|
|
166
|
+
/**
|
|
167
|
+
* Vitest's block, when this config belongs to a Vitest run. Read ONLY to spot browser mode — see
|
|
168
|
+
* `isVitestBrowserServer`. Typed as `unknown` because it is Vitest's shape, not Vite's, and this
|
|
169
|
+
* plugin has no business asserting anything about the rest of it.
|
|
170
|
+
*/
|
|
171
|
+
test?: unknown;
|
|
172
|
+
}
|
|
128
173
|
/** Structural Vite plugin shape — avoids a hard dependency on `vite` while staying assignable to its `Plugin`. */
|
|
129
174
|
export interface ReticleVitePlugin {
|
|
130
175
|
name: string;
|
|
131
176
|
/**
|
|
132
177
|
* Vite's `config` hook. Used to declare the SDK's CJS runtime deps for pre-bundling — see the
|
|
133
178
|
* implementation for why omitting them makes the whole SDK fail to load on linked setups.
|
|
179
|
+
*
|
|
180
|
+
* METHOD syntax, not a property, and every field it reads is optional-and-nullable. Both halves
|
|
181
|
+
* are load-bearing, and both are the contravariance trap this file's sibling test documents:
|
|
182
|
+
* a property's parameter is checked strictly, so a narrow stand-in REJECTS the wider `UserConfig`
|
|
183
|
+
* Vite actually passes. `server.watch` is where it bit — Vite types it `WatchOptions | null`,
|
|
184
|
+
* `null` being how a config turns the watcher off, and SvelteKit's template does exactly that.
|
|
134
185
|
*/
|
|
135
|
-
config
|
|
136
|
-
optimizeDeps?: {
|
|
137
|
-
include?: string[];
|
|
138
|
-
/** Whichever key the app used — the plugin reads both and writes the one this Vite wants. */
|
|
139
|
-
esbuildOptions?: Record<string, unknown>;
|
|
140
|
-
rolldownOptions?: Record<string, unknown>;
|
|
141
|
-
};
|
|
142
|
-
define?: Record<string, string>;
|
|
143
|
-
root?: string;
|
|
144
|
-
server?: {
|
|
145
|
-
watch?: {
|
|
146
|
-
ignored?: (string | RegExp)[];
|
|
147
|
-
};
|
|
148
|
-
};
|
|
149
|
-
}) => {
|
|
186
|
+
config?(config: ViteUserConfigLike): {
|
|
150
187
|
optimizeDeps: {
|
|
151
188
|
include: string[];
|
|
152
189
|
[optionsKey: string]: unknown;
|
|
@@ -154,7 +191,7 @@ export interface ReticleVitePlugin {
|
|
|
154
191
|
define: Record<string, string>;
|
|
155
192
|
server: {
|
|
156
193
|
watch: {
|
|
157
|
-
ignored:
|
|
194
|
+
ignored: WatchPattern[];
|
|
158
195
|
};
|
|
159
196
|
};
|
|
160
197
|
};
|
|
@@ -172,6 +209,9 @@ export interface ReticleVitePlugin {
|
|
|
172
209
|
configResolved?: (config: {
|
|
173
210
|
root?: string;
|
|
174
211
|
command?: string;
|
|
212
|
+
base?: string;
|
|
213
|
+
/** Vitest's block, read only to spot browser mode. See isVitestBrowserServer. */
|
|
214
|
+
test?: unknown;
|
|
175
215
|
}) => void;
|
|
176
216
|
/** Dev-server hook: keeps the served connect module from outliving the token it was built without. */
|
|
177
217
|
configureServer?: (server: ViteDevServerLike) => void;
|
|
@@ -179,6 +219,9 @@ export interface ReticleVitePlugin {
|
|
|
179
219
|
buildEnd?: () => void;
|
|
180
220
|
/** Runs the dev-mode injection check immediately. Test seam for the deferred timer. */
|
|
181
221
|
checkInjectedForTest?: () => void;
|
|
222
|
+
checkHtmlHookForTest?: () => void;
|
|
223
|
+
/** The post-condition watch itself, so a test drives the real predicate and not a copy of it. */
|
|
224
|
+
injectionWatchForTest?: InjectionWatch;
|
|
182
225
|
}
|
|
183
226
|
/**
|
|
184
227
|
* The slice of Vite's dev server this plugin touches, structurally — so `vite` stays a peer the
|
|
@@ -208,6 +251,9 @@ export interface ViteDevServerLike {
|
|
|
208
251
|
middlewares: {
|
|
209
252
|
use(handler: (req: {
|
|
210
253
|
url?: string | undefined;
|
|
254
|
+
headers?: {
|
|
255
|
+
accept?: string | undefined;
|
|
256
|
+
} | undefined;
|
|
211
257
|
}, res: unknown, next: () => void) => void): void;
|
|
212
258
|
};
|
|
213
259
|
moduleGraph: {
|
|
@@ -235,10 +281,9 @@ export declare function readPairingToken(): string | undefined;
|
|
|
235
281
|
/**
|
|
236
282
|
* The conventional app-side dev module: `registerStore` / `registerCapabilities` live here.
|
|
237
283
|
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
* Convention costs one `existsSync` and leaves their entry untouched.
|
|
284
|
+
* Imported by CONVENTION rather than by patching the app's entry file: the connect is injected into
|
|
285
|
+
* a virtual module, so the alternative is `init` editing `src/main.tsx` — a file the user owns — for
|
|
286
|
+
* something that is opt-in enrichment. Convention costs one `existsSync`.
|
|
242
287
|
*/
|
|
243
288
|
export declare const RETICLE_DEV_MODULE_CANDIDATES: readonly ["src/reticle-dev.ts", "src/reticle-dev.js", "src/reticle-dev.tsx", "src/reticle-dev.jsx"];
|
|
244
289
|
/** The app's dev module, as an importable path — or null when the app has none. */
|
|
@@ -246,14 +291,11 @@ export declare function findDevModule(root: string, exists: (p: string) => boole
|
|
|
246
291
|
/**
|
|
247
292
|
* Which SDK package this app actually has, and whether `install()` applies.
|
|
248
293
|
*
|
|
249
|
-
* The injected connect
|
|
294
|
+
* The injected connect must NOT name `@reticlehq/react` unconditionally. That is right for a React
|
|
250
295
|
* app and fatal for any other: `reticle init` gives a Vue or Svelte codebase the framework-neutral
|
|
251
296
|
* `@reticlehq/browser` — deliberately, because a package named `@reticlehq/react` with `react` in
|
|
252
|
-
* its peers has no business in a Vue app — and the injected import then
|
|
253
|
-
* installed, so nothing connects and the page reports no session with no obvious cause.
|
|
254
|
-
*
|
|
255
|
-
* Measured end to end on a pristine `npm create vite --template vue` app: init wrote every file
|
|
256
|
-
* correctly and the tab never dialled the daemon, because of this one specifier.
|
|
297
|
+
* its peers has no business in a Vue app — and the injected import would then name a package that is
|
|
298
|
+
* not installed, so nothing connects and the page reports no session with no obvious cause.
|
|
257
299
|
*
|
|
258
300
|
* The React kit WINS when both resolve: it is a superset (it re-exports the sensor and adds the
|
|
259
301
|
* adapter), so an app that has it wants component identity. `install()` is the adapter's alone and
|
|
@@ -288,4 +330,3 @@ export declare function connectModuleSource(options: ReticleVitePluginOptions, d
|
|
|
288
330
|
*/
|
|
289
331
|
export declare const JOURNAL_IGNORE: RegExp;
|
|
290
332
|
export declare function reticle(options?: ReticleVitePluginOptions): ReticleVitePlugin;
|
|
291
|
-
export {};
|