@napuketto/loader 0.0.26 → 0.0.27

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.
@@ -741,6 +741,16 @@ function replayStatus() {
741
741
  payload: lastStatus
742
742
  });
743
743
  }
744
+ /** 最近一次 status 的 phase(从未发送过为 null)。
745
+ * 引导失败决策用:判断「是否已发过更具体的 failed」,避免通用 failed 覆盖具体错误码。 */
746
+ function lastIpcStatusPhase() {
747
+ return lastStatus?.phase ?? null;
748
+ }
749
+ /** 引导未完成时是否补发通用 failed:仅 IPC 模式且最近一条不是 failed
750
+ * (已发过带具体错误码的 failed 时不覆盖,如登录失败的 NOT_LOGIN)。 */
751
+ function shouldSendGenericBootFailed(ipcMode, lastPhase) {
752
+ return ipcMode && lastPhase !== "failed";
753
+ }
744
754
  /** 登录状态(QR 状态机 idle/waiting_scan/scanned/logged_in/failed)。 */
745
755
  function sendLogin(state, selfInfo, message) {
746
756
  sendIpc({
@@ -1349,7 +1359,13 @@ async function createKernelServices(kernel, ctx, loginResult) {
1349
1359
  * kernel 服务),返回 KernelServices 由 bootstrap 装配 ipc-server。
1350
1360
  * - 非 IPC(cli pnpm start):照旧装配 OB11/Satori 网络传输。
1351
1361
  */
1352
- /** 登录成功后装配协议:IPC 模式返回 kernel 服务(供 ipc-server),否则装配 OB11/Satori。 */
1362
+ /**
1363
+ * 登录成功后装配协议:IPC 模式返回 kernel 服务(供 ipc-server),否则装配 OB11/Satori。
1364
+ *
1365
+ * 返回 null = 服务未装配(session 缺失 / OB11/Satori 装配失败)——调用方据此判
1366
+ * 引导失败。env 未注入 adapter/network 入口时「跳过装配」仍返回服务(合法运行形态,
1367
+ * 如纯 kernel 探测),不算失败。
1368
+ */
1353
1369
  async function startProtocols(kernel, ctx, loginResult) {
1354
1370
  const services = await createKernelServices(kernel, ctx, loginResult);
1355
1371
  if (services === null) return null;
@@ -1361,6 +1377,7 @@ async function startProtocols(kernel, ctx, loginResult) {
1361
1377
  await assembleOb11AndSatori(kernel, services, loginResult);
1362
1378
  } catch (e) {
1363
1379
  log(`bootstrap: 协议装配失败: ${errMsg(e)}`);
1380
+ return null;
1364
1381
  }
1365
1382
  return services;
1366
1383
  }
@@ -1778,10 +1795,12 @@ function runProbePhase(kernel, ctx) {
1778
1795
  log(`bootstrap: probe error: ${errMsg(e)}`);
1779
1796
  }
1780
1797
  }
1781
- /** NapukettoCore 装配路径:create → attachWrapper → 登录 → 激活 → 协议 → 探测。 */
1798
+ /** NapukettoCore 装配路径:create → attachWrapper → 登录 → 激活 → 协议 → 探测。
1799
+ * @returns 引导是否完整完成(协议服务装配成功 = true;登录失败/服务装配失败等
1800
+ * 静默收敛为 false,具体原因见 napuketto-boot.log)。 */
1782
1801
  async function bootstrapWithCore(kernel, state, bootEnv, Appid) {
1783
1802
  const coreCtor = kernel.NapukettoCore;
1784
- if (coreCtor === void 0) return;
1803
+ if (coreCtor === void 0) return false;
1785
1804
  const core = coreCtor.create({
1786
1805
  paths: { dataRoot: bootEnv.dataDir },
1787
1806
  logLevel: "info",
@@ -1802,7 +1821,7 @@ async function bootstrapWithCore(kernel, state, bootEnv, Appid) {
1802
1821
  probeSessionMethods(ctx);
1803
1822
  if (typeof core.login !== "function") {
1804
1823
  log("bootstrap: kernel core missing login fn");
1805
- return;
1824
+ return false;
1806
1825
  }
1807
1826
  const forcedUin = env.NAPUTO_QUICK_UIN;
1808
1827
  const ref = { targetUin: void 0 };
@@ -1815,7 +1834,7 @@ async function bootstrapWithCore(kernel, state, bootEnv, Appid) {
1815
1834
  code: "NOT_LOGIN",
1816
1835
  message: "登录失败"
1817
1836
  });
1818
- return;
1837
+ return false;
1819
1838
  }
1820
1839
  log(`bootstrap: 登录成功 uin=${loginResult.uin} uid=${loginResult.uid} nick=${loginResult.nick}`);
1821
1840
  if (env.NAPUTO_IPC === "1") sendLogin("logged_in", {
@@ -1828,11 +1847,16 @@ async function bootstrapWithCore(kernel, state, bootEnv, Appid) {
1828
1847
  if (env.NAPUTO_IPC === "1") sendStatus("sessioning");
1829
1848
  await runSmokeIfEnabled(kernel, ctx, loginResult);
1830
1849
  const services = await startProtocols(kernel, ctx, loginResult);
1831
- if (env.NAPUTO_IPC === "1" && services !== null && ipcActions !== null) {
1850
+ if (services === null) {
1851
+ log("bootstrap: 协议服务装配失败,引导中止");
1852
+ return false;
1853
+ }
1854
+ if (env.NAPUTO_IPC === "1" && ipcActions !== null) {
1832
1855
  attachIpcServices(ipcActions, services);
1833
1856
  await attachOb11IpcBridge(ipcActions, services);
1834
1857
  }
1835
1858
  runProbePhase(kernel, ctx);
1859
+ return true;
1836
1860
  }
1837
1861
  //#endregion
1838
1862
  //#region src/host/core/bootstrap.ts
@@ -1867,11 +1891,11 @@ function resolveAppid(kernel, bootEnv) {
1867
1891
  }
1868
1892
  throw new Error("无法从 major.node 解析 appid,请确认 wrapper.node/major.node 完整,或更新 qq-releases.json");
1869
1893
  }
1870
- /** 快速登录 + session 初始化(kernel lifecycle 路径;生命周期方法缺失则跳过)。 */
1894
+ /** 快速登录 + session 初始化(kernel lifecycle 路径)。生命周期方法缺失 → false(无登录态,引导不完整)。 */
1871
1895
  async function quickLoginAndStartSession(kernel, ctx, Appid, bootEnv) {
1872
1896
  if (typeof kernel.quickLogin !== "function" || typeof kernel.initAndStartSession !== "function") {
1873
1897
  log("bootstrap: kernel missing lifecycle fns (quickLogin/initAndStartSession)");
1874
- return;
1898
+ return false;
1875
1899
  }
1876
1900
  if (typeof kernel.buildLoginConfig === "function" && ctx.loginService) {
1877
1901
  const loginCfg = kernel.buildLoginConfig(Appid, bootEnv.qqVersion || "", bootEnv.dataDir || ".");
@@ -1895,6 +1919,7 @@ async function quickLoginAndStartSession(kernel, ctx, Appid, bootEnv) {
1895
1919
  const listener = kernel.createLifecycleSessionListener();
1896
1920
  await kernel.initAndStartSession(ctx, sessionConfig, listener, { timeoutMs: 2e4 });
1897
1921
  log("bootstrap: session init + startNT OK!");
1922
+ return true;
1898
1923
  }
1899
1924
  /** 冒烟探测(NAPUTO_PROBE=1 时运行)。 */
1900
1925
  async function probeRuntime(kernel, ctx) {
@@ -1906,7 +1931,7 @@ async function probeRuntime(kernel, ctx) {
1906
1931
  log(`bootstrap: probe error: ${errMsg(e)}`);
1907
1932
  }
1908
1933
  }
1909
- /** 回退:旧装配路径(startNapuketto + 手工 lifecycle)。 */
1934
+ /** 回退:旧装配路径(startNapuketto + 手工 lifecycle)。返回引导是否完整完成。 */
1910
1935
  async function bootstrapFallback(kernel, state, bootEnv, Appid) {
1911
1936
  log("bootstrap: kernel has no NapukettoCore, falling back");
1912
1937
  const ctx = kernel.startNapuketto?.({
@@ -1915,25 +1940,31 @@ async function bootstrapFallback(kernel, state, bootEnv, Appid) {
1915
1940
  });
1916
1941
  if (ctx === void 0) {
1917
1942
  log("bootstrap: startNapuketto 不可用");
1918
- return;
1943
+ return false;
1919
1944
  }
1920
1945
  log(`bootstrap: startNapuketto OK, engine=${typeof ctx.engine}, session=${ctx.session !== null}`);
1921
- await quickLoginAndStartSession(kernel, ctx, Appid, bootEnv);
1946
+ const loggedIn = await quickLoginAndStartSession(kernel, ctx, Appid, bootEnv);
1922
1947
  await probeRuntime(kernel, ctx);
1948
+ return loggedIn;
1923
1949
  }
1924
- /** 核心引导:import kernel → 装配 → 登录 → 替换 session → 等待就绪 → 协议装配。 */
1950
+ /**
1951
+ * 核心引导:import kernel → 装配 → 登录 → 替换 session → 等待就绪 → 协议装配。
1952
+ * @returns 引导是否完整完成(IPC 模式 = 协议服务装配成功;各失败路径静默收敛为
1953
+ * false 而非抛错,具体原因记录在 NAPUTO_CFG_DIR 下 napuketto-boot.log——
1954
+ * 调用方 self-host 依此决定 ready/failed 与进程去留)。
1955
+ */
1925
1956
  async function bootstrap(state) {
1926
1957
  const kernelEntry = env.NAPUTO_KERNEL_ENTRY;
1927
1958
  if (!kernelEntry) {
1928
1959
  log("bootstrap: NAPUTO_KERNEL_ENTRY not set");
1929
- return;
1960
+ return false;
1930
1961
  }
1931
1962
  try {
1932
1963
  const kernel = await import(`file://${kernelEntry.replace(/\\/g, "/")}`);
1933
1964
  log(`bootstrap: kernel imported, keys: ${Object.keys(kernel).join(", ")}`);
1934
1965
  if (typeof kernel.startNapuketto !== "function" && typeof kernel.NapukettoCore !== "function") {
1935
1966
  log("bootstrap: kernel 无 startNapuketto/NapukettoCore 导出");
1936
- return;
1967
+ return false;
1937
1968
  }
1938
1969
  const bootEnv = {
1939
1970
  qqVersion: env.NAPUTO_QQ_VERSION || "",
@@ -1943,13 +1974,15 @@ async function bootstrap(state) {
1943
1974
  try {
1944
1975
  const Appid = resolveAppid(kernel, bootEnv);
1945
1976
  log(`bootstrap: appid=${Appid}(wrapper=${bootEnv.wrapperPath})`);
1946
- if (kernel.NapukettoCore !== void 0) await bootstrapWithCore(kernel, state, bootEnv, Appid);
1947
- else await bootstrapFallback(kernel, state, bootEnv, Appid);
1977
+ if (kernel.NapukettoCore !== void 0) return await bootstrapWithCore(kernel, state, bootEnv, Appid);
1978
+ return await bootstrapFallback(kernel, state, bootEnv, Appid);
1948
1979
  } catch (e) {
1949
1980
  log(`bootstrap: lifecycle error: ${errMsg(e)}`);
1981
+ return false;
1950
1982
  }
1951
1983
  } catch (e) {
1952
1984
  log(`bootstrap: import kernel failed: ${errMsg(e)}`);
1985
+ return false;
1953
1986
  }
1954
1987
  }
1955
1988
  //#endregion
@@ -2047,7 +2080,13 @@ try {
2047
2080
  log("[self-host] 调 bootstrap(state) ...");
2048
2081
  (async () => {
2049
2082
  try {
2050
- await bootstrap(state);
2083
+ if (!await bootstrap(state)) {
2084
+ if (shouldSendGenericBootFailed(ipcMode, lastIpcStatusPhase())) sendStatus("failed", "bootstrap 未完成", {
2085
+ code: "UNKNOWN",
2086
+ message: "bootstrap 未完成,详见 napuketto-boot.log"
2087
+ });
2088
+ process.exit(1);
2089
+ }
2051
2090
  log("[self-host] bootstrap 完成");
2052
2091
  if (ipcMode) sendStatus("ready");
2053
2092
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@napuketto/loader",
3
- "version": "0.0.26",
3
+ "version": "0.0.27",
4
4
  "description": "NapukettoQQ 引导组件:自建宿主(标准 Node + stub QQNT.dll)dlopen wrapper.node 并启动 kernel,不拉起 QQ / 不注入",
5
5
  "type": "module",
6
6
  "files": [