@nyar/nyar 0.0.0 → 0.0.2
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/README.md +32 -0
- package/bin/nyar.js +5 -53
- package/package.json +15 -11
- package/readme.md +32 -20
- package/src/cli/catalog.ts +18 -0
- package/src/cli/cli.ts +136 -0
- package/src/index.ts +39 -38
- package/src/native.ts +115 -0
- package/src/platform-triple.ts +25 -0
- package/src/platform.ts +65 -68
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# @nyar/nyar
|
|
2
|
+
|
|
3
|
+
Cross-platform Nyar host CLI and TypeScript facade. **CLI orchestration** uses [`@vmz/commander`](https://www.npmjs.com/package/@vmz/commander); **orthogonal native capabilities** are exported from `nyar-napi` via `src/native.ts`.
|
|
4
|
+
|
|
5
|
+
## CLI
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
nyar version
|
|
9
|
+
nyar host-info
|
|
10
|
+
nyar runtime list
|
|
11
|
+
nyar runtime prepare --family wasi --artifact ./app.wasm --entry main
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Programmatic native surface
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { getHostInfo, listRuntimeFamilies, prepareRuntimeCommand } from '@nyar/nyar';
|
|
18
|
+
|
|
19
|
+
const info = getHostInfo();
|
|
20
|
+
const families = listRuntimeFamilies();
|
|
21
|
+
const cmd = prepareRuntimeCommand({
|
|
22
|
+
family: 'wasi',
|
|
23
|
+
artifact: '/path/to/app.wasm',
|
|
24
|
+
entry: 'main',
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Platform collects (`nyar-win32-x64`, `nyar-linux-x64`, `nyar-darwin-*`, `nyar-unknown-wasm32`) are resolved automatically when installed on a matching host.
|
|
29
|
+
|
|
30
|
+
## License
|
|
31
|
+
|
|
32
|
+
MIT
|
package/bin/nyar.js
CHANGED
|
@@ -1,53 +1,5 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const require = createRequire(import.meta.url);
|
|
8
|
-
const pkg = require('../package.json');
|
|
9
|
-
|
|
10
|
-
function printUsage() {
|
|
11
|
-
console.error(`@nyar/nyar ${pkg.version} (${hostPlatformKey()})`);
|
|
12
|
-
console.error('Usage: nyar <command> [args...]');
|
|
13
|
-
console.error('Commands:');
|
|
14
|
-
console.error(' host-info Print resolved platform collect metadata');
|
|
15
|
-
console.error(' version Print package version');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function cmdHostInfo() {
|
|
19
|
-
const collect = resolveCollect();
|
|
20
|
-
console.log(JSON.stringify({ version: pkg.version, host: hostPlatformKey(), collect }, null, 2));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function cmdVersion() {
|
|
24
|
-
console.log(pkg.version);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const [command, ...rest] = process.argv.slice(2);
|
|
28
|
-
|
|
29
|
-
if (!command || command === '--help' || command === '-h') {
|
|
30
|
-
printUsage();
|
|
31
|
-
process.exit(command ? 0 : 1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (command === 'version' || command === '--version' || command === '-V') {
|
|
35
|
-
cmdVersion();
|
|
36
|
-
process.exit(0);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (command === 'host-info') {
|
|
40
|
-
cmdHostInfo();
|
|
41
|
-
process.exit(0);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Forward unknown commands to wasmtime when the wasm collect is present (maintainer / CI path).
|
|
45
|
-
const collect = resolveCollect();
|
|
46
|
-
if (collect.kind === 'wasm' && rest.length > 0) {
|
|
47
|
-
const result = spawnSync('wasmtime', [collect.entry, ...rest], { stdio: 'inherit', shell: false });
|
|
48
|
-
process.exit(result.status ?? 1);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
console.error(`nyar: unknown command '${command}'`);
|
|
52
|
-
printUsage();
|
|
53
|
-
process.exit(1);
|
|
1
|
+
#!/usr/bin/env node --experimental-strip-types
|
|
2
|
+
import {runCli} from '../src/cli/cli.ts';
|
|
3
|
+
|
|
4
|
+
const code = await runCli(process.argv.slice(2));
|
|
5
|
+
process.exit(code ?? 0);
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nyar/nyar",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Nyar VM
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Nyar VM host CLI (@vmz/commander) and orthogonal nyar-napi bindings.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "src/index.ts",
|
|
8
8
|
"exports": {
|
|
9
|
-
".": "./src/index.ts"
|
|
9
|
+
".": "./src/index.ts",
|
|
10
|
+
"./cli": "./src/cli/cli.ts"
|
|
10
11
|
},
|
|
11
12
|
"bin": {
|
|
12
13
|
"nyar": "bin/nyar.js"
|
|
@@ -17,14 +18,18 @@
|
|
|
17
18
|
"readme.md",
|
|
18
19
|
"README.md"
|
|
19
20
|
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "node --experimental-strip-types --test tests/**/*.test.ts"
|
|
23
|
+
},
|
|
20
24
|
"dependencies": {
|
|
21
|
-
"@
|
|
25
|
+
"@vmz/commander": "^0.3.2",
|
|
26
|
+
"@nyar/nyar-unknown-wasm32": "0.0.2"
|
|
22
27
|
},
|
|
23
28
|
"optionalDependencies": {
|
|
24
|
-
"@nyar/nyar-win32-x64": "0.0.
|
|
25
|
-
"@nyar/nyar-
|
|
26
|
-
"@nyar/nyar-
|
|
27
|
-
"@nyar/nyar-darwin-arm64": "0.0.
|
|
29
|
+
"@nyar/nyar-win32-x64": "0.0.2",
|
|
30
|
+
"@nyar/nyar-linux-x64": "0.0.2",
|
|
31
|
+
"@nyar/nyar-darwin-x64": "0.0.2",
|
|
32
|
+
"@nyar/nyar-darwin-arm64": "0.0.2"
|
|
28
33
|
},
|
|
29
34
|
"engines": {
|
|
30
35
|
"node": ">=20"
|
|
@@ -42,6 +47,5 @@
|
|
|
42
47
|
},
|
|
43
48
|
"publishConfig": {
|
|
44
49
|
"access": "public"
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
}
|
|
50
|
+
}
|
|
51
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
|
-
# @nyar/nyar
|
|
2
|
-
|
|
3
|
-
Cross-platform
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
# @nyar/nyar
|
|
2
|
+
|
|
3
|
+
Cross-platform Nyar host CLI and TypeScript facade. **CLI orchestration** uses [`@vmz/commander`](https://www.npmjs.com/package/@vmz/commander); **orthogonal native capabilities** are exported from `nyar-napi` via `src/native.ts`.
|
|
4
|
+
|
|
5
|
+
## CLI
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
nyar version
|
|
9
|
+
nyar host-info
|
|
10
|
+
nyar runtime list
|
|
11
|
+
nyar runtime prepare --family wasi --artifact ./app.wasm --entry main
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Programmatic native surface
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { getHostInfo, listRuntimeFamilies, prepareRuntimeCommand } from '@nyar/nyar';
|
|
18
|
+
|
|
19
|
+
const info = getHostInfo();
|
|
20
|
+
const families = listRuntimeFamilies();
|
|
21
|
+
const cmd = prepareRuntimeCommand({
|
|
22
|
+
family: 'wasi',
|
|
23
|
+
artifact: '/path/to/app.wasm',
|
|
24
|
+
entry: 'main',
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Platform collects (`nyar-win32-x64`, `nyar-linux-x64`, `nyar-darwin-*`, `nyar-unknown-wasm32`) are resolved automatically when installed on a matching host.
|
|
29
|
+
|
|
30
|
+
## License
|
|
31
|
+
|
|
32
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type {LocaleCatalog} from '@vmz/commander';
|
|
2
|
+
|
|
3
|
+
/** Nyar CLI 英文 catalog(产品层;`commander.*` 由框架 fallback 提供)。 */
|
|
4
|
+
export const NYAR_CLI_CATALOG: LocaleCatalog = {
|
|
5
|
+
'cli.intro': 'Nyar VM host CLI — runtime dispatch and collect diagnostics',
|
|
6
|
+
'cli.cmd.version': 'Print package version and host protocol',
|
|
7
|
+
'cli.cmd.host-info': 'Print resolved platform collect and native host metadata',
|
|
8
|
+
'cli.cmd.runtime': 'Runtime family helpers',
|
|
9
|
+
'cli.cmd.runtime.list': 'List supported runtime families',
|
|
10
|
+
'cli.cmd.runtime.prepare': 'Expand a runtime template without executing',
|
|
11
|
+
'cli.cmd.runtime.run': 'Prepare and execute a runtime command',
|
|
12
|
+
'cli.opt.family': 'Runtime family id (clr, jvm, node, wasi, nyar-vm, …)',
|
|
13
|
+
'cli.opt.artifact': 'Artifact path (binary, jar, wasm module, …)',
|
|
14
|
+
'cli.opt.classpath': 'Classpath for JVM family',
|
|
15
|
+
'cli.opt.entry': 'Logical entry symbol',
|
|
16
|
+
'cli.opt.wasi-p3': 'Enable wasmtime -S p3 for WASI family',
|
|
17
|
+
'cli.opt.cwd': 'Working directory for runtime run',
|
|
18
|
+
};
|
package/src/cli/cli.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import {readFileSync} from 'node:fs';
|
|
3
|
+
import {createRequire} from 'node:module';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
import type {Cli, Command, ParsedOptions} from '@vmz/commander';
|
|
7
|
+
import {createCli} from '@vmz/commander';
|
|
8
|
+
|
|
9
|
+
import {NYAR_CLI_CATALOG} from './catalog.ts';
|
|
10
|
+
import {getHostInfo, listRuntimeFamilies, prepareRuntimeCommand, runPreparedCommand} from '../native.ts';
|
|
11
|
+
import {hostPlatformKey, resolveCollect} from '../platform.ts';
|
|
12
|
+
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
const pkg = require('../../package.json') as { version: string };
|
|
15
|
+
|
|
16
|
+
function buildCli(): Cli {
|
|
17
|
+
const cli = createCli('nyar').catalog(() => NYAR_CLI_CATALOG).intro('cli.intro');
|
|
18
|
+
|
|
19
|
+
cli.command('version', 'cli.cmd.version').action(() => {
|
|
20
|
+
const info = getHostInfo();
|
|
21
|
+
console.log(`@nyar/nyar ${pkg.version}`);
|
|
22
|
+
console.log(`host ${info.hostProtocol} (${info.binding})`);
|
|
23
|
+
return 0;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
cli.command('host-info', 'cli.cmd.host-info').action(() => {
|
|
27
|
+
const collect = resolveCollect();
|
|
28
|
+
const info = getHostInfo();
|
|
29
|
+
console.log(
|
|
30
|
+
JSON.stringify(
|
|
31
|
+
{
|
|
32
|
+
version: pkg.version,
|
|
33
|
+
host: hostPlatformKey(),
|
|
34
|
+
hostProtocol: info.hostProtocol,
|
|
35
|
+
binding: info.binding,
|
|
36
|
+
collect,
|
|
37
|
+
},
|
|
38
|
+
null,
|
|
39
|
+
2,
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
return 0;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const runtime = cli.command('runtime', 'cli.cmd.runtime');
|
|
46
|
+
|
|
47
|
+
runtime.command('list', 'cli.cmd.runtime.list').action(() => {
|
|
48
|
+
for (const family of listRuntimeFamilies()) {
|
|
49
|
+
console.log(family);
|
|
50
|
+
}
|
|
51
|
+
return 0;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const runtimeOpts = (cmd: Command) =>
|
|
55
|
+
cmd
|
|
56
|
+
.option('--family <id>', 'cli.opt.family')
|
|
57
|
+
.option('--artifact <path>', 'cli.opt.artifact')
|
|
58
|
+
.option('--classpath <path>', 'cli.opt.classpath')
|
|
59
|
+
.option('--entry <name>', 'cli.opt.entry')
|
|
60
|
+
.option('--wasi-p3', 'cli.opt.wasi-p3');
|
|
61
|
+
|
|
62
|
+
runtimeOpts(runtime.command('prepare', 'cli.cmd.runtime.prepare')).action((options: ParsedOptions) => {
|
|
63
|
+
const family = requireString(options, 'family');
|
|
64
|
+
const artifact = requireString(options, 'artifact');
|
|
65
|
+
const entry = requireString(options, 'entry');
|
|
66
|
+
const prepared = prepareRuntimeCommand({
|
|
67
|
+
family,
|
|
68
|
+
artifact: path.resolve(artifact),
|
|
69
|
+
classpath: typeof options.classpath === 'string' ? options.classpath : undefined,
|
|
70
|
+
entry,
|
|
71
|
+
wasiP3: Boolean(options['wasi-p3']),
|
|
72
|
+
});
|
|
73
|
+
console.log(JSON.stringify(prepared, null, 2));
|
|
74
|
+
return 0;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
runtimeOpts(runtime.command('run', 'cli.cmd.runtime.run'))
|
|
78
|
+
.option('--cwd <dir>', 'cli.opt.cwd')
|
|
79
|
+
.action((options: ParsedOptions) => {
|
|
80
|
+
const family = requireString(options, 'family');
|
|
81
|
+
const artifact = requireString(options, 'artifact');
|
|
82
|
+
const entry = requireString(options, 'entry');
|
|
83
|
+
const prepared = prepareRuntimeCommand({
|
|
84
|
+
family,
|
|
85
|
+
artifact: path.resolve(artifact),
|
|
86
|
+
classpath: typeof options.classpath === 'string' ? options.classpath : undefined,
|
|
87
|
+
entry,
|
|
88
|
+
wasiP3: Boolean(options['wasi-p3']),
|
|
89
|
+
});
|
|
90
|
+
const cwd = typeof options.cwd === 'string' ? path.resolve(options.cwd) : process.cwd();
|
|
91
|
+
const code = runPreparedCommand(prepared, cwd);
|
|
92
|
+
return code;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return cli;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function requireString(options: ParsedOptions, key: string): string {
|
|
99
|
+
const value = options[key];
|
|
100
|
+
if (typeof value !== 'string' || !value) {
|
|
101
|
+
throw new Error(`missing required --${key}`);
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** 解析 argv 并执行 Nyar CLI(@vmz/commander 编排;能力调用走 nyar-napi)。 */
|
|
107
|
+
export async function runCli(argv: string[] = process.argv.slice(2)): Promise<number> {
|
|
108
|
+
const [cmd] = argv;
|
|
109
|
+
if (cmd === 'wasm' && resolveCollect().kind === 'wasm') {
|
|
110
|
+
return forwardWasm(argv.slice(1));
|
|
111
|
+
}
|
|
112
|
+
return buildCli().parse(argv);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function forwardWasm(rest: string[]): number {
|
|
116
|
+
const collect = resolveCollect();
|
|
117
|
+
if (collect.kind !== 'wasm') {
|
|
118
|
+
console.error('nyar: wasm forward requires wasm collect');
|
|
119
|
+
return 1;
|
|
120
|
+
}
|
|
121
|
+
if (!existsArtifact(collect.entry)) {
|
|
122
|
+
console.error(`nyar: missing wasm collect at ${collect.entry}`);
|
|
123
|
+
return 1;
|
|
124
|
+
}
|
|
125
|
+
const result = spawnSync('wasmtime', [collect.entry, ...rest], {stdio: 'inherit', shell: false});
|
|
126
|
+
return result.status ?? 1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function existsArtifact(filePath: string): boolean {
|
|
130
|
+
try {
|
|
131
|
+
readFileSync(filePath);
|
|
132
|
+
return true;
|
|
133
|
+
} catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
import { type NyarCollect, resolveCollect } from './platform.ts';
|
|
2
|
+
|
|
3
|
+
export { hostPlatformKey, type NyarCollect, resolveCollect } from './platform.ts';
|
|
4
|
+
export { nativeBinaryName, platformShort, platformTriple } from './platform-triple.ts';
|
|
5
|
+
export {
|
|
6
|
+
HOST_PROTOCOL,
|
|
7
|
+
getHostInfo,
|
|
8
|
+
listRuntimeFamilies,
|
|
9
|
+
loadNative,
|
|
10
|
+
prepareRuntimeCommand,
|
|
11
|
+
runPreparedCommand,
|
|
12
|
+
type HostInfo,
|
|
13
|
+
type PrepareRuntimeOptions,
|
|
14
|
+
type PreparedRuntimeCommand,
|
|
15
|
+
} from './native.ts';
|
|
16
|
+
export { runCli } from './cli/cli.ts';
|
|
17
|
+
|
|
18
|
+
export type NyarHost = {
|
|
19
|
+
/** Resolved platform collect metadata for diagnostics and tooling. */
|
|
20
|
+
collect: NyarCollect;
|
|
21
|
+
/** Host protocol from nyar-napi. */
|
|
22
|
+
hostProtocol: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create a Nyar host handle for the current platform.
|
|
27
|
+
*
|
|
28
|
+
* Native collects are preferred when the matching optional dependency is installed;
|
|
29
|
+
* otherwise the Wasm collect from `@nyar/nyar-unknown-wasm32` is used.
|
|
30
|
+
*/
|
|
31
|
+
export async function createNyarHost(): Promise<NyarHost> {
|
|
32
|
+
const collect = resolveCollect();
|
|
33
|
+
if (collect.kind === 'native') {
|
|
34
|
+
const { getHostInfo } = await import('./native.ts');
|
|
35
|
+
const info = getHostInfo();
|
|
36
|
+
return { collect, hostProtocol: info.hostProtocol };
|
|
37
|
+
}
|
|
38
|
+
return { collect, hostProtocol: 'nyar-host/0' };
|
|
39
|
+
}
|
package/src/native.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {createRequire} from 'node:module';
|
|
2
|
+
import {existsSync} from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
|
|
6
|
+
import {hostPlatformKey} from './platform.ts';
|
|
7
|
+
import {nativeBinaryName, platformShort, platformTriple} from './platform-triple.ts';
|
|
8
|
+
|
|
9
|
+
/** Node 宿主协议 id(与 nyar-napi `HOST_PROTOCOL` 对齐)。 */
|
|
10
|
+
export const HOST_PROTOCOL = 'nyar-host/0';
|
|
11
|
+
|
|
12
|
+
export type HostInfo = {
|
|
13
|
+
hostProtocol: string;
|
|
14
|
+
binding: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type PrepareRuntimeOptions = {
|
|
18
|
+
family: string;
|
|
19
|
+
artifact: string;
|
|
20
|
+
classpath?: string;
|
|
21
|
+
entry: string;
|
|
22
|
+
wasiP3?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type PreparedRuntimeCommand = {
|
|
26
|
+
family: string;
|
|
27
|
+
command: string;
|
|
28
|
+
args: string[];
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type NyarNativeAddon = {
|
|
32
|
+
getHostInfo(): HostInfo;
|
|
33
|
+
listRuntimeFamilies(): string[];
|
|
34
|
+
parseRuntimeFamily(value: string): string;
|
|
35
|
+
prepareRuntimeCommand(options: {
|
|
36
|
+
family: string;
|
|
37
|
+
artifact: string;
|
|
38
|
+
classpath?: string;
|
|
39
|
+
entry: string;
|
|
40
|
+
wasiP3?: boolean;
|
|
41
|
+
}): PreparedRuntimeCommand;
|
|
42
|
+
runPreparedCommand(prepared: PreparedRuntimeCommand, cwd?: string): number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const pkgRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
46
|
+
const require = createRequire(import.meta.url);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Resolve native `.node` via the platform optionalDependency (`@nyar/nyar-<short>`).
|
|
50
|
+
*/
|
|
51
|
+
export function resolveNativePath(): string {
|
|
52
|
+
const triple = platformTriple();
|
|
53
|
+
const short = platformShort(triple);
|
|
54
|
+
const packageName = `@nyar/nyar-${short}`;
|
|
55
|
+
const binary = nativeBinaryName(triple);
|
|
56
|
+
const candidates: string[] = [];
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const pkgJson = require.resolve(`${packageName}/package.json`);
|
|
60
|
+
const pkgDir = path.dirname(pkgJson);
|
|
61
|
+
candidates.push(path.join(pkgDir, 'lib', binary));
|
|
62
|
+
candidates.push(path.join(pkgDir, binary));
|
|
63
|
+
} catch {
|
|
64
|
+
/* optional dep not installed */
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
candidates.push(path.join(pkgRoot, '..', '..', `nyar-${short}`, 'lib', binary));
|
|
68
|
+
candidates.push(path.join(pkgRoot, '..', '..', `nyar-${short}`, binary));
|
|
69
|
+
candidates.push(path.join(pkgRoot, 'node_modules', packageName, 'lib', binary));
|
|
70
|
+
|
|
71
|
+
for (const candidate of candidates) {
|
|
72
|
+
if (existsSync(candidate)) return candidate;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
throw new Error(
|
|
76
|
+
`nyar native addon not found for ${packageName}. Run: node scripts/build.mjs napi\n` +
|
|
77
|
+
`Looked in:\n${candidates.map((c) => ` - ${c}`).join('\n')}\n` +
|
|
78
|
+
`(host ${hostPlatformKey()})`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let nativeAddon: NyarNativeAddon | undefined;
|
|
83
|
+
|
|
84
|
+
/** 加载当前平台的 nyar-napi 绑定(正交能力面,不含 CLI)。 */
|
|
85
|
+
export function loadNative(): NyarNativeAddon {
|
|
86
|
+
if (nativeAddon) return nativeAddon;
|
|
87
|
+
const triple = platformTriple();
|
|
88
|
+
const short = platformShort(triple);
|
|
89
|
+
const packageName = `@nyar/nyar-${short}`;
|
|
90
|
+
nativeAddon = require(resolveNativePath()) as NyarNativeAddon;
|
|
91
|
+
return nativeAddon;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function getHostInfo(): HostInfo {
|
|
95
|
+
return loadNative().getHostInfo();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function listRuntimeFamilies(): string[] {
|
|
99
|
+
return loadNative().listRuntimeFamilies();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function prepareRuntimeCommand(options: PrepareRuntimeOptions): PreparedRuntimeCommand {
|
|
103
|
+
const native = loadNative();
|
|
104
|
+
return native.prepareRuntimeCommand({
|
|
105
|
+
family: options.family,
|
|
106
|
+
artifact: options.artifact,
|
|
107
|
+
classpath: options.classpath,
|
|
108
|
+
entry: options.entry,
|
|
109
|
+
wasiP3: options.wasiP3,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function runPreparedCommand(prepared: PreparedRuntimeCommand, cwd?: string): number {
|
|
114
|
+
return loadNative().runPreparedCommand(prepared, cwd);
|
|
115
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {arch, platform} from 'node:os';
|
|
2
|
+
|
|
3
|
+
/** npm platform short id (`win32-x64`, …) from host OS. */
|
|
4
|
+
export function platformShort(triple?: string): string {
|
|
5
|
+
const t = triple ?? platformTriple();
|
|
6
|
+
if (t.startsWith('win32-')) return 'win32-x64';
|
|
7
|
+
if (t.startsWith('linux-')) return 'linux-x64';
|
|
8
|
+
if (t === 'darwin-arm64') return 'darwin-arm64';
|
|
9
|
+
if (t === 'darwin-x64') return 'darwin-x64';
|
|
10
|
+
return t;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Host triple used for platform-named native binaries (`nyar.<triple>.node`). */
|
|
14
|
+
export function platformTriple(): string {
|
|
15
|
+
const {platform: os, arch: cpu} = {platform: platform(), arch: arch()};
|
|
16
|
+
if (os === 'win32' && cpu === 'x64') return 'win32-x64-msvc';
|
|
17
|
+
if (os === 'linux' && cpu === 'x64') return 'linux-x64-gnu';
|
|
18
|
+
if (os === 'darwin' && cpu === 'arm64') return 'darwin-arm64';
|
|
19
|
+
if (os === 'darwin' && cpu === 'x64') return 'darwin-x64';
|
|
20
|
+
return `${os}-${cpu}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function nativeBinaryName(triple?: string): string {
|
|
24
|
+
return `nyar.${triple ?? platformTriple()}.node`;
|
|
25
|
+
}
|
package/src/platform.ts
CHANGED
|
@@ -1,68 +1,65 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
const HOST_KEY = `${platform()}-${arch()}`;
|
|
6
|
-
|
|
7
|
-
const OPTIONAL_NATIVE_PACKAGES: Record<string, string> = {
|
|
8
|
-
'win32-x64': '@nyar/nyar-win32-x64',
|
|
9
|
-
'linux-x64': '@nyar/nyar-linux-x64',
|
|
10
|
-
'darwin-x64': '@nyar/nyar-darwin-x64',
|
|
11
|
-
'darwin-arm64': '@nyar/nyar-darwin-arm64',
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const WASM_PACKAGE = '@nyar/nyar-unknown-wasm32';
|
|
15
|
-
|
|
16
|
-
export type NyarCollectKind = 'native' | 'wasm';
|
|
17
|
-
|
|
18
|
-
export type NyarCollect = {
|
|
19
|
-
kind: NyarCollectKind;
|
|
20
|
-
packageName: string;
|
|
21
|
-
entry: string;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export function hostPlatformKey(): string {
|
|
25
|
-
return HOST_KEY;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function resolveNativeCollectPackage(): string | undefined {
|
|
29
|
-
return OPTIONAL_NATIVE_PACKAGES[HOST_KEY];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function resolveWasmCollectPackage(): string {
|
|
33
|
-
return WASM_PACKAGE;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function requireOptional(packageName: string): { resolve(request: string): string } | undefined {
|
|
37
|
-
const require = createRequire(fileURLToPath(import.meta.url));
|
|
38
|
-
try {
|
|
39
|
-
require.resolve(packageName);
|
|
40
|
-
return createRequire(require.resolve(`${packageName}/package.json`));
|
|
41
|
-
} catch {
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function resolveCollect(): NyarCollect {
|
|
47
|
-
const nativePackage = resolveNativeCollectPackage();
|
|
48
|
-
if (nativePackage) {
|
|
49
|
-
const req = requireOptional(nativePackage);
|
|
50
|
-
if (req) {
|
|
51
|
-
const entry =
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
entry: wasmReq.resolve(`${WASM_PACKAGE}/nyar.wasm`),
|
|
67
|
-
};
|
|
68
|
-
}
|
|
1
|
+
import {createRequire} from 'node:module';
|
|
2
|
+
import {arch, platform} from 'node:os';
|
|
3
|
+
import {fileURLToPath} from 'node:url';
|
|
4
|
+
|
|
5
|
+
const HOST_KEY = `${platform()}-${arch()}`;
|
|
6
|
+
|
|
7
|
+
const OPTIONAL_NATIVE_PACKAGES: Record<string, string> = {
|
|
8
|
+
'win32-x64': '@nyar/nyar-win32-x64',
|
|
9
|
+
'linux-x64': '@nyar/nyar-linux-x64',
|
|
10
|
+
'darwin-x64': '@nyar/nyar-darwin-x64',
|
|
11
|
+
'darwin-arm64': '@nyar/nyar-darwin-arm64',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const WASM_PACKAGE = '@nyar/nyar-unknown-wasm32';
|
|
15
|
+
|
|
16
|
+
export type NyarCollectKind = 'native' | 'wasm';
|
|
17
|
+
|
|
18
|
+
export type NyarCollect = {
|
|
19
|
+
kind: NyarCollectKind;
|
|
20
|
+
packageName: string;
|
|
21
|
+
entry: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function hostPlatformKey(): string {
|
|
25
|
+
return HOST_KEY;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function resolveNativeCollectPackage(): string | undefined {
|
|
29
|
+
return OPTIONAL_NATIVE_PACKAGES[HOST_KEY];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function resolveWasmCollectPackage(): string {
|
|
33
|
+
return WASM_PACKAGE;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function requireOptional(packageName: string): { resolve(request: string): string } | undefined {
|
|
37
|
+
const require = createRequire(fileURLToPath(import.meta.url));
|
|
38
|
+
try {
|
|
39
|
+
require.resolve(packageName);
|
|
40
|
+
return createRequire(require.resolve(`${packageName}/package.json`));
|
|
41
|
+
} catch {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function resolveCollect(): NyarCollect {
|
|
47
|
+
const nativePackage = resolveNativeCollectPackage();
|
|
48
|
+
if (nativePackage) {
|
|
49
|
+
const req = requireOptional(nativePackage);
|
|
50
|
+
if (req) {
|
|
51
|
+
const entry = req.resolve('./index.mjs');
|
|
52
|
+
return {kind: 'native', packageName: nativePackage, entry};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const wasmReq = requireOptional(WASM_PACKAGE);
|
|
57
|
+
if (!wasmReq) {
|
|
58
|
+
throw new Error(`missing required dependency ${WASM_PACKAGE}; install workspace collects before publishing`);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
kind: 'wasm',
|
|
62
|
+
packageName: WASM_PACKAGE,
|
|
63
|
+
entry: wasmReq.resolve(`${WASM_PACKAGE}/nyar.wasm`),
|
|
64
|
+
};
|
|
65
|
+
}
|