@uruhalushia/rule-converter-napi 0.0.0 → 0.1.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.
Files changed (4) hide show
  1. package/README.md +118 -1
  2. package/index.d.ts +79 -0
  3. package/index.js +110 -1
  4. package/package.json +58 -7
package/README.md CHANGED
@@ -1,3 +1,120 @@
1
1
  # @uruhalushia/rule-converter-napi
2
2
 
3
- Placeholder package for repository setup.
3
+ Node.js bindings for the Rust rule converter. Inputs are auto-detected from payload/file content by default, and can be overridden with input options when needed.
4
+
5
+ ## Build
6
+
7
+ ```bash
8
+ pnpm --dir napi install
9
+ pnpm --dir napi build
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ ```js
15
+ import { writeFileSync } from 'node:fs'
16
+ import {
17
+ convertPayloadStringToMrs,
18
+ convertPayloadStringToString,
19
+ convertFileToBuffer,
20
+ convertFileToPath,
21
+ } from '@uruhalushia/rule-converter-napi'
22
+
23
+ const payload = `
24
+ payload:
25
+ - DOMAIN,example.com
26
+ - DOMAIN-SUFFIX,example.net
27
+ - IP-CIDR,192.168.1.0/24,no-resolve
28
+ `
29
+
30
+ const result = convertPayloadStringToMrs(payload, {
31
+ inputTarget: 'mihomo',
32
+ inputFormat: 'yaml',
33
+ inputBehavior: 'classical',
34
+ outputTarget: 'mihomo',
35
+ outputFormat: 'mrs',
36
+ outputBehavior: 'domain',
37
+ })
38
+
39
+ for (const output of result.outputs) {
40
+ writeFileSync(`${output.behavior}.mrs`, output.bytes)
41
+ }
42
+
43
+ const text = convertPayloadStringToString(payload, {
44
+ inputTarget: 'mihomo',
45
+ inputFormat: 'yaml',
46
+ inputBehavior: 'classical',
47
+ outputTarget: 'general',
48
+ outputFormat: 'ruleset',
49
+ outputBehavior: 'classical',
50
+ })
51
+
52
+ console.log(text.outputs[0].text)
53
+
54
+ const srs = convertFileToBuffer('rules.yaml', {
55
+ outputTarget: 'sing-box',
56
+ outputFormat: 'srs',
57
+ outputBehavior: 'classical',
58
+ })
59
+
60
+ writeFileSync('rules.srs', srs.outputs[0].buffer)
61
+
62
+ const written = convertFileToPath('rules.yaml', 'dist/rules.list', {
63
+ outputTarget: 'general',
64
+ outputFormat: 'ruleset',
65
+ outputBehavior: 'classical',
66
+ })
67
+
68
+ console.log(written.outputs)
69
+ ```
70
+
71
+ Multiple files can be merged by passing a path array, a directory path, or a final-component `*` wildcard:
72
+
73
+ ```js
74
+ convertFileToPath(['/path/rules-a.yaml', '/path/rules-b.yaml'], 'dist/ad.mrs', {
75
+ outputTarget: 'mihomo',
76
+ outputFormat: 'mrs',
77
+ outputBehavior: 'domain',
78
+ })
79
+ ```
80
+
81
+ ## API
82
+
83
+ - `convertPayloadToMrs(payload, options?)`: accepts `Uint8Array` and returns generated MRS files in memory.
84
+ - `convertPayloadStringToMrs(payload, options?)`: accepts a string and returns generated MRS files in memory.
85
+ - `convertFileToMrs(input, options?)`: reads one file, directory, wildcard, or path array and returns generated MRS files in memory.
86
+ - `convertPayloadToBuffer(payload, options?)`: accepts `Uint8Array` and returns generated files as Node.js `Buffer` objects in memory.
87
+ - `convertPayloadStringToBuffer(payload, options?)`: accepts a string and returns generated files as Node.js `Buffer` objects in memory.
88
+ - `convertFileToBuffer(input, options?)`: reads one file, directory, wildcard, or path array and returns generated files as Node.js `Buffer` objects in memory.
89
+ - `convertPayloadToString(payload, options?)`: accepts `Uint8Array` and returns generated text output as strings.
90
+ - `convertPayloadStringToString(payload, options?)`: accepts a string and returns generated text output as strings.
91
+ - `convertFileToString(input, options?)`: reads one file, directory, wildcard, or path array and returns generated text output as strings.
92
+ - `convertFileToPath(input, output, options?)`: writes converted outputs to disk.
93
+
94
+ ```ts
95
+ interface ConvertOptions {
96
+ inputTarget?: 'mihomo' | 'general' | 'egern' | 'sing-box'
97
+ inputFormat?: 'yaml' | 'mrs' | 'text' | 'json' | 'srs'
98
+ inputBehavior?: 'auto' | 'domain' | 'ip' | 'classical'
99
+ outputTarget?: 'mihomo' | 'general' | 'egern' | 'sing-box'
100
+ outputFormat?: 'mrs' | 'text' | 'yaml' | 'json' | 'srs' | 'domainset' | 'ruleset' | 'ipset'
101
+ outputBehavior?: 'domain' | 'ip' | 'classical'
102
+ }
103
+ ```
104
+
105
+ Defaults:
106
+
107
+ - `inputTarget`: auto-detected
108
+ - `inputFormat`: auto-detected
109
+ - `inputBehavior`: `auto`
110
+ - `outputTarget`: `mihomo`
111
+ - `outputFormat`: `mrs`
112
+ - `outputBehavior`: `domain`
113
+
114
+ mihomo MRS output supports only `domain` and `ip`. sing-box JSON/SRS is available with `outputTarget: 'sing-box'` and `outputFormat: 'json' | 'srs'`.
115
+
116
+ String output supports text formats only: `text`, `yaml`, `json`, `domainset`, `ruleset`, and `ipset`. Use the buffer functions for binary `mrs` and `srs` output.
117
+
118
+ `mihomo + text/yaml + domain` uses mihomo/Clash domain wildcard syntax such as `+.example.com`; `general + domainset + domain` uses domain-set syntax where `.example.com` means the domain itself and all subdomains.
119
+
120
+ `no-resolve` is preserved only between mixed text, mihomo YAML, and Egern ruleset YAML. MRS, sing-box JSON/SRS, and domain-set output do not have a field for it.
package/index.d.ts ADDED
@@ -0,0 +1,79 @@
1
+ /* auto-generated by NAPI-RS */
2
+ /* eslint-disable */
3
+ export interface ConvertBufferOutput {
4
+ behavior: 'domain' | 'ip'
5
+ count: number
6
+ buffer: Uint8Array
7
+ }
8
+
9
+ export interface ConvertBufferResult {
10
+ outputs: Array<ConvertBufferOutput>
11
+ skipped: Array<SkippedRule>
12
+ }
13
+
14
+ export declare function convertFileToBuffer(input: string | string[], options?: ConvertOptions | undefined | null): ConvertBufferResult
15
+
16
+ export declare function convertFileToMrs(input: string | string[], options?: ConvertOptions | undefined | null): ConvertResult
17
+
18
+ export declare function convertFileToPath(input: string | string[], output: string, options?: ConvertOptions | undefined | null): WriteResult
19
+
20
+ export declare function convertFileToString(input: string | string[], options?: ConvertOptions | undefined | null): ConvertStringResult
21
+
22
+ export interface ConvertOptions {
23
+ inputTarget?: 'mihomo' | 'general' | 'egern' | 'sing-box'
24
+ inputFormat?: 'yaml' | 'mrs' | 'text' | 'json' | 'srs'
25
+ inputBehavior?: 'auto' | 'domain' | 'ip' | 'classical'
26
+ outputTarget?: 'mihomo' | 'general' | 'egern' | 'sing-box'
27
+ outputFormat?: 'mrs' | 'text' | 'yaml' | 'json' | 'srs' | 'domainset' | 'ruleset' | 'ipset'
28
+ outputBehavior?: 'auto' | 'domain' | 'ip' | 'classical'
29
+ }
30
+
31
+ export interface ConvertOutput {
32
+ behavior: 'domain' | 'ip'
33
+ count: number
34
+ bytes: Uint8Array
35
+ }
36
+
37
+ export declare function convertPayloadStringToBuffer(payload: string, options?: ConvertOptions | undefined | null): ConvertBufferResult
38
+
39
+ export declare function convertPayloadStringToMrs(payload: string, options?: ConvertOptions | undefined | null): ConvertResult
40
+
41
+ export declare function convertPayloadStringToString(payload: string, options?: ConvertOptions | undefined | null): ConvertStringResult
42
+
43
+ export declare function convertPayloadToBuffer(payload: Uint8Array, options?: ConvertOptions | undefined | null): ConvertBufferResult
44
+
45
+ export declare function convertPayloadToMrs(payload: Uint8Array, options?: ConvertOptions | undefined | null): ConvertResult
46
+
47
+ export declare function convertPayloadToString(payload: Uint8Array, options?: ConvertOptions | undefined | null): ConvertStringResult
48
+
49
+ export interface ConvertResult {
50
+ outputs: Array<ConvertOutput>
51
+ skipped: Array<SkippedRule>
52
+ }
53
+
54
+ export interface ConvertStringOutput {
55
+ behavior: 'domain' | 'ip'
56
+ count: number
57
+ text: string
58
+ }
59
+
60
+ export interface ConvertStringResult {
61
+ outputs: Array<ConvertStringOutput>
62
+ skipped: Array<SkippedRule>
63
+ }
64
+
65
+ export interface SkippedRule {
66
+ rule: string
67
+ reason: string
68
+ }
69
+
70
+ export interface WriteResult {
71
+ outputs: Array<WrittenOutput>
72
+ skipped: Array<SkippedRule>
73
+ }
74
+
75
+ export interface WrittenOutput {
76
+ behavior: 'domain' | 'ip'
77
+ count: number
78
+ path: string
79
+ }
package/index.js CHANGED
@@ -1 +1,110 @@
1
- export default {}
1
+ // prettier-ignore
2
+ /* eslint-disable */
3
+ // @ts-nocheck
4
+
5
+ import { existsSync } from 'node:fs'
6
+ import { join } from 'node:path'
7
+ import { createRequire } from 'node:module'
8
+ import packageJson from './package.json' with { type: 'json' }
9
+
10
+ const require = createRequire(import.meta.url)
11
+ const __dirname = new URL('.', import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, '$1')
12
+
13
+ const packageName = '@uruhalushia/rule-converter-napi'
14
+ const packageVersion = packageJson.version
15
+ const binaryName = 'rule-converter'
16
+ const loadErrors = []
17
+
18
+ function isMusl() {
19
+ try {
20
+ return require('node:child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl')
21
+ } catch (_) {
22
+ return false
23
+ }
24
+ }
25
+
26
+ function requireLocal(tuple) {
27
+ const filename = join(__dirname, `${binaryName}.${tuple}.node`)
28
+ if (!existsSync(filename)) {
29
+ loadErrors.push(new Error(`Native binding not found: ${filename}`))
30
+ return null
31
+ }
32
+ try {
33
+ return require(filename)
34
+ } catch (err) {
35
+ loadErrors.push(err)
36
+ return null
37
+ }
38
+ }
39
+
40
+ function requirePackage(tuple) {
41
+ const nativePackage = `${packageName}-${tuple}`
42
+ try {
43
+ const binding = require(nativePackage)
44
+ const bindingPackageVersion = require(`${nativePackage}/package.json`).version
45
+ if (
46
+ bindingPackageVersion !== packageVersion &&
47
+ process.env.NAPI_RS_ENFORCE_VERSION_CHECK &&
48
+ process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0'
49
+ ) {
50
+ throw new Error(
51
+ `Native binding package version mismatch, expected ${packageVersion} but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`,
52
+ )
53
+ }
54
+ return binding
55
+ } catch (err) {
56
+ loadErrors.push(err)
57
+ return null
58
+ }
59
+ }
60
+
61
+ function requireBinding(tuple) {
62
+ return requireLocal(tuple) || requirePackage(tuple)
63
+ }
64
+
65
+ function requireNative() {
66
+ if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {
67
+ try {
68
+ return require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH)
69
+ } catch (err) {
70
+ loadErrors.push(err)
71
+ }
72
+ }
73
+
74
+ if (process.platform === 'win32') {
75
+ if (process.arch === 'x64') return requireBinding('win32-x64-msvc')
76
+ if (process.arch === 'arm64') return requireBinding('win32-arm64-msvc')
77
+ } else if (process.platform === 'darwin') {
78
+ if (process.arch === 'x64') return requireBinding('darwin-x64')
79
+ if (process.arch === 'arm64') return requireBinding('darwin-arm64')
80
+ } else if (process.platform === 'linux') {
81
+ const musl = isMusl()
82
+ if (process.arch === 'x64') return requireBinding(musl ? 'linux-x64-musl' : 'linux-x64-gnu')
83
+ if (process.arch === 'arm64') return requireBinding(musl ? 'linux-arm64-musl' : 'linux-arm64-gnu')
84
+ if (process.arch === 'riscv64') return requireBinding(musl ? 'linux-riscv64-musl' : 'linux-riscv64-gnu')
85
+ if (process.arch === 'loong64') return requireBinding(musl ? 'linux-loong64-musl' : 'linux-loong64-gnu')
86
+ }
87
+
88
+ loadErrors.push(new Error(`Unsupported OS or architecture: ${process.platform} ${process.arch}`))
89
+ return null
90
+ }
91
+
92
+ const nativeBinding = requireNative()
93
+
94
+ if (!nativeBinding) {
95
+ const error = new Error('Failed to load rule-converter native binding')
96
+ error.cause = loadErrors
97
+ throw error
98
+ }
99
+
100
+ export default nativeBinding
101
+ export const convertPayloadToMrs = nativeBinding.convertPayloadToMrs
102
+ export const convertPayloadStringToMrs = nativeBinding.convertPayloadStringToMrs
103
+ export const convertPayloadToBuffer = nativeBinding.convertPayloadToBuffer
104
+ export const convertPayloadStringToBuffer = nativeBinding.convertPayloadStringToBuffer
105
+ export const convertPayloadToString = nativeBinding.convertPayloadToString
106
+ export const convertPayloadStringToString = nativeBinding.convertPayloadStringToString
107
+ export const convertFileToMrs = nativeBinding.convertFileToMrs
108
+ export const convertFileToBuffer = nativeBinding.convertFileToBuffer
109
+ export const convertFileToString = nativeBinding.convertFileToString
110
+ export const convertFileToPath = nativeBinding.convertFileToPath
package/package.json CHANGED
@@ -1,16 +1,67 @@
1
1
  {
2
2
  "name": "@uruhalushia/rule-converter-napi",
3
- "version": "0.0.0",
4
- "description": "Placeholder package for repository setup.",
3
+ "version": "0.1.2",
4
+ "description": "Node.js bindings for converting mihomo, sing-box, Egern, and generic rule sets.",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
+ "types": "index.d.ts",
8
+ "packageManager": "pnpm@10.33.0",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/UruhaLushia/rule-converter.git"
12
+ },
13
+ "homepage": "https://github.com/UruhaLushia/rule-converter",
14
+ "bugs": {
15
+ "url": "https://github.com/UruhaLushia/rule-converter/issues"
16
+ },
17
+ "license": "GPL-3.0-only",
7
18
  "files": [
8
19
  "index.js",
20
+ "index.d.ts",
9
21
  "README.md"
10
22
  ],
11
- "license": "UNLICENSED",
12
- "publishConfig": {
13
- "access": "public",
14
- "registry": "https://registry.npmjs.org/"
23
+ "napi": {
24
+ "binaryName": "rule-converter",
25
+ "targets": [
26
+ "x86_64-unknown-linux-gnu",
27
+ "aarch64-unknown-linux-gnu",
28
+ "riscv64gc-unknown-linux-gnu",
29
+ "loongarch64-unknown-linux-gnu",
30
+ "x86_64-unknown-linux-musl",
31
+ "aarch64-unknown-linux-musl",
32
+ "riscv64gc-unknown-linux-musl",
33
+ "loongarch64-unknown-linux-musl",
34
+ "x86_64-apple-darwin",
35
+ "aarch64-apple-darwin",
36
+ "x86_64-pc-windows-msvc",
37
+ "aarch64-pc-windows-msvc"
38
+ ]
39
+ },
40
+ "scripts": {
41
+ "build": "napi build --platform --release --no-js",
42
+ "build:debug": "napi build --platform --no-js",
43
+ "create-npm-dirs": "napi create-npm-dirs",
44
+ "artifacts": "napi artifacts",
45
+ "test": "node -e \"import('./index.js').then((m) => console.log(Object.keys(m).sort().join(',')))\""
46
+ },
47
+ "engines": {
48
+ "node": ">=16"
49
+ },
50
+ "devDependencies": {
51
+ "@napi-rs/cli": "^3"
52
+ },
53
+ "optionalDependencies": {
54
+ "@uruhalushia/rule-converter-napi-linux-x64-gnu": "0.1.2",
55
+ "@uruhalushia/rule-converter-napi-linux-arm64-gnu": "0.1.2",
56
+ "@uruhalushia/rule-converter-napi-linux-riscv64-gnu": "0.1.2",
57
+ "@uruhalushia/rule-converter-napi-linux-loong64-gnu": "0.1.2",
58
+ "@uruhalushia/rule-converter-napi-linux-x64-musl": "0.1.2",
59
+ "@uruhalushia/rule-converter-napi-linux-arm64-musl": "0.1.2",
60
+ "@uruhalushia/rule-converter-napi-linux-riscv64-musl": "0.1.2",
61
+ "@uruhalushia/rule-converter-napi-linux-loong64-musl": "0.1.2",
62
+ "@uruhalushia/rule-converter-napi-darwin-x64": "0.1.2",
63
+ "@uruhalushia/rule-converter-napi-darwin-arm64": "0.1.2",
64
+ "@uruhalushia/rule-converter-napi-win32-x64-msvc": "0.1.2",
65
+ "@uruhalushia/rule-converter-napi-win32-arm64-msvc": "0.1.2"
15
66
  }
16
- }
67
+ }