@joystick.js/cli-canary 0.0.0-canary.2138 → 0.0.0-canary.2139

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.
@@ -1,11 +1,12 @@
1
- import l from"chalk";import N from"child_process";import $ from"fs";import"os";import O,{dirname as j}from"path";import{fileURLToPath as R}from"url";import I from"util";import m from"./check_if_port_occupied.js";import i from"../cli_log.js";import d from"./get_database_process_ids.js";import H from"../get_platform_safe_path.js";import g from"../kill_port_process.js";import y from"../load_settings.js";import C from"../loader.js";import f from"../path_exists.js";import x from"../required_files.js";import M from"./start_app_server.js";import V from"./start_databases.js";import A from"./start_hmr_server.js";import P from"./watch_for_changes/index.js";import q from"../constants.js";import b from"./kill_process_ids.js";import L,{run_tests_integrated as k}from"./run_tests.js";import G from"../debounce.js";import J from"./databases/download_database_binary.js";const{stat:U}=$.promises,F=I.promisify(N.exec),p=parseInt(process?.version?.split(".")[0]?.replace("v",""),10),B=R(import.meta.url),_=j(B),h=[];let w=null,E=!1,u=!1;const n=async()=>{if(E&&u){if(n.running)return;n.running=!0,setTimeout(async()=>{console.log("Running tests...");try{await k({__dirname:_})}catch(s){console.error("Error running integrated tests:",s)}finally{n.running=!1}},2e3)}},S=async(s={})=>{await m(1977)&&await g(1977),setTimeout(async()=>{try{await D({environment:"test",port:1977,watch:!1,imports:s?.imports||[],_is_test_server:!0})}catch(r){console.error("Error starting test server:",r)}},100)},X=()=>{w&&(w.kill(),w=null),u=!1},z=()=>{E=!1,u=!1,n.running=!1},Cs=async(s=!1)=>{const t=d();await L({watch:s,__dirname:_,process_ids:[...h,...t],cleanup_process:process.cleanup_process})},K=(s=[],t=0,r="")=>{const c=["--no-warnings"];t<19&&c.push("--experimental-specifier-resolution=node");const e=N.fork(O.resolve(`${r}/cleanup.js`),[],{detached:!0,silent:!0});process.cleanup_process=e,process.on("SIGINT",async()=>{const a=d();e.send(JSON.stringify({process_ids:[...s,...a]})),process.exit()}),process.on("SIGTERM",async()=>{const a=d();e.send(JSON.stringify({process_ids:[...s,...a]})),process.exit()})},Q=async(s=[])=>{const t=s?.find(o=>o?.path?.match(q.SETTINGS_FILE_NAME_REGEX)?.length>0),r=s?.find(o=>o?.path?.includes("i18n")),c=s?.find(o=>o?.path?.includes("index.html")),e=s?.find(o=>o?.path?.includes("index.css")||o?.path?.includes("css/")),a=s?.find(o=>o?.path?.includes("index.client.js"));process.hmr_server_process.send(JSON.stringify({type:"FILE_CHANGE",settings:t?await y(process.env.NODE_ENV):null,i18n_change:!!r,index_html_change:!!c,index_css_change:!!e,index_client_change:!!a}))},W=(s=0,t=!1,r={},c=[],e=!1)=>{process.hmr_server_process.on("message",async a=>{["HAS_HMR_CONNECTIONS","HAS_NO_HMR_CONNECTIONS","HMR_UPDATE_COMPLETE"].includes(a?.type)||process.loader.print(a),a?.type==="HAS_HMR_CONNECTIONS"&&(process.hmr_server_process.has_connections=!0),a?.type==="HAS_NO_HMR_CONNECTIONS"&&(process.hmr_server_process.has_connections=!1),a?.type==="HMR_UPDATE_COMPLETE"&&process.app_server_process&&!process.app_server_restarting&&(process.app_server_restarting=!0,T(s,t,r,c,e))})},Y=()=>{process.hmr_server_process.on("error",s=>{i(s.toString(),{level:"danger",docs:"https://github.com/cheatcode/joystick"})}),process.hmr_server_process.stdout.on("data",s=>{console.log(s.toString())}),process.hmr_server_process.stderr.on("data",s=>{i(s.toString(),{level:"danger",docs:"https://github.com/cheatcode/joystick"})})},Z=(s=0,t="",r=!1,c={},e=[],a=!1)=>{process.hmr_server_process=A(s,t),h.push(process.hmr_server_process?.pid),Y(),W(s,r,c,e,a)},ss=async(s={})=>{const t=await y(process.env.NODE_ENV),r=t?.config?.databases?JSON.stringify(t?.config?.databases):"",c=s?.config?.databases?JSON.stringify(s?.config?.databases):"";return r!==c},T=async(s=0,t=!1,r=null,c=[],e=!1)=>{G(async()=>{if(await ss(r)){const o=d();i(`Database configuration has changed in settings.${process.env.NODE_ENV}.json. Please restart your app to add, change, or remove databases.`,{level:"danger",docs:"https://cheatcode.co/docs/joystick/structure"}),b([process.hmr_server_process?.pid,process.app_server_process?.pid,...o]),process.exit(0)}else e&&(z(),X()),b([...process.app_server_process.external_process_ids||[]]),await g(process.env.PORT),v(s,t,c,e),e&&await S({imports:c||[]})},300)},es=(s=!1,t=!1,r=!1)=>{process.app_server_process.external_process_ids=[],process.app_server_process.on("message",c=>{c?.external_process_id&&(process.app_server_process.external_process_ids=[...process.app_server_process.external_process_ids||[],c?.external_process_id])}),process.app_server_process.on("error",c=>{r||i(c.toString(),{level:"danger",docs:"https://github.com/cheatcode/joystick"})}),process.app_server_process.stdout.on("data",async c=>{const e=c.toString(),a=e.includes("App running at:");r||(e&&a&&process.env.NODE_ENV!=="test"&&process.loader.print(e),e&&!a&&!e.includes("BUILD_ERROR")&&console.log(e),e&&a&&t&&process.env.NODE_ENV!=="test"&&(E=!0,n()),e&&a&&process.env.NODE_ENV==="test"&&(u=!0,n()))}),process.app_server_process.stderr.on("data",c=>{r||i(c.toString(),{level:"danger",docs:"https://cheatcode.co/docs/joystick"})})},v=(s=0,t=!1,r=[],c=!1,e=!1)=>{process.app_server_process=M(s,t,r),h.push(process.app_server_process?.pid),es(t,c,e),process.app_server_restarting=!1},ts=async(s={})=>{const t=s?.config?.databases?.map((r={})=>r?.provider);for(let r=0;r<t?.length;r+=1){const c=t[r];await J(c)}},rs=(s={},t=2600)=>{process.title=s?.environment==="test"?"joystick_test":"joystick",process.project_folder=O.basename(process.cwd()),process.loader=new C,process.env.LOGS_PATH=s?.logs||null,process.env.NODE_ENV=s?.environment||"development",process.env.PORT=t,process.env.IS_DEBUG_MODE=s?.debug},cs=(s=2600)=>{i(`Port ${s} is already occupied. To start Joystick on this port, clear it and try again.`,{level:"danger"}),process.exit(0)},as=(s=2600)=>parseInt(s||2600,10),os=async()=>{const s=H(`${process.cwd()}/.joystick/build`);await f(s)&&await F(`${process.platform==="win32"?"rmdir /s /q":"rm -rf"} ${s}`)},is=async()=>{const s=[];for(let t=0;t<x?.length;t+=1){const r=x[t],c=await f(`${process.cwd()}/${r.path}`),e=c&&await U(`${process.cwd()}/${r.path}`);r&&r.type==="file"&&(!c||c&&!e.isFile())&&s.push({type:"file",path:r.path}),r&&r.type==="directory"&&(!c||c&&!e.isDirectory())&&s.push({type:"directory",path:r.path})}if(s?.length>0){const t=s?.filter(e=>e.type==="file"),r=s?.filter(e=>e.type==="directory");let c=`The following paths are missing and required in a Joystick project:
1
+ import _ from"chalk";import y from"child_process";import b from"fs";import"os";import w,{dirname as k}from"path";import{fileURLToPath as S}from"url";import T from"util";import f from"./check_if_port_occupied.js";import i from"../cli_log.js";import d from"./get_database_process_ids.js";import D from"../get_platform_safe_path.js";import m from"../kill_port_process.js";import g from"../load_settings.js";import $ from"../loader.js";import l from"../path_exists.js";import E from"../required_files.js";import j from"./start_app_server.js";import R from"./start_databases.js";import I from"./start_hmr_server.js";import H from"./watch_for_changes/index.js";import C from"../constants.js";import N from"./kill_process_ids.js";import M,{run_tests_integrated as v}from"./run_tests.js";import V from"../debounce.js";import A from"./databases/download_database_binary.js";const{stat:P}=b.promises,q=T.promisify(y.exec),n=parseInt(process?.version?.split(".")[0]?.replace("v",""),10),L=S(import.meta.url),p=k(L),h=[],G=async(s=!1)=>{const t=d();await M({watch:s,__dirname:p,process_ids:[...h,...t],cleanup_process:process.cleanup_process})},J=(s=[],t=0,r="")=>{const c=["--no-warnings"];t<19&&c.push("--experimental-specifier-resolution=node");const e=y.fork(w.resolve(`${r}/cleanup.js`),[],{detached:!0,silent:!0});process.cleanup_process=e,process.on("SIGINT",async()=>{const o=d();e.send(JSON.stringify({process_ids:[...s,...o]})),process.exit()}),process.on("SIGTERM",async()=>{const o=d();e.send(JSON.stringify({process_ids:[...s,...o]})),process.exit()})},U=async(s=[])=>{const t=s?.find(a=>a?.path?.match(C.SETTINGS_FILE_NAME_REGEX)?.length>0),r=s?.find(a=>a?.path?.includes("i18n")),c=s?.find(a=>a?.path?.includes("index.html")),e=s?.find(a=>a?.path?.includes("index.css")||a?.path?.includes("css/")),o=s?.find(a=>a?.path?.includes("index.client.js"));process.hmr_server_process.send(JSON.stringify({type:"FILE_CHANGE",settings:t?await g(process.env.NODE_ENV):null,i18n_change:!!r,index_html_change:!!c,index_css_change:!!e,index_client_change:!!o}))},F=(s=0,t=!1,r={},c=[],e=!1)=>{process.hmr_server_process.on("message",async o=>{["HAS_HMR_CONNECTIONS","HAS_NO_HMR_CONNECTIONS","HMR_UPDATE_COMPLETE"].includes(o?.type)||process.loader.print(o),o?.type==="HAS_HMR_CONNECTIONS"&&(process.hmr_server_process.has_connections=!0),o?.type==="HAS_NO_HMR_CONNECTIONS"&&(process.hmr_server_process.has_connections=!1),o?.type==="HMR_UPDATE_COMPLETE"&&process.app_server_process&&!process.app_server_restarting&&(process.app_server_restarting=!0,O(s,t,r,c,e))})},B=()=>{process.hmr_server_process.on("error",s=>{i(s.toString(),{level:"danger",docs:"https://github.com/cheatcode/joystick"})}),process.hmr_server_process.stdout.on("data",s=>{console.log(s.toString())}),process.hmr_server_process.stderr.on("data",s=>{i(s.toString(),{level:"danger",docs:"https://github.com/cheatcode/joystick"})})},z=(s=0,t="",r=!1,c={},e=[],o=!1)=>{process.hmr_server_process=I(s,t),h.push(process.hmr_server_process?.pid),B(),F(s,r,c,e,o)},X=async(s={})=>{const t=await g(process.env.NODE_ENV),r=t?.config?.databases?JSON.stringify(t?.config?.databases):"",c=s?.config?.databases?JSON.stringify(s?.config?.databases):"";return r!==c},O=async(s=0,t=!1,r=null,c=[],e=!1)=>{V(async()=>{if(await X(r)){const a=d();i(`Database configuration has changed in settings.${process.env.NODE_ENV}.json. Please restart your app to add, change, or remove databases.`,{level:"danger",docs:"https://cheatcode.co/docs/joystick/structure"}),N([process.hmr_server_process?.pid,process.app_server_process?.pid,...a]),process.exit(0)}else N([...process.app_server_process.external_process_ids||[]]),await m(process.env.PORT),u(s,t,c,e)},300)},K=(s=!1,t=!1,r=!1)=>{process.app_server_process.external_process_ids=[],process.app_server_process.on("message",c=>{c?.external_process_id&&(process.app_server_process.external_process_ids=[...process.app_server_process.external_process_ids||[],c?.external_process_id])}),process.app_server_process.on("error",c=>{r||i(c.toString(),{level:"danger",docs:"https://github.com/cheatcode/joystick"})}),process.app_server_process.stdout.on("data",async c=>{const e=c.toString(),o=e.includes("App running at:");r||(e&&o&&process.env.NODE_ENV!=="test"&&process.loader.print(e),e&&!o&&!e.includes("BUILD_ERROR")&&console.log(e),e&&o&&process.env.NODE_ENV==="test"&&G(s),e&&o&&t&&process.env.NODE_ENV!=="test"&&setTimeout(async()=>{try{await v({__dirname:p})}catch(a){console.error("Error running integrated tests:",a)}},2e3))}),process.app_server_process.stderr.on("data",c=>{r||i(c.toString(),{level:"danger",docs:"https://cheatcode.co/docs/joystick"})})},u=(s=0,t=!1,r=[],c=!1,e=!1)=>{process.app_server_process=j(s,t,r),h.push(process.app_server_process?.pid),K(t,c,e),process.app_server_restarting=!1},Q=async(s={})=>{const t=s?.config?.databases?.map((r={})=>r?.provider);for(let r=0;r<t?.length;r+=1){const c=t[r];await A(c)}},W=(s={},t=2600)=>{process.title=s?.environment==="test"?"joystick_test":"joystick",process.project_folder=w.basename(process.cwd()),process.loader=new $,s?.environment==="test"&&(console.log(""),process.loader.print(`Initializing test environment...
2
+ `)),process.env.LOGS_PATH=s?.logs||null,process.env.NODE_ENV=s?.environment||"development",process.env.PORT=t,process.env.IS_DEBUG_MODE=s?.debug},Y=(s=2600)=>{i(`Port ${s} is already occupied. To start Joystick on this port, clear it and try again.`,{level:"danger"}),process.exit(0)},Z=(s=2600)=>parseInt(s||2600,10),ss=async()=>{const s=D(`${process.cwd()}/.joystick/build`);await l(s)&&await q(`${process.platform==="win32"?"rmdir /s /q":"rm -rf"} ${s}`)},es=async()=>{const s=[];for(let t=0;t<E?.length;t+=1){const r=E[t],c=await l(`${process.cwd()}/${r.path}`),e=c&&await P(`${process.cwd()}/${r.path}`);r&&r.type==="file"&&(!c||c&&!e.isFile())&&s.push({type:"file",path:r.path}),r&&r.type==="directory"&&(!c||c&&!e.isDirectory())&&s.push({type:"directory",path:r.path})}if(s?.length>0){const t=s?.filter(e=>e.type==="file"),r=s?.filter(e=>e.type==="directory");let c=`The following paths are missing and required in a Joystick project:
2
3
 
3
- `;if(t?.length>0){c+=` ${l.yellow(">")} Required Files:
4
+ `;if(t?.length>0){c+=` ${_.yellow(">")} Required Files:
4
5
 
5
- `;for(let e=0;e<t?.length;e+=1){const a=t[e],o=e+1===t?.length;c+=` ${l.red(`/${a.path}
6
- ${o&&r?.length>0?`
7
- `:""}`)}`}}if(r?.length>0){c+=` ${l.yellow(">")} Required Directories:
6
+ `;for(let e=0;e<t?.length;e+=1){const o=t[e],a=e+1===t?.length;c+=` ${_.red(`/${o.path}
7
+ ${a&&r?.length>0?`
8
+ `:""}`)}`}}if(r?.length>0){c+=` ${_.yellow(">")} Required Directories:
8
9
 
9
- `;for(let e=0;e<r?.length;e+=1){const a=r[e];c+=` ${l.red(`/${a.path}
10
- `)}`}}i(c,{level:"danger",docs:"https://cheatcode.co/docs/joystick/structure"}),process.exit(0)}},ns=async()=>{const s=await f(`${process.cwd()}/.joystick`),t=await f(`${process.cwd()}/tests`);process.env.NODE_ENV==="test"&&(!s||!t)&&(i("joystick test must be run in a directory with a .joystick folder and tests folder.",{level:"danger",docs:"https://cheatcode.co/docs/joystick/cli/test"}),process.exit(0)),process.env.NODE_ENV!=="test"&&!s&&(i("joystick start must be run in a directory with a .joystick folder.",{level:"danger",docs:"https://cheatcode.co/docs/joystick/cli/start"}),process.exit(0))},D=async(s={})=>{await ns(),await is(),await os();const t=as(s?.port),r=await m(t),c=await m(t+1);r&&cs(t),c&&g(t),rs(s,t);const e=await y(process.env.NODE_ENV);await ts(e),await V({environment:process.env.NODE_ENV,port:t,settings:e}),s?.tests&&s?.environment!=="test"&&!s?._is_test_server&&await S({imports:s?.imports||[]}),s?._is_test_server?v(p,!1,s?.imports||[],!1,!0):P({hot_module_reload:(a=[])=>Q(a),restart_app_server:()=>T(p,s?.watch,e,s?.imports,s?.tests),start_app_server:()=>v(p,s?.watch,s?.imports,s?.tests,s?._is_test_server),start_hmr_server:s?.environment!=="test"?()=>Z(p,_,s?.watch,e,s?.imports,s?.tests):null,run_tests:s?.tests?async()=>{setTimeout(async()=>{try{await k({__dirname:_})}catch(a){console.error("Error running tests after file change:",a)}},1e3)}:null},{excluded_paths:e?.config?.build?.excluded_paths,custom_copy_paths:e?.config?.build?.copy_paths?.map(a=>({path:a}))||[]}),K(h,p,_)};var Ms=D;export{Ms as default};
10
+ `;for(let e=0;e<r?.length;e+=1){const o=r[e];c+=` ${_.red(`/${o.path}
11
+ `)}`}}i(c,{level:"danger",docs:"https://cheatcode.co/docs/joystick/structure"}),process.exit(0)}},ts=async()=>{const s=await l(`${process.cwd()}/.joystick`),t=await l(`${process.cwd()}/tests`);process.env.NODE_ENV==="test"&&(!s||!t)&&(i("joystick test must be run in a directory with a .joystick folder and tests folder.",{level:"danger",docs:"https://cheatcode.co/docs/joystick/cli/test"}),process.exit(0)),process.env.NODE_ENV!=="test"&&!s&&(i("joystick start must be run in a directory with a .joystick folder.",{level:"danger",docs:"https://cheatcode.co/docs/joystick/cli/start"}),process.exit(0))},x=async(s={})=>{await ts(),await es(),await ss();const t=Z(s?.port),r=await f(t),c=await f(t+1);r&&Y(t),c&&m(t),W(s,t);const e=await g(process.env.NODE_ENV);await Q(e),await R({environment:process.env.NODE_ENV,port:t,settings:e}),s?.tests&&s?.environment!=="test"&&(await f(1977)&&await m(1977),setTimeout(async()=>{try{await x({environment:"test",port:1977,watch:!1,imports:s?.imports||[],_is_test_server:!0})}catch(a){console.error("Error starting test server:",a)}},100)),s?._is_test_server?u(n,!1,s?.imports||[],!1,!0):H({hot_module_reload:(o=[])=>U(o),restart_app_server:()=>O(n,s?.watch,e,s?.imports,s?.tests),start_app_server:()=>u(n,s?.watch,s?.imports,s?.tests,s?._is_test_server),start_hmr_server:s?.environment!=="test"?()=>z(n,p,s?.watch,e,s?.imports,s?.tests):null,run_tests:s?.tests?async()=>{setTimeout(async()=>{try{await v({__dirname:p})}catch(o){console.error("Error running tests after file change:",o)}},1e3)}:null},{excluded_paths:e?.config?.build?.excluded_paths,custom_copy_paths:e?.config?.build?.copy_paths?.map(o=>({path:o}))||[]}),J(h,n,p)};var Ds=x;export{Ds as default};
11
12
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/development_server/index.js"],
4
- "sourcesContent": ["import chalk from 'chalk';\nimport child_process from 'child_process';\nimport fs from 'fs';\nimport os from 'os';\nimport path, { dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport util from 'util';\nimport check_if_port_occupied from './check_if_port_occupied.js';\nimport cli_log from '../cli_log.js';\nimport get_database_process_ids from './get_database_process_ids.js';\n import get_platform_safe_path from '../get_platform_safe_path.js';\nimport kill_port_process from '../kill_port_process.js';\nimport load_settings from '../load_settings.js';\nimport Loader from '../loader.js';\nimport path_exists from '../path_exists.js';\nimport required_files from '../required_files.js';\nimport start_app_server from './start_app_server.js';\nimport start_databases from './start_databases.js';\nimport start_hmr_server from './start_hmr_server.js';\nimport watch_for_changes from './watch_for_changes/index.js';\nimport constants from '../constants.js';\nimport kill_process_ids from './kill_process_ids.js';\nimport run_tests, { run_tests_integrated } from './run_tests.js';\nimport debounce from '../debounce.js';\nimport download_database_binary from './databases/download_database_binary.js';\n\nconst { stat } = fs.promises;\nconst exec = util.promisify(child_process.exec);\n\nconst node_major_version = parseInt(\n process?.version?.split(\".\")[0]?.replace(\"v\", \"\"),\n 10\n);\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst process_ids = [];\n\n// NOTE: Global test server process tracking and server readiness state\nlet test_server_process = null;\nlet main_server_ready = false;\nlet test_server_ready = false;\n\nconst check_and_run_tests = async () => {\n if (main_server_ready && test_server_ready) {\n // NOTE: Only run tests once per readiness cycle\n if (check_and_run_tests.running) {\n return;\n }\n check_and_run_tests.running = true;\n \n // NOTE: Add 2s delay to ensure both servers are fully ready\n setTimeout(async () => {\n console.log('Running tests...');\n try {\n await run_tests_integrated({\n __dirname,\n });\n } catch (error) {\n console.error('Error running integrated tests:', error);\n } finally {\n check_and_run_tests.running = false;\n }\n }, 2000);\n }\n};\n\nconst start_test_server = async (development_server_options = {}) => {\n const test_port_occupied = await check_if_port_occupied(1977);\n if (test_port_occupied) {\n await kill_port_process(1977);\n }\n\n // NOTE: Start test server using the same development_server function\n // but with different options to avoid recursion and environment conflicts\n setTimeout(async () => {\n try {\n await development_server({\n environment: 'test',\n port: 1977,\n watch: false, // No file watching for test server\n imports: development_server_options?.imports || [],\n _is_test_server: true, // Internal flag to prevent infinite recursion\n });\n } catch (error) {\n console.error('Error starting test server:', error);\n }\n }, 100); // Small delay to let main server start first\n};\n\nconst stop_test_server = () => {\n if (test_server_process) {\n test_server_process.kill();\n test_server_process = null;\n }\n test_server_ready = false;\n};\n\nconst reset_server_readiness = () => {\n main_server_ready = false;\n test_server_ready = false;\n check_and_run_tests.running = false;\n};\n\nconst handle_run_tests = async (watch = false) => {\n const database_process_ids = get_database_process_ids();\n await run_tests({\n watch,\n __dirname,\n process_ids: [\n ...process_ids,\n ...database_process_ids,\n ],\n cleanup_process: process.cleanup_process,\n });\n};\n\nconst handle_signal_events = (process_ids = [], node_major_version = 0, __dirname = '') => {\n const exec_argv = [\"--no-warnings\"];\n\n if (node_major_version < 19) {\n exec_argv.push(\"--experimental-specifier-resolution=node\");\n }\n\n const cleanup_process = child_process.fork(\n path.resolve(`${__dirname}/cleanup.js`),\n [],\n {\n // NOTE: Run in detached mode so when parent process dies, the child still runs\n // and cleanup completes. Keep silent as we don't wan't/expect any messages.\n detached: true,\n silent: true,\n }\n );\n\n process.cleanup_process = cleanup_process;\n\n process.on(\"SIGINT\", async () => {\n const database_process_ids = get_database_process_ids();\n cleanup_process.send(JSON.stringify(({ process_ids: [...process_ids, ...database_process_ids] })));\n process.exit();\n });\n\n process.on(\"SIGTERM\", async () => {\n const database_process_ids = get_database_process_ids();\n cleanup_process.send(JSON.stringify(({ process_ids: [...process_ids, ...database_process_ids] })));\n process.exit();\n });\n};\n\nconst handle_signal_hmr_update = async (jobs = []) => {\n const has_settings_change = jobs?.find((job) => (job?.path?.match(constants.SETTINGS_FILE_NAME_REGEX))?.length > 0);\n const has_i18n_change = jobs?.find((job) => job?.path?.includes('i18n'));\n const has_index_html_change = jobs?.find((job) => job?.path?.includes('index.html'));\n const has_index_css_change = jobs?.find((job) => {\n return job?.path?.includes('index.css') || job?.path?.includes('css/');\n });\n const has_index_client_change = jobs?.find((job) => job?.path?.includes('index.client.js'));\n\n process.hmr_server_process.send(JSON.stringify({\n type: 'FILE_CHANGE',\n settings: has_settings_change ? await load_settings(process.env.NODE_ENV) : null,\n i18n_change: !!has_i18n_change,\n index_html_change: !!has_index_html_change,\n index_css_change: !!has_index_css_change,\n index_client_change: !!has_index_client_change,\n }));\n};\n\nconst handle_hmr_server_process_messages = (node_major_version = 0, watch = false, old_settings = {}, imports = [], run_integrated_tests = false) => {\n process.hmr_server_process.on(\"message\", async (message) => {\n const process_messages = [\n \"HAS_HMR_CONNECTIONS\",\n \"HAS_NO_HMR_CONNECTIONS\",\n \"HMR_UPDATE_COMPLETE\",\n ];\n\n if (!process_messages.includes(message?.type)) {\n process.loader.print(message);\n }\n\n if (message?.type === \"HAS_HMR_CONNECTIONS\") {\n process.hmr_server_process.has_connections = true;\n }\n\n if (message?.type === \"HAS_NO_HMR_CONNECTIONS\") {\n process.hmr_server_process.has_connections = false;\n }\n\n if (message?.type === \"HMR_UPDATE_COMPLETE\") {\n if (process.app_server_process && !process.app_server_restarting) {\n process.app_server_restarting = true;\n handle_restart_app_server(node_major_version, watch, old_settings, imports, run_integrated_tests);\n }\n }\n });\n};\n\nconst handle_hmr_server_process_stdio = () => {\n process.hmr_server_process.on(\"error\", (error) => {\n cli_log(error.toString(), {\n level: \"danger\",\n docs: \"https://github.com/cheatcode/joystick\",\n });\n });\n\n process.hmr_server_process.stdout.on(\"data\", (data) => {\n console.log(data.toString());\n });\n\n process.hmr_server_process.stderr.on(\"data\", (data) => {\n cli_log(data.toString(), {\n level: \"danger\",\n docs: \"https://github.com/cheatcode/joystick\",\n });\n });\n};\n\nconst handle_start_hmr_server = (node_major_version = 0, __dirname = '', watch = false, old_settings = {}, imports = [], run_integrated_tests = false) => {\n\tprocess.hmr_server_process = start_hmr_server(node_major_version, __dirname);\n process_ids.push(process.hmr_server_process?.pid);\n handle_hmr_server_process_stdio();\n handle_hmr_server_process_messages(node_major_version, watch, old_settings, imports, run_integrated_tests);\n};\n\nconst check_if_database_changes = async (old_settings = {}) => {\n const new_settings = await load_settings(process.env.NODE_ENV);\n const new_databse_settings = new_settings?.config?.databases ? JSON.stringify(new_settings?.config?.databases) : '';\n const old_database_settings = old_settings?.config?.databases ? JSON.stringify(old_settings?.config?.databases) : '';\n return new_databse_settings !== old_database_settings;\n};\n\nconst handle_restart_app_server = async (node_major_version = 0, watch = false, old_settings = null, imports = [], run_integrated_tests = false) => {\n debounce(async () => {\n const has_database_changes = await check_if_database_changes(old_settings);\n\n if (has_database_changes) {\n const database_process_ids = get_database_process_ids();\n\n cli_log(`Database configuration has changed in settings.${process.env.NODE_ENV}.json. Please restart your app to add, change, or remove databases.`, {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick/structure\",\n });\n\n kill_process_ids([\n process.hmr_server_process?.pid,\n process.app_server_process?.pid,\n ...database_process_ids,\n ]);\n\n process.exit(0);\n } else {\n // NOTE: Reset server readiness states when restarting\n if (run_integrated_tests) {\n reset_server_readiness();\n stop_test_server();\n }\n\n kill_process_ids([\n ...(process.app_server_process.external_process_ids || []),\n ]);\n\n await kill_port_process(process.env.PORT);\n handle_start_app_server(node_major_version, watch, imports, run_integrated_tests);\n\n // NOTE: Restart test server if tests are enabled\n if (run_integrated_tests) {\n await start_test_server({\n imports: imports || [],\n });\n }\n }\n }, 300);\n};\n\nconst handle_app_server_process_stdio = (watch = false, run_integrated_tests = false, is_test_server = false) => {\n // NOTE: Default this in case we never get any external process IDs.\n process.app_server_process.external_process_ids = [];\n\n process.app_server_process.on('message', (message_from_child) => {\n if (message_from_child?.external_process_id) {\n process.app_server_process.external_process_ids = [\n ...(process.app_server_process.external_process_ids || []),\n message_from_child?.external_process_id,\n ];\n }\n });\n\n process.app_server_process.on('error', (error) => {\n if (!is_test_server) {\n cli_log(error.toString(), {\n level: \"danger\",\n docs: \"https://github.com/cheatcode/joystick\",\n });\n }\n });\n\n process.app_server_process.stdout.on(\"data\", async (data) => {\n \tconst stdout = data.toString();\n const is_startup_notification = stdout.includes(\"App running at:\");\n\n // NOTE: Suppress all test server output\n if (is_test_server) {\n return;\n }\n\n // NOTE: Main server output handling\n \tif (stdout && is_startup_notification && process.env.NODE_ENV !== 'test') {\n \t\tprocess.loader.print(stdout);\n \t}\n\n if (stdout && !is_startup_notification && !stdout.includes(\"BUILD_ERROR\")) {\n console.log(stdout);\n }\n\n // NOTE: Mark main server as ready when --tests flag is used\n if (stdout && is_startup_notification && run_integrated_tests && process.env.NODE_ENV !== 'test') {\n main_server_ready = true;\n check_and_run_tests();\n }\n\n // NOTE: Mark test server as ready when it starts up (but don't run standalone tests)\n if (stdout && is_startup_notification && process.env.NODE_ENV === 'test') {\n test_server_ready = true;\n check_and_run_tests();\n }\n });\n\n process.app_server_process.stderr.on(\"data\", (data) => {\n if (!is_test_server) {\n cli_log(data.toString(), {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick\",\n });\n }\n });\n};\n\nconst handle_start_app_server = (node_major_version = 0, watch = false, imports = [], run_integrated_tests = false, is_test_server = false) => {\n\tprocess.app_server_process = start_app_server(node_major_version, watch, imports);\n process_ids.push(process.app_server_process?.pid);\n handle_app_server_process_stdio(watch, run_integrated_tests, is_test_server);\n process.app_server_restarting = false;\n};\n\nconst install_missing_databases = async (settings = {}) => {\n const required_databases = settings?.config?.databases?.map((database = {}) => {\n return database?.provider;\n });\n\n for (let i = 0; i < required_databases?.length; i += 1) {\n const provider_name = required_databases[i];\n await download_database_binary(provider_name);\n }\n};\n\nconst set_process_variables = (development_server_options = {}, port = 2600) => {\n process.title = development_server_options?.environment === 'test' ? \"joystick_test\" : 'joystick';\n process.project_folder = path.basename(process.cwd());\n process.loader = new Loader();\n\n process.env.LOGS_PATH = development_server_options?.logs || null;\n process.env.NODE_ENV = development_server_options?.environment || \"development\";\n process.env.PORT = port;\n process.env.IS_DEBUG_MODE = development_server_options?.debug;\n};\n\nconst warn_app_port_occupied = (port = 2600) => {\n cli_log(`Port ${port} is already occupied. To start Joystick on this port, clear it and try again.`, {\n level: 'danger',\n });\n\n process.exit(0);\n};\n\nconst get_port = (port = 2600) => {\n\treturn parseInt(port || 2600, 10);\n};\n\nconst clean_up_existing_build = async () => {\n\tconst build_path = get_platform_safe_path(`${process.cwd()}/.joystick/build`);\n\n\tif (await path_exists(build_path)) {\n\t\tawait exec(`${process.platform === 'win32' ? 'rmdir /s /q' : 'rm -rf'} ${build_path}`);\n\t}\n};\n\nconst check_for_required_files = async () => {\n const missing_files = [];\n\n for (let i = 0; i < required_files?.length; i += 1) {\n const required_file = required_files[i];\n const exists = await path_exists(`${process.cwd()}/${required_file.path}`);\n const stats = exists && await stat(`${process.cwd()}/${required_file.path}`);\n\n if (required_file && required_file.type === \"file\" && (!exists || (exists && !stats.isFile()))) {\n missing_files.push({ type: 'file', path: required_file.path });\n }\n\n if (required_file && required_file.type === \"directory\" && (!exists || (exists && !stats.isDirectory()))) {\n missing_files.push({ type: 'directory', path: required_file.path });\n }\n }\n\n if (missing_files?.length > 0) {\n const files = missing_files?.filter((path) => path.type === 'file');\n const directories = missing_files?.filter((path) => path.type === 'directory');\n\n let error = `The following paths are missing and required in a Joystick project:\\n\\n`;\n\n if (files?.length > 0) {\n error += ` ${chalk.yellow('>')} Required Files:\\n\\n`;\n\n for (let i = 0; i < files?.length; i += 1) {\n const file = files[i];\n const is_last_file = i +1 === files?.length;\n error += ` ${chalk.red(`/${file.path}\\n${is_last_file && directories?.length > 0 ? '\\n' : ''}`)}`;\n }\n }\n\n if (directories?.length > 0) {\n error += ` ${chalk.yellow('>')} Required Directories:\\n\\n`;\n\n for (let i = 0; i < directories?.length; i += 1) {\n const file = directories[i];\n error += ` ${chalk.red(`/${file.path}\\n`)}`;\n }\n }\n\n cli_log(error, {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick/structure\",\n });\n\n process.exit(0);\n }\n};\n\nconst warn_invalid_joystick_environment = async () => {\n const has_joystick_folder = await path_exists(`${process.cwd()}/.joystick`);\n const has_tests_folder = await path_exists(`${process.cwd()}/tests`);\n\n if (process.env.NODE_ENV === 'test' && (!has_joystick_folder || !has_tests_folder)) {\n cli_log(\n \"joystick test must be run in a directory with a .joystick folder and tests folder.\",\n {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick/cli/test\",\n }\n );\n\n process.exit(0);\n }\n\n if (process.env.NODE_ENV !== 'test' && !has_joystick_folder) {\n cli_log(\n \"joystick start must be run in a directory with a .joystick folder.\",\n {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick/cli/start\",\n }\n );\n\n process.exit(0);\n }\n};\n\nconst development_server = async (development_server_options = {}) => {\n await warn_invalid_joystick_environment();\n await check_for_required_files();\n\n\tawait clean_up_existing_build();\n\n\tconst port = get_port(development_server_options?.port);\n\tconst app_port_occupied = await check_if_port_occupied(port);\n const hmr_port_occupied = await check_if_port_occupied(port + 1);\n\n if (app_port_occupied) {\n \twarn_app_port_occupied(port);\n }\n\n if (hmr_port_occupied) {\n \tkill_port_process(port);\n }\n\n set_process_variables(development_server_options, port);\n\n const settings = await load_settings(process.env.NODE_ENV);\n\n await install_missing_databases(settings);\n\n await start_databases({\n environment: process.env.NODE_ENV,\n port,\n settings\n });\n\n // NOTE: Start test server if tests flag is enabled and this is not already a test server\n if (development_server_options?.tests && development_server_options?.environment !== 'test' && !development_server_options?._is_test_server) {\n await start_test_server({\n imports: development_server_options?.imports || [],\n });\n }\n\n\n // NOTE: Only set up file watching for non-test servers\n if (!development_server_options?._is_test_server) {\n watch_for_changes({\n hot_module_reload: (jobs = []) => handle_signal_hmr_update(jobs),\n restart_app_server: () => handle_restart_app_server(\n node_major_version,\n development_server_options?.watch,\n settings,\n development_server_options?.imports,\n development_server_options?.tests,\n ),\n start_app_server: () => handle_start_app_server(\n node_major_version,\n development_server_options?.watch,\n development_server_options?.imports,\n development_server_options?.tests,\n development_server_options?._is_test_server,\n ),\n start_hmr_server: development_server_options?.environment !== 'test' ? () => handle_start_hmr_server(\n node_major_version,\n __dirname,\n development_server_options?.watch,\n settings,\n development_server_options?.imports,\n development_server_options?.tests,\n ) : null,\n run_tests: development_server_options?.tests ? async () => {\n // NOTE: Add delay to avoid jarring UX when test files change\n setTimeout(async () => {\n try {\n await run_tests_integrated({\n __dirname,\n });\n } catch (error) {\n console.error('Error running tests after file change:', error);\n }\n }, 1000);\n } : null,\n }, {\n excluded_paths: settings?.config?.build?.excluded_paths,\n custom_copy_paths: settings?.config?.build?.copy_paths?.map((path) => {\n return { path };\n }) || [],\n });\n } else {\n // NOTE: For test server, just start the app server without file watching\n handle_start_app_server(\n node_major_version,\n false, // No file watching for test server\n development_server_options?.imports || [],\n false, // No integrated tests for test server\n true, // This is a test server\n );\n }\n\n handle_signal_events(process_ids, node_major_version, __dirname);\n};\n\nexport default development_server;\n"],
5
- "mappings": "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",
6
- "names": ["chalk", "child_process", "fs", "path", "dirname", "fileURLToPath", "util", "check_if_port_occupied", "cli_log", "get_database_process_ids", "get_platform_safe_path", "kill_port_process", "load_settings", "Loader", "path_exists", "required_files", "start_app_server", "start_databases", "start_hmr_server", "watch_for_changes", "constants", "kill_process_ids", "run_tests", "run_tests_integrated", "debounce", "download_database_binary", "stat", "exec", "node_major_version", "__filename", "__dirname", "process_ids", "test_server_process", "main_server_ready", "test_server_ready", "check_and_run_tests", "error", "start_test_server", "development_server_options", "development_server", "stop_test_server", "reset_server_readiness", "handle_run_tests", "watch", "database_process_ids", "handle_signal_events", "exec_argv", "cleanup_process", "handle_signal_hmr_update", "jobs", "has_settings_change", "job", "has_i18n_change", "has_index_html_change", "has_index_css_change", "has_index_client_change", "handle_hmr_server_process_messages", "old_settings", "imports", "run_integrated_tests", "message", "handle_restart_app_server", "handle_hmr_server_process_stdio", "data", "handle_start_hmr_server", "check_if_database_changes", "new_settings", "new_databse_settings", "old_database_settings", "handle_start_app_server", "handle_app_server_process_stdio", "is_test_server", "message_from_child", "stdout", "is_startup_notification", "install_missing_databases", "settings", "required_databases", "database", "i", "provider_name", "set_process_variables", "port", "warn_app_port_occupied", "get_port", "clean_up_existing_build", "build_path", "check_for_required_files", "missing_files", "required_file", "exists", "stats", "files", "directories", "file", "is_last_file", "warn_invalid_joystick_environment", "has_joystick_folder", "has_tests_folder", "app_port_occupied", "hmr_port_occupied", "index_default"]
4
+ "sourcesContent": ["import chalk from 'chalk';\nimport child_process from 'child_process';\nimport fs from 'fs';\nimport os from 'os';\nimport path, { dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport util from 'util';\nimport check_if_port_occupied from './check_if_port_occupied.js';\nimport cli_log from '../cli_log.js';\nimport get_database_process_ids from './get_database_process_ids.js';\n import get_platform_safe_path from '../get_platform_safe_path.js';\nimport kill_port_process from '../kill_port_process.js';\nimport load_settings from '../load_settings.js';\nimport Loader from '../loader.js';\nimport path_exists from '../path_exists.js';\nimport required_files from '../required_files.js';\nimport start_app_server from './start_app_server.js';\nimport start_databases from './start_databases.js';\nimport start_hmr_server from './start_hmr_server.js';\nimport watch_for_changes from './watch_for_changes/index.js';\nimport constants from '../constants.js';\nimport kill_process_ids from './kill_process_ids.js';\nimport run_tests, { run_tests_integrated } from './run_tests.js';\nimport debounce from '../debounce.js';\nimport download_database_binary from './databases/download_database_binary.js';\n\nconst { stat } = fs.promises;\nconst exec = util.promisify(child_process.exec);\n\nconst node_major_version = parseInt(\n process?.version?.split(\".\")[0]?.replace(\"v\", \"\"),\n 10\n);\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst process_ids = [];\n\nconst handle_run_tests = async (watch = false) => {\n const database_process_ids = get_database_process_ids();\n await run_tests({\n watch,\n __dirname,\n process_ids: [\n ...process_ids,\n ...database_process_ids,\n ],\n cleanup_process: process.cleanup_process,\n });\n};\n\nconst handle_signal_events = (process_ids = [], node_major_version = 0, __dirname = '') => {\n const exec_argv = [\"--no-warnings\"];\n\n if (node_major_version < 19) {\n exec_argv.push(\"--experimental-specifier-resolution=node\");\n }\n\n const cleanup_process = child_process.fork(\n path.resolve(`${__dirname}/cleanup.js`),\n [],\n {\n // NOTE: Run in detached mode so when parent process dies, the child still runs\n // and cleanup completes. Keep silent as we don't wan't/expect any messages.\n detached: true,\n silent: true,\n }\n );\n\n process.cleanup_process = cleanup_process;\n\n process.on(\"SIGINT\", async () => {\n const database_process_ids = get_database_process_ids();\n cleanup_process.send(JSON.stringify(({ process_ids: [...process_ids, ...database_process_ids] })));\n process.exit();\n });\n\n process.on(\"SIGTERM\", async () => {\n const database_process_ids = get_database_process_ids();\n cleanup_process.send(JSON.stringify(({ process_ids: [...process_ids, ...database_process_ids] })));\n process.exit();\n });\n};\n\nconst handle_signal_hmr_update = async (jobs = []) => {\n const has_settings_change = jobs?.find((job) => (job?.path?.match(constants.SETTINGS_FILE_NAME_REGEX))?.length > 0);\n const has_i18n_change = jobs?.find((job) => job?.path?.includes('i18n'));\n const has_index_html_change = jobs?.find((job) => job?.path?.includes('index.html'));\n const has_index_css_change = jobs?.find((job) => {\n return job?.path?.includes('index.css') || job?.path?.includes('css/');\n });\n const has_index_client_change = jobs?.find((job) => job?.path?.includes('index.client.js'));\n\n process.hmr_server_process.send(JSON.stringify({\n type: 'FILE_CHANGE',\n settings: has_settings_change ? await load_settings(process.env.NODE_ENV) : null,\n i18n_change: !!has_i18n_change,\n index_html_change: !!has_index_html_change,\n index_css_change: !!has_index_css_change,\n index_client_change: !!has_index_client_change,\n }));\n};\n\nconst handle_hmr_server_process_messages = (node_major_version = 0, watch = false, old_settings = {}, imports = [], run_integrated_tests = false) => {\n process.hmr_server_process.on(\"message\", async (message) => {\n const process_messages = [\n \"HAS_HMR_CONNECTIONS\",\n \"HAS_NO_HMR_CONNECTIONS\",\n \"HMR_UPDATE_COMPLETE\",\n ];\n\n if (!process_messages.includes(message?.type)) {\n process.loader.print(message);\n }\n\n if (message?.type === \"HAS_HMR_CONNECTIONS\") {\n process.hmr_server_process.has_connections = true;\n }\n\n if (message?.type === \"HAS_NO_HMR_CONNECTIONS\") {\n process.hmr_server_process.has_connections = false;\n }\n\n if (message?.type === \"HMR_UPDATE_COMPLETE\") {\n if (process.app_server_process && !process.app_server_restarting) {\n process.app_server_restarting = true;\n handle_restart_app_server(node_major_version, watch, old_settings, imports, run_integrated_tests);\n }\n }\n });\n};\n\nconst handle_hmr_server_process_stdio = () => {\n process.hmr_server_process.on(\"error\", (error) => {\n cli_log(error.toString(), {\n level: \"danger\",\n docs: \"https://github.com/cheatcode/joystick\",\n });\n });\n\n process.hmr_server_process.stdout.on(\"data\", (data) => {\n console.log(data.toString());\n });\n\n process.hmr_server_process.stderr.on(\"data\", (data) => {\n cli_log(data.toString(), {\n level: \"danger\",\n docs: \"https://github.com/cheatcode/joystick\",\n });\n });\n};\n\nconst handle_start_hmr_server = (node_major_version = 0, __dirname = '', watch = false, old_settings = {}, imports = [], run_integrated_tests = false) => {\n\tprocess.hmr_server_process = start_hmr_server(node_major_version, __dirname);\n process_ids.push(process.hmr_server_process?.pid);\n handle_hmr_server_process_stdio();\n handle_hmr_server_process_messages(node_major_version, watch, old_settings, imports, run_integrated_tests);\n};\n\nconst check_if_database_changes = async (old_settings = {}) => {\n const new_settings = await load_settings(process.env.NODE_ENV);\n const new_databse_settings = new_settings?.config?.databases ? JSON.stringify(new_settings?.config?.databases) : '';\n const old_database_settings = old_settings?.config?.databases ? JSON.stringify(old_settings?.config?.databases) : '';\n return new_databse_settings !== old_database_settings;\n};\n\nconst handle_restart_app_server = async (node_major_version = 0, watch = false, old_settings = null, imports = [], run_integrated_tests = false) => {\n debounce(async () => {\n const has_database_changes = await check_if_database_changes(old_settings);\n\n if (has_database_changes) {\n const database_process_ids = get_database_process_ids();\n\n cli_log(`Database configuration has changed in settings.${process.env.NODE_ENV}.json. Please restart your app to add, change, or remove databases.`, {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick/structure\",\n });\n\n kill_process_ids([\n process.hmr_server_process?.pid,\n process.app_server_process?.pid,\n ...database_process_ids,\n ]);\n\n process.exit(0);\n } else {\n kill_process_ids([\n ...(process.app_server_process.external_process_ids || []),\n ]);\n\n await kill_port_process(process.env.PORT);\n handle_start_app_server(node_major_version, watch, imports, run_integrated_tests);\n }\n }, 300);\n};\n\nconst handle_app_server_process_stdio = (watch = false, run_integrated_tests = false, is_test_server = false) => {\n // NOTE: Default this in case we never get any external process IDs.\n process.app_server_process.external_process_ids = [];\n\n process.app_server_process.on('message', (message_from_child) => {\n if (message_from_child?.external_process_id) {\n process.app_server_process.external_process_ids = [\n ...(process.app_server_process.external_process_ids || []),\n message_from_child?.external_process_id,\n ];\n }\n });\n\n process.app_server_process.on('error', (error) => {\n if (!is_test_server) {\n cli_log(error.toString(), {\n level: \"danger\",\n docs: \"https://github.com/cheatcode/joystick\",\n });\n }\n });\n\n process.app_server_process.stdout.on(\"data\", async (data) => {\n \tconst stdout = data.toString();\n const is_startup_notification = stdout.includes(\"App running at:\");\n\n // NOTE: Suppress all test server output\n if (is_test_server) {\n return;\n }\n\n // NOTE: Main server output handling\n \tif (stdout && is_startup_notification && process.env.NODE_ENV !== 'test') {\n \t\tprocess.loader.print(stdout);\n \t}\n\n if (stdout && !is_startup_notification && !stdout.includes(\"BUILD_ERROR\")) {\n console.log(stdout);\n }\n\n // NOTE: Run tests here so we can guarantee app server is running. Do a slight delay\n // to ensure that test routes are registered.\n if (stdout && is_startup_notification && process.env.NODE_ENV === 'test') {\n handle_run_tests(watch);\n }\n\n // NOTE: Run integrated tests when --tests flag is used and server has started\n if (stdout && is_startup_notification && run_integrated_tests && process.env.NODE_ENV !== 'test') {\n // NOTE: Add delay to avoid jarring UX and ensure server is fully ready\n setTimeout(async () => {\n try {\n await run_tests_integrated({\n __dirname,\n });\n } catch (error) {\n console.error('Error running integrated tests:', error);\n }\n }, 2000);\n }\n });\n\n process.app_server_process.stderr.on(\"data\", (data) => {\n if (!is_test_server) {\n cli_log(data.toString(), {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick\",\n });\n }\n });\n};\n\nconst handle_start_app_server = (node_major_version = 0, watch = false, imports = [], run_integrated_tests = false, is_test_server = false) => {\n\tprocess.app_server_process = start_app_server(node_major_version, watch, imports);\n process_ids.push(process.app_server_process?.pid);\n handle_app_server_process_stdio(watch, run_integrated_tests, is_test_server);\n process.app_server_restarting = false;\n};\n\nconst install_missing_databases = async (settings = {}) => {\n const required_databases = settings?.config?.databases?.map((database = {}) => {\n return database?.provider;\n });\n\n for (let i = 0; i < required_databases?.length; i += 1) {\n const provider_name = required_databases[i];\n await download_database_binary(provider_name);\n }\n};\n\nconst set_process_variables = (development_server_options = {}, port = 2600) => {\n process.title = development_server_options?.environment === 'test' ? \"joystick_test\" : 'joystick';\n process.project_folder = path.basename(process.cwd());\n process.loader = new Loader();\n\n if (development_server_options?.environment === 'test') {\n console.log(''); // NOTE: Silly, but gives us better styling.\n process.loader.print(\"Initializing test environment...\\n\");\n }\n\n process.env.LOGS_PATH = development_server_options?.logs || null;\n process.env.NODE_ENV = development_server_options?.environment || \"development\";\n process.env.PORT = port;\n process.env.IS_DEBUG_MODE = development_server_options?.debug;\n};\n\nconst warn_app_port_occupied = (port = 2600) => {\n cli_log(`Port ${port} is already occupied. To start Joystick on this port, clear it and try again.`, {\n level: 'danger',\n });\n\n process.exit(0);\n};\n\nconst get_port = (port = 2600) => {\n\treturn parseInt(port || 2600, 10);\n};\n\nconst clean_up_existing_build = async () => {\n\tconst build_path = get_platform_safe_path(`${process.cwd()}/.joystick/build`);\n\n\tif (await path_exists(build_path)) {\n\t\tawait exec(`${process.platform === 'win32' ? 'rmdir /s /q' : 'rm -rf'} ${build_path}`);\n\t}\n};\n\nconst check_for_required_files = async () => {\n const missing_files = [];\n\n for (let i = 0; i < required_files?.length; i += 1) {\n const required_file = required_files[i];\n const exists = await path_exists(`${process.cwd()}/${required_file.path}`);\n const stats = exists && await stat(`${process.cwd()}/${required_file.path}`);\n\n if (required_file && required_file.type === \"file\" && (!exists || (exists && !stats.isFile()))) {\n missing_files.push({ type: 'file', path: required_file.path });\n }\n\n if (required_file && required_file.type === \"directory\" && (!exists || (exists && !stats.isDirectory()))) {\n missing_files.push({ type: 'directory', path: required_file.path });\n }\n }\n\n if (missing_files?.length > 0) {\n const files = missing_files?.filter((path) => path.type === 'file');\n const directories = missing_files?.filter((path) => path.type === 'directory');\n\n let error = `The following paths are missing and required in a Joystick project:\\n\\n`;\n\n if (files?.length > 0) {\n error += ` ${chalk.yellow('>')} Required Files:\\n\\n`;\n\n for (let i = 0; i < files?.length; i += 1) {\n const file = files[i];\n const is_last_file = i +1 === files?.length;\n error += ` ${chalk.red(`/${file.path}\\n${is_last_file && directories?.length > 0 ? '\\n' : ''}`)}`;\n }\n }\n\n if (directories?.length > 0) {\n error += ` ${chalk.yellow('>')} Required Directories:\\n\\n`;\n\n for (let i = 0; i < directories?.length; i += 1) {\n const file = directories[i];\n error += ` ${chalk.red(`/${file.path}\\n`)}`;\n }\n }\n\n cli_log(error, {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick/structure\",\n });\n\n process.exit(0);\n }\n};\n\nconst warn_invalid_joystick_environment = async () => {\n const has_joystick_folder = await path_exists(`${process.cwd()}/.joystick`);\n const has_tests_folder = await path_exists(`${process.cwd()}/tests`);\n\n if (process.env.NODE_ENV === 'test' && (!has_joystick_folder || !has_tests_folder)) {\n cli_log(\n \"joystick test must be run in a directory with a .joystick folder and tests folder.\",\n {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick/cli/test\",\n }\n );\n\n process.exit(0);\n }\n\n if (process.env.NODE_ENV !== 'test' && !has_joystick_folder) {\n cli_log(\n \"joystick start must be run in a directory with a .joystick folder.\",\n {\n level: \"danger\",\n docs: \"https://cheatcode.co/docs/joystick/cli/start\",\n }\n );\n\n process.exit(0);\n }\n};\n\nconst development_server = async (development_server_options = {}) => {\n await warn_invalid_joystick_environment();\n await check_for_required_files();\n\n\tawait clean_up_existing_build();\n\n\tconst port = get_port(development_server_options?.port);\n\tconst app_port_occupied = await check_if_port_occupied(port);\n const hmr_port_occupied = await check_if_port_occupied(port + 1);\n\n if (app_port_occupied) {\n \twarn_app_port_occupied(port);\n }\n\n if (hmr_port_occupied) {\n \tkill_port_process(port);\n }\n\n set_process_variables(development_server_options, port);\n\n const settings = await load_settings(process.env.NODE_ENV);\n\n await install_missing_databases(settings);\n\n await start_databases({\n environment: process.env.NODE_ENV,\n port,\n settings\n });\n\n // NOTE: If tests flag is enabled, start a separate test server on port 1977\n if (development_server_options?.tests && development_server_options?.environment !== 'test') {\n const test_port_occupied = await check_if_port_occupied(1977);\n if (test_port_occupied) {\n await kill_port_process(1977);\n }\n\n // NOTE: Start test server in parallel using the same development_server function\n // but with different options to avoid recursion and environment conflicts\n setTimeout(async () => {\n try {\n await development_server({\n environment: 'test',\n port: 1977,\n watch: false, // No file watching for test server\n imports: development_server_options?.imports || [],\n _is_test_server: true, // Internal flag to prevent infinite recursion\n });\n } catch (error) {\n console.error('Error starting test server:', error);\n }\n }, 100); // Small delay to let main server start first\n }\n\n // NOTE: Only set up file watching for non-test servers\n if (!development_server_options?._is_test_server) {\n watch_for_changes({\n hot_module_reload: (jobs = []) => handle_signal_hmr_update(jobs),\n restart_app_server: () => handle_restart_app_server(\n node_major_version,\n development_server_options?.watch,\n settings,\n development_server_options?.imports,\n development_server_options?.tests,\n ),\n start_app_server: () => handle_start_app_server(\n node_major_version,\n development_server_options?.watch,\n development_server_options?.imports,\n development_server_options?.tests,\n development_server_options?._is_test_server,\n ),\n start_hmr_server: development_server_options?.environment !== 'test' ? () => handle_start_hmr_server(\n node_major_version,\n __dirname,\n development_server_options?.watch,\n settings,\n development_server_options?.imports,\n development_server_options?.tests,\n ) : null,\n run_tests: development_server_options?.tests ? async () => {\n // NOTE: Add delay to avoid jarring UX when test files change\n setTimeout(async () => {\n try {\n await run_tests_integrated({\n __dirname,\n });\n } catch (error) {\n console.error('Error running tests after file change:', error);\n }\n }, 1000);\n } : null,\n }, {\n excluded_paths: settings?.config?.build?.excluded_paths,\n custom_copy_paths: settings?.config?.build?.copy_paths?.map((path) => {\n return { path };\n }) || [],\n });\n } else {\n // NOTE: For test server, just start the app server without file watching\n handle_start_app_server(\n node_major_version,\n false, // No file watching for test server\n development_server_options?.imports || [],\n false, // No integrated tests for test server\n true, // This is a test server\n );\n }\n\n handle_signal_events(process_ids, node_major_version, __dirname);\n};\n\nexport default development_server;\n"],
5
+ "mappings": "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",
6
+ "names": ["chalk", "child_process", "fs", "path", "dirname", "fileURLToPath", "util", "check_if_port_occupied", "cli_log", "get_database_process_ids", "get_platform_safe_path", "kill_port_process", "load_settings", "Loader", "path_exists", "required_files", "start_app_server", "start_databases", "start_hmr_server", "watch_for_changes", "constants", "kill_process_ids", "run_tests", "run_tests_integrated", "debounce", "download_database_binary", "stat", "exec", "node_major_version", "__filename", "__dirname", "process_ids", "handle_run_tests", "watch", "database_process_ids", "handle_signal_events", "exec_argv", "cleanup_process", "handle_signal_hmr_update", "jobs", "has_settings_change", "job", "has_i18n_change", "has_index_html_change", "has_index_css_change", "has_index_client_change", "handle_hmr_server_process_messages", "old_settings", "imports", "run_integrated_tests", "message", "handle_restart_app_server", "handle_hmr_server_process_stdio", "error", "data", "handle_start_hmr_server", "check_if_database_changes", "new_settings", "new_databse_settings", "old_database_settings", "handle_start_app_server", "handle_app_server_process_stdio", "is_test_server", "message_from_child", "stdout", "is_startup_notification", "install_missing_databases", "settings", "required_databases", "database", "i", "provider_name", "set_process_variables", "development_server_options", "port", "warn_app_port_occupied", "get_port", "clean_up_existing_build", "build_path", "check_for_required_files", "missing_files", "required_file", "exists", "stats", "files", "directories", "file", "is_last_file", "warn_invalid_joystick_environment", "has_joystick_folder", "has_tests_folder", "development_server", "app_port_occupied", "hmr_port_occupied", "index_default"]
7
7
  }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@joystick.js/cli-canary",
