create-flow-os 0.0.1-dev.1771668141 → 0.0.1-dev.1771669629
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/bin/index.js +31 -32
- package/package.json +1 -1
- package/profiles/client/dev.ts +5 -0
- package/profiles/client/package.json +3 -3
- package/profiles/client/packages/client/build.ts +14 -0
- package/profiles/client/packages/client/config.ts +70 -2
- package/profiles/client/packages/client/preview.ts +14 -0
- package/profiles/client/packages/client/start-dev.ts +23 -0
- package/profiles/full/dev.ts +5 -0
- package/profiles/full/package.json +3 -3
- package/profiles/full/packages/client/build.ts +14 -0
- package/profiles/full/packages/client/config.ts +70 -2
- package/profiles/full/packages/client/preview.ts +14 -0
- package/profiles/full/packages/client/start-dev.ts +23 -0
- package/profiles/server/dev.ts +5 -0
- package/profiles/server/package.json +3 -3
package/bin/index.js
CHANGED
|
@@ -721,10 +721,6 @@ var he = (s = "") => {
|
|
|
721
721
|
|
|
722
722
|
`);
|
|
723
723
|
};
|
|
724
|
-
var pe = (s = "") => {
|
|
725
|
-
process.stdout.write(`${import_picocolors2.default.gray(Q2)} ${s}
|
|
726
|
-
`);
|
|
727
|
-
};
|
|
728
724
|
var ge = (s = "") => {
|
|
729
725
|
process.stdout.write(`${import_picocolors2.default.gray(a2)}
|
|
730
726
|
${import_picocolors2.default.gray($2)} ${s}
|
|
@@ -873,13 +869,21 @@ var nameArg = argv.find((a3) => !a3.startsWith("--"));
|
|
|
873
869
|
var DIR = basename(import.meta.dir) === "dist" || basename(import.meta.dir) === "bin" ? join2(import.meta.dir, "..") : import.meta.dir;
|
|
874
870
|
var REPO_ROOT = (process.env.FLOW_FRAMEWORK_ROOT ?? join2(DIR, "..", "..")).replace(/\\/g, "/");
|
|
875
871
|
var c2 = {
|
|
876
|
-
brand: (s) => import_picocolors3.default.cyan(s),
|
|
872
|
+
brand: (s) => import_picocolors3.default.bold(import_picocolors3.default.cyan(s)),
|
|
873
|
+
cyan: (s) => import_picocolors3.default.cyan(s),
|
|
877
874
|
dim: (s) => import_picocolors3.default.dim(s),
|
|
878
875
|
bold: (s) => import_picocolors3.default.bold(s),
|
|
879
|
-
muted: (s) => import_picocolors3.default.
|
|
876
|
+
muted: (s) => import_picocolors3.default.cyan(s),
|
|
880
877
|
bright: (s) => import_picocolors3.default.white(s)
|
|
881
878
|
};
|
|
882
879
|
var W2 = 50;
|
|
880
|
+
var ICON = {
|
|
881
|
+
full: "\u25C9",
|
|
882
|
+
client: "\u25C6",
|
|
883
|
+
server: "\u25CF",
|
|
884
|
+
deps: "\uD83D\uDCE6",
|
|
885
|
+
rocket: "\u25B6"
|
|
886
|
+
};
|
|
883
887
|
function stripAnsi(s) {
|
|
884
888
|
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
885
889
|
}
|
|
@@ -898,6 +902,13 @@ function box(lines) {
|
|
|
898
902
|
` + bottom + `
|
|
899
903
|
`;
|
|
900
904
|
}
|
|
905
|
+
async function runDev(cwd) {
|
|
906
|
+
const devProc = Bun.spawn(["bun", "run", "dev"], {
|
|
907
|
+
cwd,
|
|
908
|
+
stdio: ["inherit", "inherit", "inherit"]
|
|
909
|
+
});
|
|
910
|
+
await devProc.exited;
|
|
911
|
+
}
|
|
901
912
|
function optsForProfile(config, profileId) {
|
|
902
913
|
return Object.entries(config.packages).filter(([, e2]) => {
|
|
903
914
|
const inc = e2.includeIn ?? [];
|
|
@@ -909,13 +920,11 @@ function optsForProfile(config, profileId) {
|
|
|
909
920
|
});
|
|
910
921
|
}
|
|
911
922
|
async function main() {
|
|
912
|
-
const devBadge = useDevTag ? c2.
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
];
|
|
918
|
-
pe(box(introLines));
|
|
923
|
+
const devBadge = useDevTag ? c2.dim(" \xB7 dev") : "";
|
|
924
|
+
console.log(`
|
|
925
|
+
` + c2.bold("Flow OS") + devBadge + `
|
|
926
|
+
` + c2.dim("Create Flow OS application") + `
|
|
927
|
+
`);
|
|
919
928
|
const config = await Bun.file(join2(DIR, "config.json")).json();
|
|
920
929
|
const hasDeps = Object.values(config.packages).every((e2) => Array.isArray(e2.deps));
|
|
921
930
|
if (!hasDeps) {
|
|
@@ -946,9 +955,9 @@ async function main() {
|
|
|
946
955
|
const choice = await le({
|
|
947
956
|
message: c2.muted("Template"),
|
|
948
957
|
options: [
|
|
949
|
-
{ value: "full", label:
|
|
950
|
-
{ value: "client", label:
|
|
951
|
-
{ value: "server", label:
|
|
958
|
+
{ value: "full", label: `${ICON.full} Full stack ${c2.dim("(client + server)")}` },
|
|
959
|
+
{ value: "client", label: `${ICON.client} Client only` },
|
|
960
|
+
{ value: "server", label: `${ICON.server} Server only` }
|
|
952
961
|
]
|
|
953
962
|
});
|
|
954
963
|
if (lD(choice))
|
|
@@ -992,7 +1001,7 @@ async function main() {
|
|
|
992
1001
|
const isDevFromRepoPromise = useDevTag ? findPackageDir(REPO_ROOT, "@flow.os/client").then((d2) => !!d2) : Promise.resolve(false);
|
|
993
1002
|
await rm(projectPathNew, { recursive: true, force: true });
|
|
994
1003
|
const createSpinner = _2();
|
|
995
|
-
createSpinner.start(c2.
|
|
1004
|
+
createSpinner.start(c2.cyan(ICON.rocket + " Creating project\u2026"));
|
|
996
1005
|
await copyWithExclude(profileDir, projectPathNew, ["node_modules", ".git"]);
|
|
997
1006
|
for (const id of selected) {
|
|
998
1007
|
const pkgDir = join2(DIR, "packages", id);
|
|
@@ -1000,7 +1009,7 @@ async function main() {
|
|
|
1000
1009
|
await copyWithExclude(pkgDir, projectPathNew, []);
|
|
1001
1010
|
} catch {}
|
|
1002
1011
|
}
|
|
1003
|
-
createSpinner.stop(c2.
|
|
1012
|
+
createSpinner.stop(c2.cyan(ICON.rocket + " Project created"));
|
|
1004
1013
|
const extraDeps = {};
|
|
1005
1014
|
for (const id of selected) {
|
|
1006
1015
|
const deps = config.packages[id]?.deps;
|
|
@@ -1054,10 +1063,10 @@ async function main() {
|
|
|
1054
1063
|
}
|
|
1055
1064
|
if (!noInstall) {
|
|
1056
1065
|
const s = _2();
|
|
1057
|
-
s.start(c2.
|
|
1066
|
+
s.start(c2.cyan(ICON.deps + " Installing dependencies\u2026"));
|
|
1058
1067
|
const proc = Bun.spawn(["bun", "install"], { cwd: projectPathNew, stdout: "pipe", stderr: "pipe" });
|
|
1059
1068
|
const code = await proc.exited;
|
|
1060
|
-
s.stop(code === 0 ? c2.
|
|
1069
|
+
s.stop(code === 0 ? c2.cyan(ICON.deps + " Dependencies installed") : "Failed");
|
|
1061
1070
|
if (code !== 0) {
|
|
1062
1071
|
const err = await new Response(proc.stderr).text();
|
|
1063
1072
|
v2.error(err || "bun install exit " + code);
|
|
@@ -1070,18 +1079,8 @@ async function main() {
|
|
|
1070
1079
|
await rename(projectPathNew, projectPath);
|
|
1071
1080
|
const startDev = !noStart && !noInstall;
|
|
1072
1081
|
if (startDev) {
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
"",
|
|
1076
|
-
c2.dim("Project ") + c2.brand(name) + c2.dim(" is ready."),
|
|
1077
|
-
c2.dim("Starting dev server\u2026")
|
|
1078
|
-
];
|
|
1079
|
-
ge(box(outroLines));
|
|
1080
|
-
const devProc = Bun.spawn(["bun", "run", "dev"], {
|
|
1081
|
-
cwd: projectPath,
|
|
1082
|
-
stdio: ["inherit", "inherit", "inherit"]
|
|
1083
|
-
});
|
|
1084
|
-
await devProc.exited;
|
|
1082
|
+
ge(c2.cyan(ICON.rocket + " Starting dev server\u2026"));
|
|
1083
|
+
await runDev(projectPath);
|
|
1085
1084
|
} else {
|
|
1086
1085
|
const outroLines = [
|
|
1087
1086
|
c2.bold("Done"),
|
package/package.json
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"dev": "
|
|
8
|
-
"build": "tsc -b &&
|
|
9
|
-
"preview": "
|
|
7
|
+
"dev": "bun dev.ts",
|
|
8
|
+
"build": "tsc -b && bun packages/client/build.ts",
|
|
9
|
+
"preview": "bun packages/client/preview.ts",
|
|
10
10
|
"start": "bun node_modules/@flow.os/server/start.ts",
|
|
11
11
|
"lint": "oxlint .",
|
|
12
12
|
"fmt": "oxfmt",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { build } from 'vite';
|
|
5
|
+
|
|
6
|
+
const cwd = process.cwd();
|
|
7
|
+
const configPath = join(cwd, 'flow.config.ts');
|
|
8
|
+
const mod = await import(pathToFileURL(configPath).href).catch((e: Error) => {
|
|
9
|
+
console.error('Flow: could not load flow.config.ts:', e.message);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
});
|
|
12
|
+
const getConfig = mod.default;
|
|
13
|
+
const config = typeof getConfig === 'function' ? await getConfig() : getConfig;
|
|
14
|
+
await build(config);
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
3
4
|
import type { Plugin } from 'vite';
|
|
5
|
+
import { createLogger } from 'vite';
|
|
6
|
+
|
|
7
|
+
const cyan = (s: string) => `\x1b[36m${s}\x1b[0m`;
|
|
8
|
+
const bold = (s: string) => `\x1b[1m${s}\x1b[0m`;
|
|
9
|
+
const dim = (s: string) => `\x1b[2m${s}\x1b[0m`;
|
|
10
|
+
const stripAnsi = (s: string) => s.replace(/\x1b\[[0-9;]*m/g, '');
|
|
11
|
+
const CONTENT_W = 48;
|
|
12
|
+
const BORDER_W = 52;
|
|
13
|
+
|
|
14
|
+
function getNetworkUrl(port: number): string | null {
|
|
15
|
+
const ifaces = os.networkInterfaces();
|
|
16
|
+
for (const list of Object.values(ifaces ?? {})) {
|
|
17
|
+
if (!list) continue;
|
|
18
|
+
for (const i of list) {
|
|
19
|
+
if (i.family === 'IPv4' && !i.internal) return `http://${i.address}:${port}/`;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
4
24
|
|
|
5
25
|
/** Solo in monorepo (esiste packages/): Rollup in Docker non segue i symlink, quindi alias a path assoluti. Generico: legge packages/ e mappa tutto. Fuori monorepo (npm) ritorna {}. */
|
|
6
26
|
function resolveAlias(): Record<string, string> {
|
|
@@ -50,6 +70,41 @@ const DEFAULTS = {
|
|
|
50
70
|
plugins: [] as Plugin[],
|
|
51
71
|
};
|
|
52
72
|
|
|
73
|
+
/** Banner Flow OS: sostituisce l'output di Vite con uno custom (Local + Network, box, colori). */
|
|
74
|
+
function flowServerUrlPlugin(hostEnabled: boolean): Plugin {
|
|
75
|
+
return {
|
|
76
|
+
name: 'flow:server-url',
|
|
77
|
+
configureServer(server) {
|
|
78
|
+
(server as { printUrls?: () => void }).printUrls = () => {};
|
|
79
|
+
server.httpServer?.once('listening', () => {
|
|
80
|
+
const addr = server.httpServer?.address();
|
|
81
|
+
if (!addr || typeof addr !== 'object' || !('port' in addr)) return;
|
|
82
|
+
const port = (addr as { port: number }).port;
|
|
83
|
+
const host = (addr as { address: string }).address;
|
|
84
|
+
const localHost = host === '::' || host === '0.0.0.0' ? 'localhost' : host;
|
|
85
|
+
const localUrl = `http://${localHost}:${port}/`;
|
|
86
|
+
const networkUrl = hostEnabled ? getNetworkUrl(port) : null;
|
|
87
|
+
|
|
88
|
+
const line = (content: string) => {
|
|
89
|
+
const pad = Math.max(0, CONTENT_W - stripAnsi(content).length);
|
|
90
|
+
return dim(' │ ') + content + ' '.repeat(pad) + dim(' │');
|
|
91
|
+
};
|
|
92
|
+
const border = (c: string) => dim(' ' + c + '─'.repeat(BORDER_W) + (c === '╭' ? '╮' : '╯'));
|
|
93
|
+
const out: string[] = [
|
|
94
|
+
'',
|
|
95
|
+
border('╭'),
|
|
96
|
+
line(bold('Flow OS') + dim(' is running')),
|
|
97
|
+
line(cyan('◆') + ' ' + dim('Local: ') + cyan(localUrl)),
|
|
98
|
+
...(networkUrl ? [line(dim('Network: ') + cyan(networkUrl))] : []),
|
|
99
|
+
border('╰'),
|
|
100
|
+
'',
|
|
101
|
+
];
|
|
102
|
+
console.log(out.join('\n'));
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
53
108
|
/** Config per flow.config.ts. Client + Vite; server opzionale con server: flowServer(). */
|
|
54
109
|
export default function config(
|
|
55
110
|
options: FlowConfigOptions = {}
|
|
@@ -57,11 +112,24 @@ export default function config(
|
|
|
57
112
|
const { port = DEFAULTS.port, host = DEFAULTS.host, server = DEFAULTS.server, plugins = DEFAULTS.plugins } = options;
|
|
58
113
|
return async () => {
|
|
59
114
|
const { flow } = await import('./vite.js');
|
|
60
|
-
const allPlugins =
|
|
115
|
+
const allPlugins = [
|
|
116
|
+
flowServerUrlPlugin(host === true),
|
|
117
|
+
...(server ? [server, flow(), ...plugins] : [flow(), ...plugins]),
|
|
118
|
+
];
|
|
61
119
|
const alias = resolveAlias();
|
|
120
|
+
const baseLogger = createLogger('info');
|
|
121
|
+
const customLogger = {
|
|
122
|
+
...baseLogger,
|
|
123
|
+
info: (msg: string, opts?: { clear?: boolean }) => {
|
|
124
|
+
const t = msg.replace(/\s+/g, ' ');
|
|
125
|
+
if (/VITE\s+v?\d|ready\s+in|Local:\s*http|Network:\s*http|press\s+h\s+enter/i.test(t)) return;
|
|
126
|
+
baseLogger.info(msg, opts);
|
|
127
|
+
},
|
|
128
|
+
};
|
|
62
129
|
return {
|
|
63
130
|
resolve: Object.keys(alias).length ? { alias } : {},
|
|
64
|
-
server: { port, host },
|
|
131
|
+
server: { port, host, strictPort: false },
|
|
132
|
+
customLogger,
|
|
65
133
|
build: {
|
|
66
134
|
rollupOptions: {
|
|
67
135
|
external: ['@flow.os/server', /^@flow.os\/server\/.+/],
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { preview } from 'vite';
|
|
5
|
+
|
|
6
|
+
const cwd = process.cwd();
|
|
7
|
+
const configPath = join(cwd, 'flow.config.ts');
|
|
8
|
+
const mod = await import(pathToFileURL(configPath).href).catch((e: Error) => {
|
|
9
|
+
console.error('Flow: could not load flow.config.ts:', e.message);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
});
|
|
12
|
+
const getConfig = mod.default;
|
|
13
|
+
const config = typeof getConfig === 'function' ? await getConfig() : getConfig;
|
|
14
|
+
await preview(config);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Flow OS dev server runner. Loads flow.config.ts and starts the dev server.
|
|
4
|
+
* Usage: bun node_modules/@flow.os/client/start-dev.ts (or bun packages/client/start-dev.ts in monorepo)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { pathToFileURL } from 'node:url';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { createServer } from 'vite';
|
|
10
|
+
|
|
11
|
+
const cwd = process.cwd();
|
|
12
|
+
const configPath = join(cwd, 'flow.config.ts');
|
|
13
|
+
const configUrl = pathToFileURL(configPath).href;
|
|
14
|
+
|
|
15
|
+
const mod = await import(configUrl).catch((e: Error) => {
|
|
16
|
+
console.error('Flow: could not load flow.config.ts:', e.message);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
|
19
|
+
const getConfig = mod.default;
|
|
20
|
+
const config = typeof getConfig === 'function' ? await getConfig() : getConfig;
|
|
21
|
+
const server = await createServer(config);
|
|
22
|
+
await server.listen();
|
|
23
|
+
server.watcher.on('change', () => {});
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"dev": "
|
|
8
|
-
"build": "tsc -b &&
|
|
9
|
-
"preview": "
|
|
7
|
+
"dev": "bun dev.ts",
|
|
8
|
+
"build": "tsc -b && bun packages/client/build.ts",
|
|
9
|
+
"preview": "bun packages/client/preview.ts",
|
|
10
10
|
"start": "bun node_modules/@flow.os/server/start.ts",
|
|
11
11
|
"lint": "oxlint .",
|
|
12
12
|
"fmt": "oxfmt",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { build } from 'vite';
|
|
5
|
+
|
|
6
|
+
const cwd = process.cwd();
|
|
7
|
+
const configPath = join(cwd, 'flow.config.ts');
|
|
8
|
+
const mod = await import(pathToFileURL(configPath).href).catch((e: Error) => {
|
|
9
|
+
console.error('Flow: could not load flow.config.ts:', e.message);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
});
|
|
12
|
+
const getConfig = mod.default;
|
|
13
|
+
const config = typeof getConfig === 'function' ? await getConfig() : getConfig;
|
|
14
|
+
await build(config);
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
3
4
|
import type { Plugin } from 'vite';
|
|
5
|
+
import { createLogger } from 'vite';
|
|
6
|
+
|
|
7
|
+
const cyan = (s: string) => `\x1b[36m${s}\x1b[0m`;
|
|
8
|
+
const bold = (s: string) => `\x1b[1m${s}\x1b[0m`;
|
|
9
|
+
const dim = (s: string) => `\x1b[2m${s}\x1b[0m`;
|
|
10
|
+
const stripAnsi = (s: string) => s.replace(/\x1b\[[0-9;]*m/g, '');
|
|
11
|
+
const CONTENT_W = 48;
|
|
12
|
+
const BORDER_W = 52;
|
|
13
|
+
|
|
14
|
+
function getNetworkUrl(port: number): string | null {
|
|
15
|
+
const ifaces = os.networkInterfaces();
|
|
16
|
+
for (const list of Object.values(ifaces ?? {})) {
|
|
17
|
+
if (!list) continue;
|
|
18
|
+
for (const i of list) {
|
|
19
|
+
if (i.family === 'IPv4' && !i.internal) return `http://${i.address}:${port}/`;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
4
24
|
|
|
5
25
|
/** Solo in monorepo (esiste packages/): Rollup in Docker non segue i symlink, quindi alias a path assoluti. Generico: legge packages/ e mappa tutto. Fuori monorepo (npm) ritorna {}. */
|
|
6
26
|
function resolveAlias(): Record<string, string> {
|
|
@@ -50,6 +70,41 @@ const DEFAULTS = {
|
|
|
50
70
|
plugins: [] as Plugin[],
|
|
51
71
|
};
|
|
52
72
|
|
|
73
|
+
/** Banner Flow OS: sostituisce l'output di Vite con uno custom (Local + Network, box, colori). */
|
|
74
|
+
function flowServerUrlPlugin(hostEnabled: boolean): Plugin {
|
|
75
|
+
return {
|
|
76
|
+
name: 'flow:server-url',
|
|
77
|
+
configureServer(server) {
|
|
78
|
+
(server as { printUrls?: () => void }).printUrls = () => {};
|
|
79
|
+
server.httpServer?.once('listening', () => {
|
|
80
|
+
const addr = server.httpServer?.address();
|
|
81
|
+
if (!addr || typeof addr !== 'object' || !('port' in addr)) return;
|
|
82
|
+
const port = (addr as { port: number }).port;
|
|
83
|
+
const host = (addr as { address: string }).address;
|
|
84
|
+
const localHost = host === '::' || host === '0.0.0.0' ? 'localhost' : host;
|
|
85
|
+
const localUrl = `http://${localHost}:${port}/`;
|
|
86
|
+
const networkUrl = hostEnabled ? getNetworkUrl(port) : null;
|
|
87
|
+
|
|
88
|
+
const line = (content: string) => {
|
|
89
|
+
const pad = Math.max(0, CONTENT_W - stripAnsi(content).length);
|
|
90
|
+
return dim(' │ ') + content + ' '.repeat(pad) + dim(' │');
|
|
91
|
+
};
|
|
92
|
+
const border = (c: string) => dim(' ' + c + '─'.repeat(BORDER_W) + (c === '╭' ? '╮' : '╯'));
|
|
93
|
+
const out: string[] = [
|
|
94
|
+
'',
|
|
95
|
+
border('╭'),
|
|
96
|
+
line(bold('Flow OS') + dim(' is running')),
|
|
97
|
+
line(cyan('◆') + ' ' + dim('Local: ') + cyan(localUrl)),
|
|
98
|
+
...(networkUrl ? [line(dim('Network: ') + cyan(networkUrl))] : []),
|
|
99
|
+
border('╰'),
|
|
100
|
+
'',
|
|
101
|
+
];
|
|
102
|
+
console.log(out.join('\n'));
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
53
108
|
/** Config per flow.config.ts. Client + Vite; server opzionale con server: flowServer(). */
|
|
54
109
|
export default function config(
|
|
55
110
|
options: FlowConfigOptions = {}
|
|
@@ -57,11 +112,24 @@ export default function config(
|
|
|
57
112
|
const { port = DEFAULTS.port, host = DEFAULTS.host, server = DEFAULTS.server, plugins = DEFAULTS.plugins } = options;
|
|
58
113
|
return async () => {
|
|
59
114
|
const { flow } = await import('./vite.js');
|
|
60
|
-
const allPlugins =
|
|
115
|
+
const allPlugins = [
|
|
116
|
+
flowServerUrlPlugin(host === true),
|
|
117
|
+
...(server ? [server, flow(), ...plugins] : [flow(), ...plugins]),
|
|
118
|
+
];
|
|
61
119
|
const alias = resolveAlias();
|
|
120
|
+
const baseLogger = createLogger('info');
|
|
121
|
+
const customLogger = {
|
|
122
|
+
...baseLogger,
|
|
123
|
+
info: (msg: string, opts?: { clear?: boolean }) => {
|
|
124
|
+
const t = msg.replace(/\s+/g, ' ');
|
|
125
|
+
if (/VITE\s+v?\d|ready\s+in|Local:\s*http|Network:\s*http|press\s+h\s+enter/i.test(t)) return;
|
|
126
|
+
baseLogger.info(msg, opts);
|
|
127
|
+
},
|
|
128
|
+
};
|
|
62
129
|
return {
|
|
63
130
|
resolve: Object.keys(alias).length ? { alias } : {},
|
|
64
|
-
server: { port, host },
|
|
131
|
+
server: { port, host, strictPort: false },
|
|
132
|
+
customLogger,
|
|
65
133
|
build: {
|
|
66
134
|
rollupOptions: {
|
|
67
135
|
external: ['@flow.os/server', /^@flow.os\/server\/.+/],
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { preview } from 'vite';
|
|
5
|
+
|
|
6
|
+
const cwd = process.cwd();
|
|
7
|
+
const configPath = join(cwd, 'flow.config.ts');
|
|
8
|
+
const mod = await import(pathToFileURL(configPath).href).catch((e: Error) => {
|
|
9
|
+
console.error('Flow: could not load flow.config.ts:', e.message);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
});
|
|
12
|
+
const getConfig = mod.default;
|
|
13
|
+
const config = typeof getConfig === 'function' ? await getConfig() : getConfig;
|
|
14
|
+
await preview(config);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Flow OS dev server runner. Loads flow.config.ts and starts the dev server.
|
|
4
|
+
* Usage: bun node_modules/@flow.os/client/start-dev.ts (or bun packages/client/start-dev.ts in monorepo)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { pathToFileURL } from 'node:url';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { createServer } from 'vite';
|
|
10
|
+
|
|
11
|
+
const cwd = process.cwd();
|
|
12
|
+
const configPath = join(cwd, 'flow.config.ts');
|
|
13
|
+
const configUrl = pathToFileURL(configPath).href;
|
|
14
|
+
|
|
15
|
+
const mod = await import(configUrl).catch((e: Error) => {
|
|
16
|
+
console.error('Flow: could not load flow.config.ts:', e.message);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
|
19
|
+
const getConfig = mod.default;
|
|
20
|
+
const config = typeof getConfig === 'function' ? await getConfig() : getConfig;
|
|
21
|
+
const server = await createServer(config);
|
|
22
|
+
await server.listen();
|
|
23
|
+
server.watcher.on('change', () => {});
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"dev": "
|
|
8
|
-
"build": "tsc -b &&
|
|
9
|
-
"preview": "
|
|
7
|
+
"dev": "bun dev.ts",
|
|
8
|
+
"build": "tsc -b && bun packages/client/build.ts",
|
|
9
|
+
"preview": "bun packages/client/preview.ts",
|
|
10
10
|
"start": "bun node_modules/@flow.os/server/start.ts",
|
|
11
11
|
"lint": "oxlint .",
|
|
12
12
|
"fmt": "oxfmt",
|