@myassis/gateway 1.0.22 → 1.0.23

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/dist/main.js CHANGED
@@ -159,6 +159,7 @@ else {
159
159
  }
160
160
  // 内网地址正则
161
161
  const lanPatterns = [
162
+ /^http:\/\/tauri.localhost(:\d+)?$/,
162
163
  /^http:\/\/localhost(:\d+)?$/,
163
164
  /^http:\/\/127\.\d+\.\d+\.\d+(:\d+)?$/,
164
165
  /^http:\/\/10\.\d+\.\d+\.\d+(:\d+)?$/,
@@ -9,11 +9,19 @@ const util_1 = require("util");
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const fs_1 = __importDefault(require("fs"));
11
11
  const axios_1 = __importDefault(require("axios"));
12
+ const shared_1 = require("@myassis/shared");
13
+ const os_1 = __importDefault(require("os"));
14
+ const logger = (0, shared_1.getLogger)('ServiceManager');
12
15
  const execAsync = (0, util_1.promisify)(child_process_1.exec);
13
16
  exports.SERVICE_NAME = 'myassis-gateway';
14
17
  exports.SERVICE_DISPLAY_NAME = '我的助手 Desktop Gateway Service';
15
18
  // ─── 平台无关工具 ────────────────────────────────────────────
19
+ function isPackagedExe() {
20
+ return !!process.pkg;
21
+ }
16
22
  function getServiceScript() {
23
+ if (isPackagedExe())
24
+ return '';
17
25
  // npm install -g 后,用当前模块位置定位包目录
18
26
  const pkgRoot = path_1.default.resolve(__dirname, '..', '..');
19
27
  return path_1.default.join(pkgRoot, 'dist', 'index.js');
@@ -21,10 +29,34 @@ function getServiceScript() {
21
29
  function getNodeExec() {
22
30
  return process.execPath;
23
31
  }
32
+ function getNssmPath() {
33
+ // 1. 优先:exe 同目录下有 nssm.exe
34
+ const alongside = path_1.default.join(path_1.default.dirname(process.execPath), 'nssm.exe');
35
+ if (fs_1.default.existsSync(alongside))
36
+ return alongside;
37
+ // 2. pkg 运行时从包内虚拟文件系统提取 nssm.exe 到临时目录
38
+ if (isPackagedExe()) {
39
+ const tmpPath = path_1.default.join(os_1.default.tmpdir(), 'myassis-nssm.exe');
40
+ if (!fs_1.default.existsSync(tmpPath)) {
41
+ try {
42
+ const bundledPath = path_1.default.join(__dirname, '..', '..', 'nssm.exe');
43
+ const data = fs_1.default.readFileSync(bundledPath);
44
+ fs_1.default.writeFileSync(tmpPath, data);
45
+ logger.info(`Extracted nssm.exe to ${tmpPath}`);
46
+ }
47
+ catch (e) {
48
+ logger.warn(`Failed to extract nssm.exe: ${e.message}`);
49
+ return '';
50
+ }
51
+ }
52
+ return tmpPath;
53
+ }
54
+ return '';
55
+ }
24
56
  // ─── Windows 实现 ───────────────────────────────────────────
25
57
  async function queryServiceWindows() {
26
58
  try {
27
- const { stdout } = await execAsync(`sc query ${exports.SERVICE_NAME}`, { timeout: 5000 });
59
+ const { stdout } = await execAsync(`sc.exe query ${exports.SERVICE_NAME}`, { timeout: 5000 });
28
60
  return { installed: true, running: stdout.includes('RUNNING') };
29
61
  }
30
62
  catch {
@@ -32,23 +64,35 @@ async function queryServiceWindows() {
32
64
  }
33
65
  }
34
66
  async function installWindows() {
67
+ const isPkg = isPackagedExe();
35
68
  const script = getServiceScript();
36
- const workDir = path_1.default.dirname(script);
37
- const nodeExe = getNodeExec();
69
+ const exe = getNodeExec();
70
+ const workDir = isPkg ? path_1.default.dirname(exe) : path_1.default.dirname(script);
71
+ logger.info(`isPkg=${isPkg}, exe=${exe}, script=${script}, workDir=${workDir}`);
38
72
  const { installed } = await queryServiceWindows();
39
73
  if (installed)
40
- await stopService();
41
- const nssmPath = path_1.default.join(path_1.default.dirname(process.execPath), 'nssm.exe');
42
- const useNssm = fs_1.default.existsSync(nssmPath);
74
+ await uninstallWindows();
75
+ const nssmPath = getNssmPath();
76
+ const useNssm = !!nssmPath && fs_1.default.existsSync(nssmPath);
43
77
  try {
44
78
  if (useNssm) {
45
- await execAsync(`"${nssmPath}" install ${exports.SERVICE_NAME} "${nodeExe}" "${script}"`, { timeout: 15000, cwd: workDir });
79
+ if (isPkg) {
80
+ await execAsync(`"${nssmPath}" install ${exports.SERVICE_NAME} "${exe}"`, { timeout: 15000, cwd: workDir });
81
+ }
82
+ else {
83
+ await execAsync(`"${nssmPath}" install ${exports.SERVICE_NAME} "${exe}" "${script}"`, { timeout: 15000, cwd: workDir });
84
+ }
46
85
  await execAsync(`"${nssmPath}" set ${exports.SERVICE_NAME} AppDirectory "${workDir}"`, { timeout: 10000 });
47
86
  await execAsync(`"${nssmPath}" set ${exports.SERVICE_NAME} DisplayName "${exports.SERVICE_DISPLAY_NAME}"`, { timeout: 10000 });
48
87
  await execAsync(`"${nssmPath}" set ${exports.SERVICE_NAME} Start SERVICE_AUTO_START`, { timeout: 10000 });
49
88
  }
50
89
  else {
51
- await execAsync(`sc create ${exports.SERVICE_NAME} binPath= "\\"${nodeExe}\\" \\"${script}\\"" DisplayName= "${exports.SERVICE_DISPLAY_NAME}" start= auto`, { timeout: 15000 });
90
+ if (isPkg) {
91
+ await execAsync(`sc.exe create ${exports.SERVICE_NAME} binPath= "\\"${exe}\\"" DisplayName= "${exports.SERVICE_DISPLAY_NAME}" start= auto`, { timeout: 15000 });
92
+ }
93
+ else {
94
+ await execAsync(`sc.exe create ${exports.SERVICE_NAME} binPath= "\\"${exe}\\" \\"${script}\\"" DisplayName= "${exports.SERVICE_DISPLAY_NAME}" start= auto`, { timeout: 15000 });
95
+ }
52
96
  }
53
97
  await startService();
54
98
  return { success: true, message: '服务安装并启动成功' };
@@ -60,12 +104,12 @@ async function installWindows() {
60
104
  async function uninstallWindows() {
61
105
  try {
62
106
  await stopService();
63
- const nssmPath = path_1.default.join(path_1.default.dirname(process.execPath), 'nssm.exe');
64
- if (fs_1.default.existsSync(nssmPath)) {
107
+ const nssmPath = getNssmPath();
108
+ if (nssmPath && fs_1.default.existsSync(nssmPath)) {
65
109
  await execAsync(`"${nssmPath}" remove ${exports.SERVICE_NAME} confirm`, { timeout: 10000 });
66
110
  }
67
111
  else {
68
- await execAsync(`sc delete ${exports.SERVICE_NAME}`, { timeout: 10000 });
112
+ await execAsync(`sc.exe delete ${exports.SERVICE_NAME}`, { timeout: 10000 });
69
113
  }
70
114
  return { success: true, message: '服务卸载成功' };
71
115
  }
@@ -75,7 +119,7 @@ async function uninstallWindows() {
75
119
  }
76
120
  async function startServiceWindows() {
77
121
  try {
78
- await execAsync(`sc start ${exports.SERVICE_NAME}`, { timeout: 10000 });
122
+ await execAsync(`sc.exe start ${exports.SERVICE_NAME}`, { timeout: 10000 });
79
123
  return { success: true, message: '服务启动成功' };
80
124
  }
81
125
  catch (err) {
@@ -83,7 +127,7 @@ async function startServiceWindows() {
83
127
  }
84
128
  }
85
129
  async function restartServiceWindows() {
86
- const nssmPath = path_1.default.join(path_1.default.dirname(process.execPath), 'nssm.exe');
130
+ const nssmPath = getNssmPath();
87
131
  // 无 nssm 时需要用户手动更新
88
132
  if (!fs_1.default.existsSync(nssmPath)) {
89
133
  const info = await getServiceInfo();
@@ -109,7 +153,7 @@ async function restartServiceWindows() {
109
153
  }
110
154
  async function stopServiceWindows() {
111
155
  try {
112
- await execAsync(`sc stop ${exports.SERVICE_NAME}`, { timeout: 10000 });
156
+ await execAsync(`sc.exe stop ${exports.SERVICE_NAME}`, { timeout: 10000 });
113
157
  return { success: true, message: '服务停止成功' };
114
158
  }
115
159
  catch (err) {
@@ -136,28 +180,30 @@ async function queryServiceLinux() {
136
180
  }
137
181
  }
138
182
  async function installLinux() {
183
+ const isPkg = isPackagedExe();
139
184
  const script = getServiceScript();
140
- const workDir = path_1.default.dirname(script);
141
- const nodeExe = getNodeExec();
185
+ const exe = getNodeExec();
186
+ const workDir = isPkg ? path_1.default.dirname(exe) : path_1.default.dirname(script);
142
187
  try {
143
188
  const { installed } = await queryServiceLinux();
144
189
  if (installed)
145
190
  await stopService();
146
- const unitContent = `[Unit]
147
- Description=${exports.SERVICE_DISPLAY_NAME}
148
- After=network.target
149
-
150
- [Service]
151
- Type=simple
152
- User=${process.env.USER || 'root'}
153
- WorkingDirectory=${workDir}
154
- ExecStart=${nodeExe} ${script}
155
- Restart=always
156
- RestartSec=5
157
- Environment=NODE_ENV=production
158
-
159
- [Install]
160
- WantedBy=multi-user.target
191
+ const execStart = isPkg ? exe : `${exe} ${script}`;
192
+ const unitContent = `[Unit]
193
+ Description=${exports.SERVICE_DISPLAY_NAME}
194
+ After=network.target
195
+
196
+ [Service]
197
+ Type=simple
198
+ User=${process.env.USER || 'root'}
199
+ WorkingDirectory=${workDir}
200
+ ExecStart=${execStart}
201
+ Restart=always
202
+ RestartSec=5
203
+ Environment=NODE_ENV=production
204
+
205
+ [Install]
206
+ WantedBy=multi-user.target
161
207
  `;
162
208
  await fs_1.default.promises.writeFile('/tmp/myassis-gateway.service', unitContent, 'utf8');
163
209
  await execAsync('cp /tmp/myassis-gateway.service /etc/systemd/system/myassis-gateway.service', { timeout: 10000 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myassis/gateway",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "description": "我的助手 Gateway Service - 本地 AI 网关服务,支持认证、WebSocket 实时通信和任务调度",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -84,7 +84,8 @@
84
84
  "README*",
85
85
  "node_modules/better-sqlite3/build/Release/better_sqlite3.node",
86
86
  "node_modules/.pnpm/@nut-tree+libnut-linux@2.7.1/node_modules/@nut-tree/libnut-linux/build/Release/libnut.node",
87
- "node_modules/.pnpm/@nut-tree+libnut-win32@2.7.1/node_modules/@nut-tree/libnut-win32/build/Release/libnut.node"
87
+ "node_modules/.pnpm/@nut-tree+libnut-win32@2.7.1/node_modules/@nut-tree/libnut-win32/build/Release/libnut.node",
88
+ "nssm.exe"
88
89
  ],
89
90
  "targets": [
90
91
  "node24-win-x64",