3
3
  "type": "module",
4
- "version": "0.0.0-canary.2138",
5
- "canary_version": "0.0.0-canary.2137",
4
+ "version": "0.0.0-canary.2139",
5
+ "canary_version": "0.0.0-canary.2138",
6
6
  "description": "The CLI for Joystick.",
7
7
  "main": "dist/index.js",
8
8
  "bin": {
@@ -37,72 +37,6 @@ const __dirname = dirname(__filename);
37
37
 
38
38
  const process_ids = [];
39
39
 
40
- // NOTE: Global test server process tracking and server readiness state
41
- let test_server_process = null;
42
- let main_server_ready = false;
43
- let test_server_ready = false;
44
-
45
- const check_and_run_tests = async () => {
46
- if (main_server_ready && test_server_ready) {
47
- // NOTE: Only run tests once per readiness cycle
48
- if (check_and_run_tests.running) {
49
- return;
50
- }
51
- check_and_run_tests.running = true;
52
-
53
- // NOTE: Add 2s delay to ensure both servers are fully ready
54
- setTimeout(async () => {
55
- console.log('Running tests...');
56
- try {
57
- await run_tests_integrated({
58
- __dirname,
59
- });
60
- } catch (error) {
61
- console.error('Error running integrated tests:', error);
62
- } finally {
63
- check_and_run_tests.running = false;
64
- }
65
- }, 2000);
66
- }
67
- };
68
-
69
- const start_test_server = async (development_server_options = {}) => {
70
- const test_port_occupied = await check_if_port_occupied(1977);
71
- if (test_port_occupied) {
72
- await kill_port_process(1977);
73
- }
74
-
75
- // NOTE: Start test server using the same development_server function
76
- // but with different options to avoid recursion and environment conflicts
77
- setTimeout(async () => {
78
- try {
79
- await development_server({
80
- environment: 'test',
81
- port: 1977,
82
- watch: false, // No file watching for test server
83
- imports: development_server_options?.imports || [],
84
- _is_test_server: true, // Internal flag to prevent infinite recursion
85
- });
86
- } catch (error) {
87
- console.error('Error starting test server:', error);
88
- }
89
- }, 100); // Small delay to let main server start first
90
- };
91
-
92
- const stop_test_server = () => {
93
- if (test_server_process) {
94
- test_server_process.kill();
95
- test_server_process = null;
96
- }
97
- test_server_ready = false;
98
- };
99
-
100
- const reset_server_readiness = () => {
101
- main_server_ready = false;
102
- test_server_ready = false;
103
- check_and_run_tests.running = false;
104
- };
105
-
106
40
  const handle_run_tests = async (watch = false) => {
107
41
  const database_process_ids = get_database_process_ids();
108
42
  await run_tests({
@@ -251,25 +185,12 @@ const handle_restart_app_server = async (node_major_version = 0, watch = false,
251
185
 
252
186
  process.exit(0);
253
187
  } else {
254
- // NOTE: Reset server readiness states when restarting
255
- if (run_integrated_tests) {
256
- reset_server_readiness();
257
- stop_test_server();
258
- }
259
-
260
188
  kill_process_ids([
261
189
  ...(process.app_server_process.external_process_ids || []),
262
190
  ]);
263
191
 
264
192
  await kill_port_process(process.env.PORT);
265
193
  handle_start_app_server(node_major_version, watch, imports, run_integrated_tests);
266
-
267
- // NOTE: Restart test server if tests are enabled
268
- if (run_integrated_tests) {
269
- await start_test_server({
270
- imports: imports || [],
271
- });
272
- }
273
194
  }
274
195
  }, 300);
275
196
  };
@@ -314,16 +235,24 @@ const handle_app_server_process_stdio = (watch = false, run_integrated_tests = f
314
235
  console.log(stdout);
315
236
  }
316
237
 
317
- // NOTE: Mark main server as ready when --tests flag is used
318
- if (stdout && is_startup_notification && run_integrated_tests && process.env.NODE_ENV !== 'test') {
319
- main_server_ready = true;
320
- check_and_run_tests();
238
+ // NOTE: Run tests here so we can guarantee app server is running. Do a slight delay
239
+ // to ensure that test routes are registered.
240
+ if (stdout && is_startup_notification && process.env.NODE_ENV === 'test') {
241
+ handle_run_tests(watch);
321
242
  }
322
243
 
323
- // NOTE: Mark test server as ready when it starts up (but don't run standalone tests)
324
- if (stdout && is_startup_notification && process.env.NODE_ENV === 'test') {
325
- test_server_ready = true;
326
- check_and_run_tests();
244
+ // NOTE: Run integrated tests when --tests flag is used and server has started
245
+ if (stdout && is_startup_notification && run_integrated_tests && process.env.NODE_ENV !== 'test') {
246
+ // NOTE: Add delay to avoid jarring UX and ensure server is fully ready
247
+ setTimeout(async () => {
248
+ try {
249
+ await run_tests_integrated({
250
+ __dirname,
251
+ });
252
+ } catch (error) {
253
+ console.error('Error running integrated tests:', error);
254
+ }
255
+ }, 2000);
327
256
  }
328
257
  });
329
258
 
@@ -360,6 +289,11 @@ const set_process_variables = (development_server_options = {}, port = 2600) =>
360
289
  process.project_folder = path.basename(process.cwd());
361
290
  process.loader = new Loader();
362
291
 
292
+ if (development_server_options?.environment === 'test') {
293
+ console.log(''); // NOTE: Silly, but gives us better styling.
294
+ process.loader.print("Initializing test environment...\n");
295
+ }
296
+
363
297
  process.env.LOGS_PATH = development_server_options?.logs || null;
364
298
  process.env.NODE_ENV = development_server_options?.environment || "development";
365
299
  process.env.PORT = port;
@@ -496,13 +430,29 @@ const development_server = async (development_server_options = {}) => {
496
430
  settings
497
431
  });
