@omniviewdev/vite-plugin 0.4.1 → 0.5.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 CHANGED
@@ -32,11 +32,12 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  SHARED_PACKAGES: () => SHARED_PACKAGES,
34
34
  default: () => index_default,
35
+ managedViteFeedback: () => managedViteFeedback,
35
36
  omniviewExternals: () => omniviewExternals,
36
37
  safeFilename: () => safeFilename
37
38
  });
38
39
  module.exports = __toCommonJS(index_exports);
39
- var import_node_path = __toESM(require("path"), 1);
40
+ var import_node_path3 = __toESM(require("path"), 1);
40
41
  var import_node_url = require("url");
41
42
 
42
43
  // src/sharedPackages.ts
@@ -92,17 +93,337 @@ function safeFilename(packageName) {
92
93
  return result;
93
94
  }
94
95
 
96
+ // src/workspace.ts
97
+ var import_node_fs = require("fs");
98
+ var import_node_path = __toESM(require("path"), 1);
99
+ function workspaceViteRoots(raw) {
100
+ if (raw === void 0) {
101
+ return void 0;
102
+ }
103
+ const roots = JSON.parse(raw);
104
+ if (!Array.isArray(roots) || roots.length === 0) {
105
+ throw new Error("OMNIVIEW_VITE_ALLOWED_ROOTS must be a nonempty JSON array");
106
+ }
107
+ return [...new Set(roots.map((root) => {
108
+ if (typeof root !== "string" || !import_node_path.default.isAbsolute(root) || root.includes("*") || root.includes("\0") || import_node_path.default.parse(root).root === root) {
109
+ throw new Error("Vite workspace roots must be explicit absolute repository directories");
110
+ }
111
+ const canonical = (0, import_node_fs.realpathSync)(root);
112
+ if (canonical !== import_node_path.default.resolve(root) || !(0, import_node_fs.statSync)(canonical).isDirectory()) {
113
+ throw new Error("Vite workspace roots must be canonical repository directories");
114
+ }
115
+ return canonical;
116
+ }))];
117
+ }
118
+ function workspaceVitePort(raw) {
119
+ if (raw === void 0) {
120
+ return void 0;
121
+ }
122
+ if (!/^[0-9]+$/.test(raw)) {
123
+ throw new Error("Owned Vite port must be an integer");
124
+ }
125
+ const port = Number(raw);
126
+ if (port < 1 || port > 65535) {
127
+ throw new Error("Owned Vite port is outside 1..65535");
128
+ }
129
+ return port;
130
+ }
131
+ function workspaceViteCacheDirectory(raw) {
132
+ if (raw === void 0) {
133
+ return void 0;
134
+ }
135
+ if (!import_node_path.default.isAbsolute(raw) || raw.includes("\0") || import_node_path.default.parse(raw).root === raw) {
136
+ throw new Error("Managed Vite cache must be an explicit absolute directory");
137
+ }
138
+ const canonical = (0, import_node_fs.realpathSync)(raw);
139
+ if (canonical !== import_node_path.default.resolve(raw) || !(0, import_node_fs.statSync)(canonical).isDirectory()) {
140
+ throw new Error("Managed Vite cache must be an existing canonical owned directory");
141
+ }
142
+ return canonical;
143
+ }
144
+
145
+ // src/feedback.ts
146
+ var import_node_child_process = require("child_process");
147
+ var import_node_fs2 = require("fs");
148
+ var import_node_path2 = __toESM(require("path"), 1);
149
+ var navigationTypes = { update: true, "full-reload": true, prune: true };
150
+ var maximumStateBytes = 64 * 1024;
151
+ var maximumStateSize = BigInt(maximumStateBytes);
152
+ function feedbackContext(raw) {
153
+ const value = JSON.parse(raw);
154
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
155
+ throw new Error("OMNIVIEW_VITE_FEEDBACK must be an explicit managed feedback context");
156
+ }
157
+ const context = value;
158
+ if (context.schemaVersion !== 1 || typeof context.workspaceID !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(context.workspaceID) || typeof context.generation !== "string" || !context.generation || context.generation.includes("\0") || typeof context.workspaceRoot !== "string" || !import_node_path2.default.isAbsolute(context.workspaceRoot) || context.workspaceRoot.includes("\0") || import_node_path2.default.parse(context.workspaceRoot).root === context.workspaceRoot || typeof context.file !== "string" || !import_node_path2.default.isAbsolute(context.file) || context.file.includes("\0") || import_node_path2.default.resolve(context.file) !== context.file) {
159
+ throw new Error("Managed Vite feedback requires versioned, explicit workspace and file ownership");
160
+ }
161
+ if ((0, import_node_fs2.realpathSync)(context.workspaceRoot) !== context.workspaceRoot || !(0, import_node_fs2.statSync)(context.workspaceRoot).isDirectory()) {
162
+ throw new Error("Managed Vite feedback workspace must be an existing canonical directory");
163
+ }
164
+ let authority;
165
+ if (context.authority !== void 0) {
166
+ if (!context.authority || typeof context.authority !== "object" || Array.isArray(context.authority)) {
167
+ throw new Error("Managed Vite feedback authority must be explicit supervisor ownership");
168
+ }
169
+ const value2 = context.authority;
170
+ if (typeof value2.executable !== "string" || !import_node_path2.default.isAbsolute(value2.executable) || value2.executable.includes("\0") || import_node_path2.default.resolve(value2.executable) !== value2.executable || (0, import_node_fs2.realpathSync)(value2.executable) !== value2.executable || !(0, import_node_fs2.lstatSync)(value2.executable).isFile() || !value2.identity || typeof value2.identity !== "object" || Array.isArray(value2.identity)) {
171
+ throw new Error("Managed Vite feedback authority requires its exact canonical supervisor executable");
172
+ }
173
+ const identity = value2.identity;
174
+ if (typeof identity.volume !== "string" || !/^[0-9]+$/.test(identity.volume) || typeof identity.fileID !== "string" || !/^[0-9a-f]{32}$/.test(identity.fileID)) {
175
+ throw new Error("Managed Vite feedback authority requires the full stable file identity");
176
+ }
177
+ authority = {
178
+ executable: value2.executable,
179
+ identity: { volume: identity.volume, fileID: identity.fileID }
180
+ };
181
+ }
182
+ return {
183
+ schemaVersion: 1,
184
+ workspaceID: context.workspaceID,
185
+ generation: context.generation,
186
+ workspaceRoot: context.workspaceRoot,
187
+ file: context.file,
188
+ authority
189
+ };
190
+ }
191
+ function readViteFeedbackAuthority(raw) {
192
+ try {
193
+ const context = feedbackContext(raw);
194
+ if (!context.authority) {
195
+ return true;
196
+ }
197
+ const output = (0, import_node_child_process.execFileSync)(context.authority.executable, ["vite-feedback-read", "--context", raw], {
198
+ encoding: "utf8",
199
+ shell: false,
200
+ windowsHide: true,
201
+ timeout: 2e3,
202
+ maxBuffer: 1024,
203
+ stdio: ["ignore", "pipe", "pipe"]
204
+ });
205
+ const result = JSON.parse(output);
206
+ if (!result || typeof result !== "object" || Array.isArray(result) || Object.keys(result).length !== 1) {
207
+ return true;
208
+ }
209
+ return result.held !== false;
210
+ } catch {
211
+ return true;
212
+ }
213
+ }
214
+ function privateFeedbackFile(stat) {
215
+ const owner = process.getuid?.();
216
+ return stat.isFile() && owner !== void 0 && stat.uid === BigInt(owner) && (stat.mode & 0o777n) === 0o600n;
217
+ }
218
+ function retainUnixFeedbackAuthority(context) {
219
+ const bytes = Buffer.alloc(maximumStateBytes + 1);
220
+ let identity;
221
+ function readHeld(captureIdentity = false) {
222
+ let descriptor;
223
+ try {
224
+ descriptor = (0, import_node_fs2.openSync)(context.file, import_node_fs2.constants.O_RDONLY | import_node_fs2.constants.O_NOFOLLOW | import_node_fs2.constants.O_NONBLOCK);
225
+ const stat = (0, import_node_fs2.fstatSync)(descriptor, { bigint: true });
226
+ if (!privateFeedbackFile(stat) || (0, import_node_fs2.realpathSync)(context.file) !== context.file) {
227
+ return true;
228
+ }
229
+ if (captureIdentity) {
230
+ identity = stat;
231
+ }
232
+ if (!identity || stat.dev !== identity.dev || stat.ino !== identity.ino) {
233
+ return true;
234
+ }
235
+ const linked = (0, import_node_fs2.lstatSync)(context.file, { bigint: true });
236
+ if (!privateFeedbackFile(linked) || linked.dev !== identity.dev || linked.ino !== identity.ino || stat.size < 1n || stat.size > maximumStateSize) {
237
+ return true;
238
+ }
239
+ const length = (0, import_node_fs2.readSync)(descriptor, bytes, 0, bytes.length, 0);
240
+ if (BigInt(length) !== stat.size) {
241
+ return true;
242
+ }
243
+ const state = JSON.parse(bytes.toString("utf8", 0, length));
244
+ if (!state || typeof state !== "object" || Array.isArray(state)) {
245
+ return true;
246
+ }
247
+ const value = state;
248
+ const after = (0, import_node_fs2.lstatSync)(context.file, { bigint: true });
249
+ return !privateFeedbackFile(after) || after.dev !== identity.dev || after.ino !== identity.ino || value.schemaVersion !== context.schemaVersion || value.workspaceID !== context.workspaceID || value.generation !== context.generation || value.workspaceRoot !== context.workspaceRoot || typeof value.held !== "boolean" || value.held;
250
+ } catch {
251
+ return true;
252
+ } finally {
253
+ if (descriptor !== void 0) {
254
+ (0, import_node_fs2.closeSync)(descriptor);
255
+ }
256
+ }
257
+ }
258
+ return { initiallyHeld: readHeld(true), readHeld };
259
+ }
260
+ function feedbackAuthorityReader(context, raw) {
261
+ if (process.platform !== "win32") {
262
+ return retainUnixFeedbackAuthority(context);
263
+ }
264
+ return {
265
+ initiallyHeld: readViteFeedbackAuthority(raw),
266
+ readHeld: () => readViteFeedbackAuthority(raw)
267
+ };
268
+ }
269
+ function attachManagedViteFeedback(server, raw = process.env.OMNIVIEW_VITE_FEEDBACK) {
270
+ if (raw === void 0) {
271
+ return;
272
+ }
273
+ const context = feedbackContext(raw);
274
+ if (process.platform === "win32" && !context.authority) {
275
+ throw new Error("Managed Vite feedback on Windows requires its supervisor file authority");
276
+ }
277
+ const httpServer = server.httpServer;
278
+ const hmr = typeof server.config.server.hmr === "object" ? server.config.server.hmr : void 0;
279
+ if (!httpServer || Boolean(hmr?.server && hmr.server !== httpServer) || Boolean(hmr?.port && hmr.port !== server.config.server.port)) {
280
+ throw new Error("Managed Vite feedback requires HMR on its owned HTTP listener");
281
+ }
282
+ const authority = feedbackAuthorityReader(context, raw);
283
+ let closed = false;
284
+ let watchFailed = false;
285
+ let watcher;
286
+ let held = authority.initiallyHeld;
287
+ const pendingPings = /* @__PURE__ */ new Set();
288
+ function readHeld() {
289
+ return closed || watchFailed || authority.readHeld();
290
+ }
291
+ const originalWebSocketSend = server.ws.send;
292
+ function reloadConnectedConsumers() {
293
+ if (server.ws.clients.size > 0) {
294
+ originalWebSocketSend.call(server.ws, { type: "full-reload", path: "*" });
295
+ }
296
+ }
297
+ function releasePendingHTTPPings() {
298
+ for (const response of pendingPings) {
299
+ held = readHeld();
300
+ if (held) {
301
+ return "held";
302
+ }
303
+ pendingPings.delete(response);
304
+ response.writeHead(204).end();
305
+ }
306
+ return "released";
307
+ }
308
+ function refreshReadinessAndReleaseConsumers() {
309
+ const previouslyHeld = held;
310
+ held = readHeld();
311
+ if (held) {
312
+ return "held";
313
+ }
314
+ if (!previouslyHeld) {
315
+ return "ready";
316
+ }
317
+ held = readHeld();
318
+ if (held) {
319
+ return "held";
320
+ }
321
+ reloadConnectedConsumers();
322
+ return releasePendingHTTPPings();
323
+ }
324
+ const environments = server.environments;
325
+ const channels = /* @__PURE__ */ new Set([server.ws]);
326
+ for (const environment of Object.values(environments ?? {})) {
327
+ channels.add(environment.hot);
328
+ }
329
+ for (const channel of channels) {
330
+ const original = channel.send;
331
+ channel.send = function(payload, data) {
332
+ if (payload && typeof payload === "object" && "type" in payload && typeof payload.type === "string" && navigationTypes[payload.type]) {
333
+ if (refreshReadinessAndReleaseConsumers() !== "ready" || server.ws.clients.size === 0) {
334
+ return;
335
+ }
336
+ }
337
+ original.call(this, payload, data);
338
+ };
339
+ }
340
+ server.middlewares.use((request, response, next) => {
341
+ if (request.headers.accept !== "text/x-vite-ping") {
342
+ next();
343
+ return;
344
+ }
345
+ if (refreshReadinessAndReleaseConsumers() !== "held") {
346
+ response.writeHead(204).end();
347
+ return;
348
+ }
349
+ pendingPings.add(response);
350
+ response.once("close", () => pendingPings.delete(response));
351
+ });
352
+ const upgradeHandlers = /* @__PURE__ */ new Map();
353
+ for (const listener of httpServer.rawListeners("upgrade")) {
354
+ const original = listener;
355
+ const gated = function(request, socket, head) {
356
+ if (request.headers["sec-websocket-protocol"] === "vite-ping") {
357
+ if (refreshReadinessAndReleaseConsumers() === "held") {
358
+ socket.destroy();
359
+ return;
360
+ }
361
+ }
362
+ original.call(this, request, socket, head);
363
+ };
364
+ upgradeHandlers.set(original, gated);
365
+ httpServer.off("upgrade", original);
366
+ httpServer.on("upgrade", gated);
367
+ }
368
+ const originalClose = server.close;
369
+ function cleanup() {
370
+ if (closed) {
371
+ return;
372
+ }
373
+ closed = true;
374
+ watcher?.close();
375
+ for (const response of pendingPings) {
376
+ response.destroy();
377
+ }
378
+ pendingPings.clear();
379
+ for (const [original, gated] of upgradeHandlers) {
380
+ httpServer.off("upgrade", gated);
381
+ httpServer.on("upgrade", original);
382
+ }
383
+ httpServer.off("close", cleanup);
384
+ server.close = originalClose;
385
+ }
386
+ server.close = async function() {
387
+ cleanup();
388
+ await originalClose.call(this);
389
+ };
390
+ httpServer.once("close", cleanup);
391
+ try {
392
+ watcher = (0, import_node_fs2.watch)(context.file, { persistent: false }, () => {
393
+ refreshReadinessAndReleaseConsumers();
394
+ });
395
+ watcher.on("error", () => {
396
+ watchFailed = true;
397
+ held = true;
398
+ });
399
+ refreshReadinessAndReleaseConsumers();
400
+ } catch {
401
+ watchFailed = true;
402
+ held = true;
403
+ }
404
+ }
405
+ function managedViteFeedback() {
406
+ return {
407
+ name: "omniview-managed-vite-feedback",
408
+ apply: "serve",
409
+ enforce: "pre",
410
+ configureServer(server) {
411
+ attachManagedViteFeedback(server);
412
+ }
413
+ };
414
+ }
415
+
95
416
  // src/index.ts
