@playcademy/vite-plugin 0.1.12 → 0.1.14

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.js CHANGED
@@ -124995,7 +124995,7 @@ var logger = (fn = console.log) => {
124995
124995
  };
124996
124996
  var package_default = {
124997
124997
  name: "@playcademy/sandbox",
124998
- version: "0.1.1",
124998
+ version: "0.1.3",
124999
124999
  description: "Local development server for Playcademy game development",
125000
125000
  type: "module",
125001
125001
  exports: {
@@ -125032,7 +125032,6 @@ var package_default = {
125032
125032
  dependencies: {
125033
125033
  "@electric-sql/pglite": "^0.3.2",
125034
125034
  "@hono/node-server": "^1.14.2",
125035
- "@playcademy/constants": "workspace:*",
125036
125035
  commander: "^12.1.0",
125037
125036
  "drizzle-kit": "^0.31.0",
125038
125037
  "drizzle-orm": "^0.42.0",
@@ -169636,6 +169635,92 @@ import {
169636
169635
  startPlaycademyDevServer,
169637
169636
  startPlaycademyHotReload
169638
169637
  } from "playcademy/utils";
169638
+
169639
+ // ../utils/src/port.ts
169640
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "node:fs";
169641
+ import { createServer } from "node:net";
169642
+ import { homedir } from "node:os";
169643
+ import { join as join3 } from "node:path";
169644
+ async function isPortAvailableOnHost(port, host) {
169645
+ return new Promise((resolve2) => {
169646
+ const server = createServer();
169647
+ server.once("error", () => {
169648
+ resolve2(false);
169649
+ });
169650
+ server.once("listening", () => {
169651
+ server.close();
169652
+ resolve2(true);
169653
+ });
169654
+ server.listen(port, host);
169655
+ });
169656
+ }
169657
+ async function findAvailablePort(startPort = 4321) {
169658
+ const ipv4AllAvailable = await isPortAvailableOnHost(startPort, "0.0.0.0");
169659
+ const ipv6AllAvailable = await isPortAvailableOnHost(startPort, "::");
169660
+ if (ipv4AllAvailable && ipv6AllAvailable) {
169661
+ return startPort;
169662
+ }
169663
+ return findAvailablePort(startPort + 1);
169664
+ }
169665
+ function getRegistryPath() {
169666
+ const home = homedir();
169667
+ const dir = join3(home, ".playcademy");
169668
+ if (!existsSync2(dir)) {
169669
+ mkdirSync2(dir, { recursive: true });
169670
+ }
169671
+ return join3(dir, ".proc");
169672
+ }
169673
+ function readRegistry() {
169674
+ const registryPath = getRegistryPath();
169675
+ if (!existsSync2(registryPath)) {
169676
+ return {};
169677
+ }
169678
+ try {
169679
+ const content = readFileSync(registryPath, "utf-8");
169680
+ return JSON.parse(content);
169681
+ } catch {
169682
+ return {};
169683
+ }
169684
+ }
169685
+ function writeRegistry(registry) {
169686
+ const registryPath = getRegistryPath();
169687
+ writeFileSync(registryPath, JSON.stringify(registry, null, 2), "utf-8");
169688
+ }
169689
+ function getServerKey(type, port) {
169690
+ return `${type}-${port}`;
169691
+ }
169692
+ function writeServerInfo(type, info2) {
169693
+ const registry = readRegistry();
169694
+ const key = getServerKey(type, info2.port);
169695
+ registry[key] = info2;
169696
+ writeRegistry(registry);
169697
+ }
169698
+ function cleanupServerInfo(type, projectRoot, pid) {
169699
+ const registry = readRegistry();
169700
+ const keysToRemove = [];
169701
+ for (const [key, info2] of Object.entries(registry)) {
169702
+ if (key.startsWith(`${type}-`)) {
169703
+ let matches = true;
169704
+ if (projectRoot && info2.projectRoot !== projectRoot) {
169705
+ matches = false;
169706
+ }
169707
+ if (pid !== undefined && info2.pid !== pid) {
169708
+ matches = false;
169709
+ }
169710
+ if (matches) {
169711
+ keysToRemove.push(key);
169712
+ }
169713
+ }
169714
+ }
169715
+ for (const key of keysToRemove) {
169716
+ delete registry[key];
169717
+ }
169718
+ if (keysToRemove.length > 0) {
169719
+ writeRegistry(registry);
169720
+ }
169721
+ }
169722
+
169723
+ // src/lib/cli-server.ts
169639
169724
  async function tryLoadConfig(viteConfig) {
169640
169725
  try {
169641
169726
  return await loadConfig2();
@@ -169689,19 +169774,22 @@ function setupHotReload(serverRef, options, viteConfig) {
169689
169774
  return () => watcher.close();
169690
169775
  }
169691
169776
  async function setupCliDevServer(options) {
169692
- const { port, viteConfig, platformUrl } = options;
169777
+ const { preferredPort, viteConfig, platformUrl } = options;
169693
169778
  const config2 = await tryLoadConfig(viteConfig);
169694
169779
  if (!config2)
169695
169780
  return null;
169696
169781
  if (!needsCliDevServer(config2))
169697
169782
  return null;
169698
169783
  try {
169784
+ const port = await findAvailablePort(preferredPort);
169699
169785
  const serverOptions = { port, config: config2, platformUrl };
169700
169786
  const serverRef = { current: await startServer2(serverOptions) };
169701
169787
  const stopHotReload = setupHotReload(serverRef, serverOptions, viteConfig);
169702
169788
  return {
169703
169789
  server: serverRef.current,
169704
- stopHotReload
169790
+ port,
169791
+ stopHotReload,
169792
+ cleanup: () => cleanupServerInfo("backend", viteConfig.root, process.pid)
169705
169793
  };
169706
169794
  } catch (error2) {
169707
169795
  viteConfig.logger.error(`Failed to start game backend: ${error2 instanceof Error ? error2.message : String(error2)}`);
@@ -169769,20 +169857,6 @@ function formatNumberWithCommas(numStr) {
169769
169857
  parts2[0] = parts2[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
169770
169858
  return parts2.join(".");
169771
169859
  }
169772
- async function findAvailablePort(startPort = 4321) {
169773
- const { createServer } = await import("node:net");
169774
- return new Promise((resolve2, reject) => {
169775
- const server = createServer();
169776
- server.listen(startPort, () => {
169777
- const address = server.address();
169778
- const port = address && typeof address === "object" ? address.port : startPort;
169779
- server.close(() => resolve2(port));
169780
- });
169781
- server.on("error", () => {
169782
- findAvailablePort(startPort + 1).then(resolve2).catch(reject);
169783
- });
169784
- });
169785
- }
169786
169860
 
169787
169861
  // src/lib/manifest.ts
169788
169862
  var LOG_LINE_TOTAL_WIDTH = 60;
@@ -169924,6 +169998,7 @@ async function startSandbox(viteConfig, autoStart = true, options = {}) {
169924
169998
  return {
169925
169999
  baseUrl,
169926
170000
  realtimeUrl: deriveRealtimeUrl(baseUrl),
170001
+ port: DEFAULT_PORTS.SANDBOX,
169927
170002
  project: null,
169928
170003
  cleanup: () => {}
169929
170004
  };
@@ -169942,6 +170017,13 @@ async function startSandbox(viteConfig, autoStart = true, options = {}) {
169942
170017
  realtime: { enabled: false, port: realtimePort },
169943
170018
  timeback: timebackOptions
169944
170019
  });
170020
+ writeServerInfo("sandbox", {
170021
+ pid: process.pid,
170022
+ port: sandboxPort,
170023
+ url: baseUrl,
170024
+ startedAt: Date.now(),
170025
+ projectRoot: viteConfig.root
170026
+ });
169945
170027
  if (!quiet) {
169946
170028
  setTimeout(() => {
169947
170029
  printSandboxInfo(viteConfig, sandboxPort, realtimePort, projectInfo);
@@ -169950,11 +170032,12 @@ async function startSandbox(viteConfig, autoStart = true, options = {}) {
169950
170032
  return {
169951
170033
  baseUrl,
169952
170034
  realtimeUrl,
170035
+ port: sandboxPort,
169953
170036
  project: projectInfo,
169954
170037
  cleanup: () => {
170038
+ cleanupServerInfo("sandbox", viteConfig.root, process.pid);
169955
170039
  if (server && typeof server.stop === "function") {
169956
170040
  server.stop();
169957
- viteConfig.logger.info(import_picocolors4.default.yellow("[Playcademy] Sandbox server stopped"));
169958
170041
  }
169959
170042
  }
169960
170043
  };
@@ -169963,6 +170046,7 @@ async function startSandbox(viteConfig, autoStart = true, options = {}) {
169963
170046
  return {
169964
170047
  baseUrl: `http://localhost:${DEFAULT_PORTS.SANDBOX}`,
169965
170048
  realtimeUrl: "ws://localhost:4322",
170049
+ port: DEFAULT_PORTS.SANDBOX,
169966
170050
  project: null,
169967
170051
  cleanup: () => {}
169968
170052
  };
@@ -170435,6 +170519,27 @@ function devServerMiddleware(server, sandbox, gameUrl, showBadge) {
170435
170519
  }
170436
170520
 
170437
170521
  // src/index.ts
170522
+ function setupDevServerCleanup(getSandbox, getBackend) {
170523
+ let isShuttingDown = false;
170524
+ const cleanup = () => {
170525
+ if (isShuttingDown)
170526
+ return;
170527
+ isShuttingDown = true;
170528
+ const sandbox = getSandbox();
170529
+ const backend = getBackend();
170530
+ if (sandbox)
170531
+ sandbox.cleanup();
170532
+ if (backend) {
170533
+ backend.server.dispose();
170534
+ backend.stopHotReload();
170535
+ backend.cleanup();
170536
+ }
170537
+ process.exit(0);
170538
+ };
170539
+ process.on("SIGINT", cleanup);
170540
+ process.on("SIGTERM", cleanup);
170541
+ return cleanup;
170542
+ }
170438
170543
  function playcademy(options = {}) {
170439
170544
  let viteConfig;
170440
170545
  let currentBuildOutputs = {};
@@ -170462,34 +170567,34 @@ function playcademy(options = {}) {
170462
170567
  currentBuildOutputs = {};
170463
170568
  },
170464
170569
  async configureServer(server) {
170570
+ const serverRefs = {
170571
+ sandbox: null,
170572
+ backend: null
170573
+ };
170574
+ const cleanup = setupDevServerCleanup(() => serverRefs.sandbox, () => serverRefs.backend);
170465
170575
  const sandbox = await startSandbox(viteConfig, _options.startSandbox, {
170466
170576
  verbose: _options.verbose,
170467
170577
  customUrl: _options.sandboxUrl,
170468
170578
  quiet: true
170469
170579
  });
170580
+ serverRefs.sandbox = sandbox;
170470
170581
  const backend = await setupCliDevServer({
170471
- port: DEFAULT_PORTS2.BACKEND,
170582
+ preferredPort: DEFAULT_PORTS2.BACKEND,
170472
170583
  viteConfig,
170473
170584
  platformUrl: sandbox.baseUrl
170474
170585
  });
170586
+ serverRefs.backend = backend;
170475
170587
  if (sandbox.project) {
170476
- const gameUrl = backend ? `http://localhost:${DEFAULT_PORTS2.BACKEND}` : undefined;
170588
+ const gameUrl = backend ? `http://localhost:${backend.port}` : undefined;
170477
170589
  devServerMiddleware(server, sandbox, gameUrl, _options.showBadge);
170478
170590
  }
170479
170591
  server.httpServer?.once("listening", () => {
170480
170592
  setTimeout(() => {
170481
170593
  const projectInfo = extractProjectInfo(viteConfig);
170482
- printBanner(viteConfig, {
170483
- sandbox: DEFAULT_PORTS2.SANDBOX,
170484
- backend: backend ? DEFAULT_PORTS2.BACKEND : undefined
170485
- }, projectInfo, version3);
170594
+ printBanner(viteConfig, { sandbox: sandbox.port, backend: backend?.port }, projectInfo, version3);
170486
170595
  }, 100);
170487
170596
  });
170488
- server.httpServer?.on("close", () => {
170489
- sandbox.cleanup();
170490
- backend?.server.dispose();
170491
- backend?.stopHotReload();
170492
- });
170597
+ server.httpServer?.on("close", cleanup);
170493
170598
  },
170494
170599
  async writeBundle() {
170495
170600
  const outDir = viteConfig.build.outDir || path4.join(process.cwd(), "dist");
package/dist/types.d.ts CHANGED
@@ -72,6 +72,7 @@ export interface ManifestOptions {
72
72
  export interface SandboxManager {
73
73
  baseUrl: string;
74
74
  realtimeUrl: string;
75
+ port: number;
75
76
  project: ProjectInfo | null;
76
77
  cleanup: () => void;
77
78
  }
@@ -82,13 +83,15 @@ export interface CliServerManager {
82
83
  server: {
83
84
  dispose: () => Promise<void>;
84
85
  };
86
+ port: number;
85
87
  stopHotReload: () => void;
88
+ cleanup: () => void;
86
89
  }
87
90
  /**
88
91
  * Options for setting up the CLI dev server
89
92
  */
90
93
  export interface CliDevServerOptions {
91
- port: number;
94
+ preferredPort: number;
92
95
  viteConfig: ResolvedConfig;
93
96
  platformUrl?: string;
94
97
  }
package/dist/utils.d.ts CHANGED
@@ -5,4 +5,3 @@ import type { ResolvedConfig } from 'vite';
5
5
  import type { ProjectInfo } from './types';
6
6
  export declare function extractProjectInfo(viteConfig: ResolvedConfig): ProjectInfo;
7
7
  export declare function formatNumberWithCommas(numStr: string): string;
8
- export declare function findAvailablePort(startPort?: number): Promise<number>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/vite-plugin",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -25,11 +25,11 @@
25
25
  "dependencies": {
26
26
  "archiver": "^7.0.1",
27
27
  "picocolors": "^1.1.1",
28
- "playcademy": "0.13.2"
28
+ "playcademy": "0.13.5"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@inquirer/prompts": "^7.8.6",
32
- "@playcademy/sandbox": "0.1.1",
32
+ "@playcademy/sandbox": "0.1.3",
33
33
  "@types/archiver": "^6.0.3",
34
34
  "@types/bun": "latest",
35
35
  "yocto-spinner": "^0.2.2"