498
432
 
499
- // NOTE: Start test server if tests flag is enabled and this is not already a test server
500
- if (development_server_options?.tests && development_server_options?.environment !== 'test' && !development_server_options?._is_test_server) {
501
- await start_test_server({
502
- imports: development_server_options?.imports || [],
503
- });
504
- }
433
+ // NOTE: If tests flag is enabled, start a separate test server on port 1977
434
+ if (development_server_options?.tests && development_server_options?.environment !== 'test') {
435
+ const test_port_occupied = await check_if_port_occupied(1977);
436
+ if (test_port_occupied) {
437
+ await kill_port_process(1977);
438
+ }
505
439
 
440
+ // NOTE: Start test server in parallel using the same development_server function
441
+ // but with different options to avoid recursion and environment conflicts
442
+ setTimeout(async () => {
443
+ try {
444
+ await development_server({
445
+ environment: 'test',
446
+ port: 1977,
447
+ watch: false, // No file watching for test server
448
+ imports: development_server_options?.imports || [],
449
+ _is_test_server: true, // Internal flag to prevent infinite recursion
450
+ });
451
+ } catch (error) {
452
+ console.error('Error starting test server:', error);
453
+ }
454
+ }, 100); // Small delay to let main server start first
455
+ }
506
456
 
507
457
  // NOTE: Only set up file watching for non-test servers
508
458
  if (!development_server_options?._is_test_server) {