96
417
  var import_meta = {};
97
- var __dirname = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
418
+ var moduleDirectory = typeof __dirname === "string" ? __dirname : import_node_path3.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
98
419
  function getShimsDir() {
99
- const packageRoot = import_node_path.default.resolve(__dirname, "..");
100
- return import_node_path.default.join(packageRoot, "shims");
420
+ const packageRoot = import_node_path3.default.resolve(moduleDirectory, "..");
421
+ return import_node_path3.default.join(packageRoot, "shims");
101
422
  }
102
423
  function buildShimMap(shimsDir) {
103
424
  const map = /* @__PURE__ */ new Map();
104
425
  for (const pkg of SHARED_PACKAGES) {
105
- const shimFile = import_node_path.default.join(shimsDir, `${safeFilename(pkg)}.mjs`);
426
+ const shimFile = import_node_path3.default.join(shimsDir, `${safeFilename(pkg)}.mjs`);
106
427
  map.set(pkg, shimFile);
107
428
  }
108
429
  return map;
@@ -113,7 +434,7 @@ function omniviewExternals(options = {}) {
113
434
  const shimMap = buildShimMap(shimsDir);
114
435
  if (options.additionalShared) {
115
436
  for (const pkg of options.additionalShared) {
116
- const shimFile = import_node_path.default.join(shimsDir, `${safeFilename(pkg)}.mjs`);
437
+ const shimFile = import_node_path3.default.join(shimsDir, `${safeFilename(pkg)}.mjs`);
117
438
  shimMap.set(pkg, shimFile);
118
439
  }
119
440
  }
@@ -123,8 +444,55 @@ function omniviewExternals(options = {}) {
123
444
  enforce: "pre",
124
445
  // Run before other plugins (especially @vitejs/plugin-react)
125
446
  config(config, { command }) {
447
+ const cache = workspaceViteCacheDirectory(process.env.OMNIVIEW_VITE_CACHE_DIRECTORY);
448
+ if (cache) {
449
+ if (config.cacheDir && import_node_path3.default.resolve(config.root ?? process.cwd(), config.cacheDir) !== cache) {
450
+ throw new Error("Plugin Vite cache conflicts with its owned workspace cache");
451
+ }
452
+ config.cacheDir = cache;
453
+ }
454
+ const output = process.env.OMNIVIEW_BUILD_OUTPUT_DIRECTORY;
455
+ if (command === "build" && output) {
456
+ const root = import_node_path3.default.resolve(config.root ?? process.cwd());
457
+ const configured = config.build?.outDir && import_node_path3.default.resolve(root, config.build.outDir);
458
+ if (configured && configured !== import_node_path3.default.join(root, "dist") && configured !== import_node_path3.default.resolve(output)) {
459
+ throw new Error("Plugin distribution path conflicts with controlled workspace output");
460
+ }
461
+ config.build = { ...config.build, outDir: output };
462
+ }
126
463
  if (command === "serve") {
464
+ const roots = workspaceViteRoots(process.env.OMNIVIEW_VITE_ALLOWED_ROOTS);
465
+ const ownedPort = workspaceVitePort(process.env.OMNIVIEW_VITE_PORT);
466
+ if (roots) {
467
+ if (!ownedPort) {
468
+ throw new Error("Managed plugin Vite requires its owned OMNIVIEW_VITE_PORT");
469
+ }
470
+ config.server = config.server ?? {};
471
+ if (config.server.port !== void 0 && config.server.port !== ownedPort) {
472
+ throw new Error("Plugin Vite port conflicts with its owned workspace lease");
473
+ }
474
+ if (config.server.hmr === false || typeof config.server.hmr === "object" && (config.server.hmr.clientPort !== void 0 && config.server.hmr.clientPort !== ownedPort || config.server.hmr.port !== void 0 && config.server.hmr.port !== ownedPort || config.server.hmr.host !== void 0 && config.server.hmr.host !== "127.0.0.1" || config.server.hmr.protocol !== void 0 && config.server.hmr.protocol !== "ws")) {
475
+ throw new Error("Plugin Vite HMR conflicts with its owned loopback endpoint");
476
+ }
477
+ config.server.port = ownedPort;
478
+ config.server.strictPort = true;
479
+ config.server.fs = {
480
+ ...config.server.fs,
481
+ strict: true,
482
+ allow: [.../* @__PURE__ */ new Set([...config.server.fs?.allow ?? [config.root ?? process.cwd()], ...roots, shimsDir])]
483
+ };
484
+ config.server.hmr = {
485
+ ...typeof config.server.hmr === "object" ? config.server.hmr : {},
486
+ host: "127.0.0.1",
487
+ protocol: "ws",
488
+ clientPort: ownedPort
489
+ };
490
+ }
127
491
  config.optimizeDeps = config.optimizeDeps ?? {};
492
+ config.optimizeDeps.exclude = [.../* @__PURE__ */ new Set([...config.optimizeDeps.exclude ?? [], ...allPackages])];
493
+ if (roots) {
494
+ config.optimizeDeps.force = true;
495
+ }
128
496
  config.optimizeDeps.esbuildOptions = config.optimizeDeps.esbuildOptions ?? {};
129
497
  config.optimizeDeps.esbuildOptions.plugins = [
130
498
  ...config.optimizeDeps.esbuildOptions.plugins ?? [],
@@ -154,21 +522,41 @@ function omniviewExternals(options = {}) {
154
522
  } else if (typeof existing === "function") {
155
523
  const originalFn = existing;
156
524
  config.build.rollupOptions.external = (source, importer, isResolved) => {
157
- if (sharedSet.has(source)) return true;
525
+ if (sharedSet.has(source)) {
526
+ return true;
527
+ }
158
528
  return originalFn(source, importer, isResolved);
159
529
  };
160
530
  } else if (existing === void 0 || existing === null) {
161
531
  config.build.rollupOptions.external = [...allPackages];
162
532
  } else {
163
533
  config.build.rollupOptions.external = (source) => {
164
- if (sharedSet.has(source)) return true;
165
- if (typeof existing === "string") return source === existing;
166
- if (existing instanceof RegExp) return existing.test(source);
534
+ if (sharedSet.has(source)) {
535
+ return true;
536
+ }
537
+ if (typeof existing === "string") {
538
+ return source === existing;
539
+ }
540
+ if (existing instanceof RegExp) {
541
+ return existing.test(source);
542
+ }
167
543
  return false;
168
544
  };
169
545
  }
170
546
  }
171
547
  },
548
+ configResolved(config) {
549
+ if (config.command !== "serve" || !config.optimizeDeps.include) {
550
+ return;
551
+ }
552
+ config.optimizeDeps.include = config.optimizeDeps.include.filter((dependency) => {
553
+ const target = dependency.slice(dependency.lastIndexOf(">") + 1).trim();
554
+ return !sharedSet.has(target);
555
+ });
556
+ },
557
+ configureServer(server) {
558
+ attachManagedViteFeedback(server);
559
+ },
172
560
  resolveId(source) {
173
561
  if (sharedSet.has(source)) {
174
562
  const shimPath = shimMap.get(source);
@@ -184,6 +572,7 @@ var index_default = omniviewExternals;
184
572
  // Annotate the CommonJS export names for ESM import in node:
185
573
  0 && (module.exports = {
186
574
  SHARED_PACKAGES,
575
+ managedViteFeedback,
187
576
  omniviewExternals,
188
577
  safeFilename
189
578
  });
package/dist/index.d.cts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
+ import { EventEmitter } from 'node:events';
3
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
4
 
3
5
  /**
4
6
  * The canonical list of package names shared between the Omniview host app
@@ -37,7 +39,42 @@ declare const SHARED_PACKAGES: readonly string[];
37
39
  */
38
40
  declare function safeFilename(packageName: string): string;
39
41
 
40
- interface OmniviewExternalsOptions {
42
+ type FeedbackChannel = {
43
+ send(payload: unknown, data?: unknown): void;
44
+ };
45
+ type ManagedFeedbackServer = {
46
+ config: {
47
+ server: {
48
+ port?: number;
49
+ hmr?: boolean | {
50
+ server?: EventEmitter;
51
+ port?: number;
52
+ };
53
+ };
54
+ };
55
+ httpServer: EventEmitter | null;
56
+ ws: FeedbackChannel & {
57
+ readonly clients: {
58
+ readonly size: number;
59
+ };
60
+ };
61
+ middlewares: {
62
+ use(handler: (request: IncomingMessage, response: ServerResponse, next: () => void) => void): unknown;
63
+ };
64
+ environments?: Record<string, {
65
+ hot: FeedbackChannel;
66
+ }>;
67
+ close(): Promise<void>;
68
+ };
69
+ /** Shared host entry point; plugin Vite attaches the identical barrier itself. */
70
+ declare function managedViteFeedback(): {
71
+ name: string;
72
+ apply: "serve";
73
+ enforce: "pre";
74
+ configureServer(server: ManagedFeedbackServer): void;
75
+ };
76
+
77
+ type OmniviewExternalsOptions = {
41
78
  /**
42
79
  * Additional package names to treat as shared. These are appended to the
43
80
  * built-in SHARED_PACKAGES list. You must also ensure shim files exist for
@@ -49,7 +86,7 @@ interface OmniviewExternalsOptions {
49
86
  * inside this package.
50
87
  */
51
88
  shimsDir?: string;
52
- }
89
+ };
53
90
  /**
54
91
  * Vite plugin that redirects imports of shared dependencies to shim files
55
92
  * that re-export from window.__OMNIVIEW_SHARED__.
@@ -79,4 +116,4 @@ interface OmniviewExternalsOptions {
79
116
  */
80
117
  declare function omniviewExternals(options?: OmniviewExternalsOptions): Plugin;
81
118
 
82
- export { type OmniviewExternalsOptions, SHARED_PACKAGES, omniviewExternals as default, omniviewExternals, safeFilename };
119
+ export { type OmniviewExternalsOptions, SHARED_PACKAGES, omniviewExternals as default, managedViteFeedback, omniviewExternals, safeFilename };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
+ import { EventEmitter } from 'node:events';
3
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
4
 
3
5
  /**
4
6
  * The canonical list of package names shared between the Omniview host app
@@ -37,7 +39,42 @@ declare const SHARED_PACKAGES: readonly string[];
37
39
  */
38
40
  declare function safeFilename(packageName: string): string;
39
41
 
40
- interface OmniviewExternalsOptions {
42
+ type FeedbackChannel = {
43
+ send(payload: unknown, data?: unknown): void;
44
+ };
45
+ type ManagedFeedbackServer = {
46
+ config: {
47
+ server: {
48
+ port?: number;
49
+ hmr?: boolean | {
50
+ server?: EventEmitter;
51
+ port?: number;
52
+ };
53
+ };
54
+ };
55
+ httpServer: EventEmitter | null;
56
+ ws: FeedbackChannel & {
57
+ readonly clients: {
58
+ readonly size: number;
59
+ };
60
+ };
61
+ middlewares: {
62
+ use(handler: (request: IncomingMessage, response: ServerResponse, next: () => void) => void): unknown;
63
+ };
64
+ environments?: Record<string, {
65
+ hot: FeedbackChannel;
66
+ }>;
67
+ close(): Promise<void>;
68
+ };
69
+ /** Shared host entry point; plugin Vite attaches the identical barrier itself. */
70
+ declare function managedViteFeedback(): {
71
+ name: string;
72
+ apply: "serve";
73
+ enforce: "pre";
74
+ configureServer(server: ManagedFeedbackServer): void;
75
+ };
76
+
77
+ type OmniviewExternalsOptions = {
41
78
  /**
42
79
  * Additional package names to treat as shared. These are appended to the
43
80
  * built-in SHARED_PACKAGES list. You must also ensure shim files exist for
@@ -49,7 +86,7 @@ interface OmniviewExternalsOptions {
49
86
  * inside this package.
50
87
  */
51
88
  shimsDir?: string;
52
- }
89
+ };
53
90
  /**
54
91
  * Vite plugin that redirects imports of shared dependencies to shim files
55
92
  * that re-export from window.__OMNIVIEW_SHARED__.
@@ -79,4 +116,4 @@ interface OmniviewExternalsOptions {
79
116
  */
80
117
  declare function omniviewExternals(options?: OmniviewExternalsOptions): Plugin;
81
118
 
82
- export { type OmniviewExternalsOptions, SHARED_PACKAGES, omniviewExternals as default, omniviewExternals, safeFilename };
119
+ export { type OmniviewExternalsOptions, SHARED_PACKAGES, omniviewExternals as default, managedViteFeedback, omniviewExternals, safeFilename };