@iyexin/mio-cli 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +30 -0
- package/README.md +108 -2
- package/dist/asar.d.ts +11 -0
- package/dist/asar.js +43 -0
- package/dist/asar.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +10 -0
- package/dist/bin.js.map +1 -0
- package/dist/build-android.d.ts +13 -0
- package/dist/build-android.js +93 -0
- package/dist/build-android.js.map +1 -0
- package/dist/build-windows.d.ts +13 -0
- package/dist/build-windows.js +73 -0
- package/dist/build-windows.js.map +1 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +14 -0
- package/dist/constants.js +15 -0
- package/dist/constants.js.map +1 -0
- package/dist/create.d.ts +5 -0
- package/dist/create.js +58 -0
- package/dist/create.js.map +1 -0
- package/dist/dev.d.ts +9 -0
- package/dist/dev.js +165 -0
- package/dist/dev.js.map +1 -0
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.js +56 -0
- package/dist/doctor.js.map +1 -0
- package/dist/download.d.ts +19 -0
- package/dist/download.js +115 -0
- package/dist/download.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +118 -0
- package/dist/index.js.map +1 -0
- package/dist/project.d.ts +12 -0
- package/dist/project.js +55 -0
- package/dist/project.js.map +1 -0
- package/dist/templates.d.ts +35 -0
- package/dist/templates.js +288 -0
- package/dist/templates.js.map +1 -0
- package/dist/web.d.ts +3 -0
- package/dist/web.js +33 -0
- package/dist/web.js.map +1 -0
- package/package.json +54 -5
- package/templates/web/icon.png +0 -0
- package/templates/web/index.html +113 -0
- package/templates/web/mio.config.json +20 -0
- package/templates/web/package.json +18 -0
- package/templates/web/src/main.ts +158 -0
- package/templates/web/src/style.css +389 -0
- package/templates/web/vite.config.ts +12 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mio contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Third-party components (Flutter/Dart, webview_flutter, webview_flutter_windows,
|
|
26
|
+
window_manager, file_selector, url_launcher, path_provider, @electron/asar,
|
|
27
|
+
resedit, apksigner/zipalign, and the Dart/npm dependencies listed in
|
|
28
|
+
packages/*/THIRD_PARTY_NOTICES.md) keep their own licenses. The prebuilt
|
|
29
|
+
Android/Windows templates in packages/cli/templates embed the Flutter engine;
|
|
30
|
+
review those licenses before redistributing an app built with Mio.
|
package/README.md
CHANGED
|
@@ -1,3 +1,109 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @iyexin/mio-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Mio 应用 CLI。
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @iyexin/mio-cli create my-app
|
|
7
|
+
npx @iyexin/mio-cli build --platform android
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
或全局安装后直接用 `mio`:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install -g @iyexin/mio-cli
|
|
14
|
+
mio create my-app
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
mio create [target] [--no-install]
|
|
19
|
+
mio build [--platform android|windows] [--skip-web] [--template <path>]
|
|
20
|
+
mio dev --platform android|windows [--no-install] [--template <path>]
|
|
21
|
+
mio doctor
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 模板从哪里来
|
|
25
|
+
|
|
26
|
+
预编译模板不再随包分发(体积)。`mio build` / `mio dev` 按这个顺序找模板:
|
|
27
|
+
|
|
28
|
+
1. `--template <path>`,或 `mio.config.json` 的 `android.template` / `windows.templateDir`,
|
|
29
|
+
或环境变量 `MIO_ANDROID_TEMPLATE` / `MIO_WINDOWS_TEMPLATE`;
|
|
30
|
+
2. 仓库 checkout 里的 `packages/cli/templates`(由 `scripts/build-templates.ps1` 生成);
|
|
31
|
+
3. 本地缓存 `%LOCALAPPDATA%\mio\templates\<版本>\`(或 `~/.cache/mio/templates/...`);
|
|
32
|
+
4. 从 GitHub Release 下载模板与 `manifest.json`,校验 sha256 后缓存。
|
|
33
|
+
|
|
34
|
+
模板的 `apiVersion` 主版本必须与 CLI 一致;单 ABI 模板还会校验 APK 里确实包含该 ABI。
|
|
35
|
+
|
|
36
|
+
下载会走 `HTTPS_PROXY` / `HTTP_PROXY`,若都没设置则回退到 `git config http.proxy`;
|
|
37
|
+
`NO_PROXY` 生效。下载失败会提示如何配置代理。缓存目录:
|
|
38
|
+
`%LOCALAPPDATA%\mio\templates\<版本>\`(Linux/macOS 为 `$XDG_CACHE_HOME/mio/...` 或
|
|
39
|
+
`~/.cache/mio/...`)。
|
|
40
|
+
|
|
41
|
+
## create
|
|
42
|
+
|
|
43
|
+
复制 `templates/web`,把 `@iyexin/mio-api` 复制到项目 `.mio/mio-api`(file dependency),
|
|
44
|
+
避免要求发布 npm 包。默认执行 `npm install`,可用 `--no-install` 跳过。
|
|
45
|
+
|
|
46
|
+
## build
|
|
47
|
+
|
|
48
|
+
读取 `mio.config.json`,执行 `npm run build`(可用 `--skip-web`),生成 asar,
|
|
49
|
+
然后:
|
|
50
|
+
|
|
51
|
+
- Android:注入模板 APK、替换图标、zipalign、apksigner 重签;
|
|
52
|
+
- Windows:复制模板目录、PE 资源注入。
|
|
53
|
+
|
|
54
|
+
输出:
|
|
55
|
+
|
|
56
|
+
- `build/mio/android/<AppName>-<version>.apk`
|
|
57
|
+
- `build/mio/windows/<AppName>/`
|
|
58
|
+
|
|
59
|
+
### Android 模板与 ABI
|
|
60
|
+
|
|
61
|
+
模板按 ABI 预构建,用 `android.abi` 或 `--abi` 选择:
|
|
62
|
+
|
|
63
|
+
| abi | 体积 | 适用 |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `arm64`(默认) | 约 19 MB | 现代真机 |
|
|
66
|
+
| `universal` | 约 53 MB | 32 位设备、任何模拟器 |
|
|
67
|
+
| `x64` | 约 20 MB | 仅模拟器(默认不随 CLI 分发) |
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
mio build --platform android --abi universal
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`mio dev` 始终优先用 universal 模板,因为开发机常连模拟器。
|
|
74
|
+
|
|
75
|
+
调试构建自动使用 `.mio/debug.p12`。发布构建通过配置:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"android": {
|
|
80
|
+
"keystore": "release.p12",
|
|
81
|
+
"alias": "release",
|
|
82
|
+
"storePasswordEnv": "MIO_KS_PASS",
|
|
83
|
+
"keyPasswordEnv": "MIO_KEY_PASS"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## dev
|
|
89
|
+
|
|
90
|
+
启动 Vite(自动选择空闲端口),然后:
|
|
91
|
+
|
|
92
|
+
- Windows:启动模板 exe,设置 `MIO_DEV_URL` 与 app 元信息 env;
|
|
93
|
+
- Android:`adb reverse`、安装模板 APK、用 intent extra 启动。
|
|
94
|
+
|
|
95
|
+
## doctor
|
|
96
|
+
|
|
97
|
+
检查 Node、Android tools、adb、模板路径。
|
|
98
|
+
|
|
99
|
+
## Windows 签名
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"windows": {
|
|
104
|
+
"signCommand": "signtool sign /fd SHA256 /a {exe}"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`{exe}` 会替换为最终 exe 路径;命令在项目目录执行。也可以接 `signtool` 或云签名 CLI。
|
package/dist/asar.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MioConfig } from "./config.js";
|
|
2
|
+
export interface CreateAsarOptions {
|
|
3
|
+
webDir: string;
|
|
4
|
+
output: string;
|
|
5
|
+
config: MioConfig;
|
|
6
|
+
}
|
|
7
|
+
export interface CreateAsarResult {
|
|
8
|
+
output: string;
|
|
9
|
+
size: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function createAppAsar(options: CreateAsarOptions): Promise<CreateAsarResult>;
|
package/dist/asar.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { copyFile, cp, mkdir, mkdtemp, rm, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { createPackage } from "@electron/asar";
|
|
6
|
+
import { MIO_API_VERSION, MIO_CLI_VERSION } from "./constants.js";
|
|
7
|
+
export async function createAppAsar(options) {
|
|
8
|
+
const stage = await mkdtemp(join(tmpdir(), "mio-asar-"));
|
|
9
|
+
try {
|
|
10
|
+
await cp(options.webDir, stage, { recursive: true });
|
|
11
|
+
const manifest = {
|
|
12
|
+
id: options.config.app.id,
|
|
13
|
+
name: options.config.app.name,
|
|
14
|
+
version: options.config.app.version,
|
|
15
|
+
entry: "index.html",
|
|
16
|
+
window: {
|
|
17
|
+
width: options.config.window?.width ?? 1024,
|
|
18
|
+
height: options.config.window?.height ?? 720,
|
|
19
|
+
title: options.config.window?.title ?? options.config.app.name,
|
|
20
|
+
backgroundColor: options.config.window?.backgroundColor ?? "#0f1115",
|
|
21
|
+
},
|
|
22
|
+
requires: {
|
|
23
|
+
apiVersion: MIO_API_VERSION,
|
|
24
|
+
},
|
|
25
|
+
build: {
|
|
26
|
+
cli: MIO_CLI_VERSION,
|
|
27
|
+
api: MIO_API_VERSION,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
await writeFile(join(stage, "mio-manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
31
|
+
const require = createRequire(import.meta.url);
|
|
32
|
+
const bootstrap = require.resolve("@iyexin/mio-api/bootstrap.js");
|
|
33
|
+
await mkdir(join(stage, "__mio__"), { recursive: true });
|
|
34
|
+
await copyFile(bootstrap, join(stage, "__mio__", "bootstrap.js"));
|
|
35
|
+
await createPackage(stage, options.output);
|
|
36
|
+
const info = await stat(options.output);
|
|
37
|
+
return { output: options.output, size: info.size };
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
await rm(stage, { recursive: true, force: true });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=asar.js.map
|
package/dist/asar.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asar.js","sourceRoot":"","sources":["../src/asar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAalE,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA0B;IAC5D,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG;YACf,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;YACzB,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;YAC7B,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO;YACnC,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE;gBACN,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI;gBAC3C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG;gBAC5C,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;gBAC9D,eAAe,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,IAAI,SAAS;aACrE;YACD,QAAQ,EAAE;gBACR,UAAU,EAAE,eAAe;aAC5B;YACD,KAAK,EAAE;gBACL,GAAG,EAAE,eAAe;gBACpB,GAAG,EAAE,eAAe;aACrB;SACF,CAAC;QACF,MAAM,SAAS,CACb,IAAI,CAAC,KAAK,EAAE,mBAAmB,CAAC,EAChC,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EACxC,MAAM,CACP,CAAC;QAEF,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC;QAClE,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,MAAM,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC;QAElE,MAAM,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACxC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IACrD,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
|
package/dist/bin.d.ts
ADDED
package/dist/bin.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { main } from "./index.js";
|
|
3
|
+
main().catch((error) => {
|
|
4
|
+
console.error(error instanceof Error ? error.message : error);
|
|
5
|
+
if (error instanceof Error && error.stack && process.env.MIO_DEBUG) {
|
|
6
|
+
console.error(error.stack);
|
|
7
|
+
}
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC9D,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACnE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LoadedConfig } from "./config.js";
|
|
2
|
+
export interface BuildAndroidOptions {
|
|
3
|
+
loaded: LoadedConfig;
|
|
4
|
+
skipWeb: boolean;
|
|
5
|
+
/** Overrides the resolved template path (--template). */
|
|
6
|
+
template?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface BuildAndroidResult {
|
|
9
|
+
output: string;
|
|
10
|
+
size: number;
|
|
11
|
+
verified: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function buildAndroid(options: BuildAndroidOptions): Promise<BuildAndroidResult>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { mkdtemp, rm, stat } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { discoverAndroidTools, ensureDebugKeystore, injectApk, signApk, } from "@iyexin/mio-android-tools";
|
|
5
|
+
import { createAppAsar } from "./asar.js";
|
|
6
|
+
import { resolveAndroidTemplate } from "./templates.js";
|
|
7
|
+
import { ensureWebBuild } from "./web.js";
|
|
8
|
+
import { safeName } from "./project.js";
|
|
9
|
+
export async function buildAndroid(options) {
|
|
10
|
+
const { config, projectDir } = options.loaded;
|
|
11
|
+
const webDir = await ensureWebBuild(projectDir, config, options.skipWeb);
|
|
12
|
+
const template = await resolveAndroidTemplate(projectDir, config, {
|
|
13
|
+
explicit: options.template,
|
|
14
|
+
log: (message) => console.error(message),
|
|
15
|
+
});
|
|
16
|
+
const tools = await discoverAndroidTools();
|
|
17
|
+
const temp = await mkdtemp(join(tmpdir(), "mio-android-build-"));
|
|
18
|
+
const asarPath = join(temp, "app.asar");
|
|
19
|
+
const unsigned = join(temp, "app-unsigned.apk");
|
|
20
|
+
const outputDir = resolve(projectDir, "build", "mio", "android");
|
|
21
|
+
const output = join(outputDir, `${safeName(config.app.name)}-${config.app.version}.apk`);
|
|
22
|
+
try {
|
|
23
|
+
const asar = await createAppAsar({ webDir, output: asarPath, config });
|
|
24
|
+
await injectApk({
|
|
25
|
+
templateApk: template.path,
|
|
26
|
+
asar: asarPath,
|
|
27
|
+
output: unsigned,
|
|
28
|
+
manifest: {
|
|
29
|
+
packageName: config.app.id,
|
|
30
|
+
versionCode: versionCode(config.app.version),
|
|
31
|
+
versionName: config.app.version,
|
|
32
|
+
appName: config.app.name,
|
|
33
|
+
},
|
|
34
|
+
icon: config.app.icon ? resolve(projectDir, config.app.icon) : undefined,
|
|
35
|
+
});
|
|
36
|
+
const signing = await resolveSigning(options.loaded, tools);
|
|
37
|
+
const signed = await signApk({
|
|
38
|
+
tools,
|
|
39
|
+
input: unsigned,
|
|
40
|
+
output,
|
|
41
|
+
keystore: signing.keystore,
|
|
42
|
+
keystorePassword: signing.password,
|
|
43
|
+
keyAlias: signing.alias,
|
|
44
|
+
keyPassword: signing.keyPassword,
|
|
45
|
+
minSdkVersion: config.android?.minSdk ?? 24,
|
|
46
|
+
pageSize: config.android?.pageSize ?? 16,
|
|
47
|
+
});
|
|
48
|
+
const info = await stat(output);
|
|
49
|
+
return {
|
|
50
|
+
output,
|
|
51
|
+
size: info.size,
|
|
52
|
+
verified: signed.verify.verified,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
await rm(temp, { recursive: true, force: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function resolveSigning(loaded, tools) {
|
|
60
|
+
const { config, projectDir } = loaded;
|
|
61
|
+
if (config.android?.keystore) {
|
|
62
|
+
const keystore = resolve(projectDir, config.android.keystore);
|
|
63
|
+
const passwordEnv = config.android.storePasswordEnv ?? "MIO_KS_PASS";
|
|
64
|
+
const password = process.env[passwordEnv];
|
|
65
|
+
if (!password) {
|
|
66
|
+
throw new Error(`Release keystore password is missing: set ${passwordEnv}`);
|
|
67
|
+
}
|
|
68
|
+
const keyEnv = config.android.keyPasswordEnv;
|
|
69
|
+
const keyPassword = keyEnv ? process.env[keyEnv] : undefined;
|
|
70
|
+
return {
|
|
71
|
+
keystore,
|
|
72
|
+
alias: config.android.alias ?? "release",
|
|
73
|
+
password,
|
|
74
|
+
keyPassword,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const keystore = join(projectDir, ".mio", "debug.p12");
|
|
78
|
+
const debug = await ensureDebugKeystore(tools, { path: keystore });
|
|
79
|
+
return {
|
|
80
|
+
keystore: debug.path,
|
|
81
|
+
alias: debug.alias,
|
|
82
|
+
password: debug.password,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function versionCode(version) {
|
|
86
|
+
const [majorPart = "1", minorPart = "0", patchPart = "0"] = version.split(/[.+-]/);
|
|
87
|
+
const major = Number.parseInt(majorPart, 10) || 1;
|
|
88
|
+
const minor = Number.parseInt(minorPart, 10) || 0;
|
|
89
|
+
const patch = Number.parseInt(patchPart, 10) || 0;
|
|
90
|
+
const code = major * 1_000_000 + minor * 1_000 + patch;
|
|
91
|
+
return Math.max(1, Math.min(2_100_000_000, code));
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=build-android.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-android.js","sourceRoot":"","sources":["../src/build-android.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LoadedConfig } from "./config.js";
|
|
2
|
+
export interface BuildWindowsOptions {
|
|
3
|
+
loaded: LoadedConfig;
|
|
4
|
+
skipWeb: boolean;
|
|
5
|
+
/** Overrides the resolved template path (--template). */
|
|
6
|
+
template?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface BuildWindowsResult {
|
|
9
|
+
outputDir: string;
|
|
10
|
+
exe: string;
|
|
11
|
+
size: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function buildWindows(options: BuildWindowsOptions): Promise<BuildWindowsResult>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { cp, mkdtemp, rm, stat, copyFile, readdir, rename } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { injectWindowsExe } from "@iyexin/mio-android-tools";
|
|
5
|
+
import { createAppAsar } from "./asar.js";
|
|
6
|
+
import { resolveWindowsTemplate } from "./templates.js";
|
|
7
|
+
import { ensureWebBuild, runShell } from "./web.js";
|
|
8
|
+
import { findFirstExe, safeName } from "./project.js";
|
|
9
|
+
export async function buildWindows(options) {
|
|
10
|
+
const { config, projectDir } = options.loaded;
|
|
11
|
+
const webDir = await ensureWebBuild(projectDir, config, options.skipWeb);
|
|
12
|
+
const template = await resolveWindowsTemplate(projectDir, config, {
|
|
13
|
+
explicit: options.template,
|
|
14
|
+
log: (message) => console.error(message),
|
|
15
|
+
});
|
|
16
|
+
const templateDir = template.path;
|
|
17
|
+
const outputDir = resolve(projectDir, "build", "mio", "windows", safeName(config.app.name));
|
|
18
|
+
const temp = await mkdtemp(join(tmpdir(), "mio-windows-build-"));
|
|
19
|
+
const asarPath = join(temp, "app.asar");
|
|
20
|
+
const injectedExe = join(temp, "injected.exe");
|
|
21
|
+
try {
|
|
22
|
+
await createAppAsar({ webDir, output: asarPath, config });
|
|
23
|
+
await rm(outputDir, { recursive: true, force: true });
|
|
24
|
+
await cp(templateDir, outputDir, { recursive: true });
|
|
25
|
+
const configuredExe = config.windows?.exe;
|
|
26
|
+
const exe = configuredExe
|
|
27
|
+
? join(outputDir, configuredExe)
|
|
28
|
+
: await findFirstExe(outputDir);
|
|
29
|
+
if (!exe)
|
|
30
|
+
throw new Error(`Windows template has no exe: ${templateDir}`);
|
|
31
|
+
await injectWindowsExe({
|
|
32
|
+
templateExe: exe,
|
|
33
|
+
asar: asarPath,
|
|
34
|
+
output: injectedExe,
|
|
35
|
+
appName: config.app.name,
|
|
36
|
+
version: config.app.version,
|
|
37
|
+
icon: config.app.icon ? resolve(projectDir, config.app.icon) : undefined,
|
|
38
|
+
});
|
|
39
|
+
await copyFile(injectedExe, exe);
|
|
40
|
+
const finalExe = config.windows?.exe
|
|
41
|
+
? exe
|
|
42
|
+
: join(outputDir, `${safeName(config.app.name)}.exe`);
|
|
43
|
+
if (finalExe !== exe) {
|
|
44
|
+
await rm(finalExe, { force: true });
|
|
45
|
+
await rename(exe, finalExe);
|
|
46
|
+
}
|
|
47
|
+
if (config.windows?.signCommand) {
|
|
48
|
+
const command = config.windows.signCommand.replaceAll("{exe}", `"${finalExe}"`);
|
|
49
|
+
await runShell(command, projectDir);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
outputDir,
|
|
53
|
+
exe: finalExe,
|
|
54
|
+
size: await directorySize(outputDir),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
await rm(temp, { recursive: true, force: true });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function directorySize(directory) {
|
|
62
|
+
let total = 0;
|
|
63
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
const path = join(directory, entry.name);
|
|
66
|
+
if (entry.isDirectory())
|
|
67
|
+
total += await directorySize(path);
|
|
68
|
+
else
|
|
69
|
+
total += (await stat(path)).size;
|
|
70
|
+
}
|
|
71
|
+
return total;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=build-windows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-windows.js","sourceRoot":"","sources":["../src/build-windows.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type AndroidAbi = "universal" | "arm64" | "x64";
|
|
2
|
+
export interface MioConfig {
|
|
3
|
+
app: {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
version: string;
|
|
7
|
+
icon?: string;
|
|
8
|
+
};
|
|
9
|
+
window?: {
|
|
10
|
+
width?: number;
|
|
11
|
+
height?: number;
|
|
12
|
+
title?: string;
|
|
13
|
+
backgroundColor?: string;
|
|
14
|
+
};
|
|
15
|
+
web?: {
|
|
16
|
+
outDir?: string;
|
|
17
|
+
buildCommand?: string;
|
|
18
|
+
devCommand?: string;
|
|
19
|
+
devUrl?: string;
|
|
20
|
+
};
|
|
21
|
+
android?: {
|
|
22
|
+
template?: string;
|
|
23
|
+
/** Which prebuilt template to inject into. Default: universal. */
|
|
24
|
+
abi?: AndroidAbi;
|
|
25
|
+
minSdk?: number;
|
|
26
|
+
pageSize?: 4 | 16;
|
|
27
|
+
keystore?: string;
|
|
28
|
+
alias?: string;
|
|
29
|
+
storePasswordEnv?: string;
|
|
30
|
+
keyPasswordEnv?: string;
|
|
31
|
+
};
|
|
32
|
+
windows?: {
|
|
33
|
+
templateDir?: string;
|
|
34
|
+
exe?: string;
|
|
35
|
+
signCommand?: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export interface LoadedConfig {
|
|
39
|
+
config: MioConfig;
|
|
40
|
+
path: string;
|
|
41
|
+
projectDir: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function loadConfig(projectDir: string, configPath?: string): Promise<LoadedConfig>;
|
|
44
|
+
export declare function resolveFromProject(projectDir: string, value: string | undefined): string | undefined;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
const APP_ID = /^[a-zA-Z][a-zA-Z0-9_]*(\.[a-zA-Z][a-zA-Z0-9_]*)+$/;
|
|
4
|
+
const ANDROID_ABIS = ["universal", "arm64", "x64"];
|
|
5
|
+
export async function loadConfig(projectDir, configPath = "mio.config.json") {
|
|
6
|
+
const path = resolve(projectDir, configPath);
|
|
7
|
+
let parsed;
|
|
8
|
+
try {
|
|
9
|
+
parsed = JSON.parse(await readFile(path, "utf8"));
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
throw new Error(`Cannot read ${path}: ${String(error)}`);
|
|
13
|
+
}
|
|
14
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
15
|
+
throw new Error("mio.config.json must be an object");
|
|
16
|
+
}
|
|
17
|
+
const config = parsed;
|
|
18
|
+
if (!config.app || typeof config.app !== "object") {
|
|
19
|
+
throw new Error("mio.config.json is missing app");
|
|
20
|
+
}
|
|
21
|
+
for (const key of ["id", "name", "version"]) {
|
|
22
|
+
if (typeof config.app[key] !== "string" || config.app[key].length === 0) {
|
|
23
|
+
throw new Error(`mio.config.json app.${key} is required`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (!APP_ID.test(config.app.id)) {
|
|
27
|
+
throw new Error(`Invalid Android application id: ${config.app.id}`);
|
|
28
|
+
}
|
|
29
|
+
const abi = config.android?.abi;
|
|
30
|
+
if (abi !== undefined && !ANDROID_ABIS.includes(abi)) {
|
|
31
|
+
throw new Error(`Invalid android.abi: ${String(abi)} (expected one of ${ANDROID_ABIS.join(", ")})`);
|
|
32
|
+
}
|
|
33
|
+
return { config, path, projectDir };
|
|
34
|
+
}
|
|
35
|
+
export function resolveFromProject(projectDir, value) {
|
|
36
|
+
return value ? resolve(projectDir, value) : undefined;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+CpC,MAAM,MAAM,GAAG,mDAAmD,CAAC;AACnE,MAAM,YAAY,GAA0B,CAAC,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AAE1E,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,UAAkB,EAClB,UAAU,GAAG,iBAAiB;IAE9B,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAC7C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,MAAM,GAAG,MAAmB,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAU,EAAE,CAAC;QACrD,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,cAAc,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC;IAChC,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CACb,wBAAwB,MAAM,CAAC,GAAG,CAAC,qBAAqB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACnF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,UAAkB,EAAE,KAAyB;IAC9E,OAAO,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version of the Mio API contract implemented by the bundled templates.
|
|
3
|
+
*
|
|
4
|
+
* Keep this in sync with `mioApiVersion` in the Flutter shell and with the
|
|
5
|
+
* `apiVersion` reported by `@iyexin/mio-api`. Bump the major version only on breaking
|
|
6
|
+
* bridge changes; the shell refuses to load an app requiring a newer major.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MIO_API_VERSION = "1.0.0";
|
|
9
|
+
/** Version stamped into generated manifests for traceability. */
|
|
10
|
+
export declare const MIO_CLI_VERSION = "0.1.0";
|
|
11
|
+
/** Packages published to npm under the @iyexin scope. */
|
|
12
|
+
export declare const MIO_API_PACKAGE = "@iyexin/mio-api";
|
|
13
|
+
/** Version range written into scaffolds; matches packages/api's version. */
|
|
14
|
+
export declare const MIO_API_PACKAGE_VERSION = "0.1.0";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version of the Mio API contract implemented by the bundled templates.
|
|
3
|
+
*
|
|
4
|
+
* Keep this in sync with `mioApiVersion` in the Flutter shell and with the
|
|
5
|
+
* `apiVersion` reported by `@iyexin/mio-api`. Bump the major version only on breaking
|
|
6
|
+
* bridge changes; the shell refuses to load an app requiring a newer major.
|
|
7
|
+
*/
|
|
8
|
+
export const MIO_API_VERSION = "1.0.0";
|
|
9
|
+
/** Version stamped into generated manifests for traceability. */
|
|
10
|
+
export const MIO_CLI_VERSION = "0.1.0";
|
|
11
|
+
/** Packages published to npm under the @iyexin scope. */
|
|
12
|
+
export const MIO_API_PACKAGE = "@iyexin/mio-api";
|
|
13
|
+
/** Version range written into scaffolds; matches packages/api's version. */
|
|
14
|
+
export const MIO_API_PACKAGE_VERSION = "0.1.0";
|
|
15
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AAEvC,iEAAiE;AACjE,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AAEvC,yDAAyD;AACzD,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAEjD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAC"}
|
package/dist/create.d.ts
ADDED
package/dist/create.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename, join, resolve } from "node:path";
|
|
3
|
+
import { MIO_API_PACKAGE, MIO_API_PACKAGE_VERSION } from "./constants.js";
|
|
4
|
+
import { cliRoot, copyDirectory, exists, repoRoot, safePackageName, writeJson, } from "./project.js";
|
|
5
|
+
import { runShell } from "./web.js";
|
|
6
|
+
export async function createProject(options) {
|
|
7
|
+
const target = resolve(options.target);
|
|
8
|
+
if (await exists(target)) {
|
|
9
|
+
const info = await stat(target);
|
|
10
|
+
if (!info.isDirectory())
|
|
11
|
+
throw new Error(`Target is not a directory: ${target}`);
|
|
12
|
+
if ((await readdir(target)).length > 0) {
|
|
13
|
+
throw new Error(`Target directory is not empty: ${target}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const template = await firstExisting([
|
|
17
|
+
join(cliRoot, "templates", "web"),
|
|
18
|
+
join(repoRoot, "templates", "web"),
|
|
19
|
+
]);
|
|
20
|
+
await copyDirectory(template, target);
|
|
21
|
+
await mkdir(join(target, "src"), { recursive: true });
|
|
22
|
+
// The scaffold depends on the published API package instead of vendoring it:
|
|
23
|
+
// one install step, and upgrades are a normal semver bump.
|
|
24
|
+
const packagePath = join(target, "package.json");
|
|
25
|
+
const pkg = JSON.parse(await readFile(packagePath, "utf8"));
|
|
26
|
+
const projectName = safePackageName(basename(target));
|
|
27
|
+
pkg.name = projectName;
|
|
28
|
+
pkg.private = true;
|
|
29
|
+
pkg.dependencies = {
|
|
30
|
+
...(pkg.dependencies ?? {}),
|
|
31
|
+
[MIO_API_PACKAGE]: `^${MIO_API_PACKAGE_VERSION}`,
|
|
32
|
+
};
|
|
33
|
+
await writeJson(packagePath, pkg);
|
|
34
|
+
const configPath = join(target, "mio.config.json");
|
|
35
|
+
const config = JSON.parse(await readFile(configPath, "utf8"));
|
|
36
|
+
config.app.id = `dev.mio.${projectName.replaceAll("-", "_")}`;
|
|
37
|
+
config.app.name = basename(target);
|
|
38
|
+
if (config.android)
|
|
39
|
+
delete config.android.template;
|
|
40
|
+
await writeJson(configPath, config);
|
|
41
|
+
await writeFile(join(target, ".gitignore"), ["node_modules/", "dist/", "build/", ".mio/debug.p12", "*.log", ""].join("\n"), "utf8");
|
|
42
|
+
console.log(`Created ${target}`);
|
|
43
|
+
if (options.install) {
|
|
44
|
+
console.log("Installing web dependencies...");
|
|
45
|
+
await runShell("npm install", target);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.log(`Next: cd ${basename(target)} && npm install`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function firstExisting(candidates) {
|
|
52
|
+
for (const candidate of candidates) {
|
|
53
|
+
if (await exists(candidate))
|
|
54
|
+
return candidate;
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`Template not found. Looked in:\n${candidates.join("\n")}`);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
|
package/dist/dev.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LoadedConfig } from "./config.js";
|
|
2
|
+
export interface DevOptions {
|
|
3
|
+
loaded: LoadedConfig;
|
|
4
|
+
platform: "android" | "windows";
|
|
5
|
+
install: boolean;
|
|
6
|
+
/** Overrides the resolved template path (--template). */
|
|
7
|
+
template?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function dev(options: DevOptions): Promise<void>;
|