@hermespilot/link 0.2.7 → 0.2.8
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/{chunk-SSJ7WDD7.js → chunk-W4U6XJ4W.js} +862 -373
- package/dist/cli/index.js +150 -3
- package/dist/http/app.js +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
clearPairingClaim,
|
|
7
7
|
currentCliScriptPath,
|
|
8
8
|
daemonLogFile,
|
|
9
|
+
detectRuntimeEnvironment,
|
|
9
10
|
ensureHermesApiServerAvailable,
|
|
10
11
|
ensureHermesApiServerConfig,
|
|
11
12
|
ensureIdentity,
|
|
@@ -15,21 +16,25 @@ import {
|
|
|
15
16
|
hasActiveDevices,
|
|
16
17
|
loadConfig,
|
|
17
18
|
loadIdentity,
|
|
19
|
+
normalizeLanHost,
|
|
18
20
|
preparePairing,
|
|
19
21
|
probeLocalLinkService,
|
|
20
22
|
readHermesApiServerConfig,
|
|
21
23
|
readPairingClaim,
|
|
24
|
+
reportLinkStatusToServer,
|
|
22
25
|
resolveHermesConfigPath,
|
|
23
26
|
resolveHermesProfileDir,
|
|
24
27
|
resolveRuntimePaths,
|
|
25
28
|
runDaemonSupervisor,
|
|
29
|
+
saveConfig,
|
|
26
30
|
startDaemonProcess,
|
|
27
31
|
startLinkService,
|
|
28
32
|
stopDaemonProcess
|
|
29
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-W4U6XJ4W.js";
|
|
30
34
|
|
|
31
35
|
// src/cli/index.ts
|
|
32
36
|
import { Command } from "commander";
|
|
37
|
+
import { createInterface } from "readline/promises";
|
|
33
38
|
import qrcode from "qrcode-terminal";
|
|
34
39
|
|
|
35
40
|
// src/autostart/autostart.ts
|
|
@@ -221,6 +226,9 @@ var messages = {
|
|
|
221
226
|
"status.runtime": "Runtime: {value}",
|
|
222
227
|
"status.mode": "Mode: {value}",
|
|
223
228
|
"status.port": "Local port: {value}",
|
|
229
|
+
"status.lanHost": "Configured LAN host: {value}",
|
|
230
|
+
"status.notSet": "not set",
|
|
231
|
+
"status.environmentWarning": "Network note: {message}",
|
|
224
232
|
"status.linkId": "Link ID: {value}",
|
|
225
233
|
"status.notPaired": "not paired",
|
|
226
234
|
"start.description": "Start Hermes Link daemon",
|
|
@@ -234,6 +242,15 @@ var messages = {
|
|
|
234
242
|
"stop.stopped": "Hermes Link stopped.",
|
|
235
243
|
"stop.notRunning": "Hermes Link is not running.",
|
|
236
244
|
"restart.description": "Restart the background Hermes Link daemon",
|
|
245
|
+
"config.description": "Manage local Hermes Link configuration",
|
|
246
|
+
"config.set.description": "Set a configuration value",
|
|
247
|
+
"config.unset.description": "Unset a configuration value",
|
|
248
|
+
"config.unknownKey": "Unknown config key: {key}",
|
|
249
|
+
"config.lanHostInvalid": "lan-host must be a private LAN IPv4 address, such as 192.168.1.23.",
|
|
250
|
+
"config.lanHostSet": "Configured LAN host: {value}",
|
|
251
|
+
"config.lanHostUnset": "Configured LAN host cleared.",
|
|
252
|
+
"config.reported": "Updated HermesPilot Server with the latest LAN address.",
|
|
253
|
+
"config.reportSkippedUnpaired": "Hermes Link is not paired yet. The LAN address will be reported after pairing.",
|
|
237
254
|
"daemon.description": "Run Hermes Link in the foreground",
|
|
238
255
|
"daemon.foreground": "Hermes Link foreground daemon is running. Press Ctrl+C to stop.",
|
|
239
256
|
"logs.description": "Show Hermes Link log paths",
|
|
@@ -263,6 +280,9 @@ var messages = {
|
|
|
263
280
|
"pair.expires": "Pairing expires in 10 minutes. Press Ctrl+C to cancel waiting.",
|
|
264
281
|
"pair.claimed": "Pairing succeeded. Starting Hermes Link in the background...",
|
|
265
282
|
"pair.claimedRunning": "Pairing succeeded. Hermes Link is already running in the background.",
|
|
283
|
+
"pair.relayOnlyNotice": "Network note: this {kind} environment does not expose a phone-reachable LAN/public direct address by default. The App will connect through Relay.",
|
|
284
|
+
"pair.relayOnlyLanHostHint": "If you manually expose this Link from Windows or your router, run `hermeslink config set lan-host <Windows LAN IP>` to publish the reachable LAN address.",
|
|
285
|
+
"pair.relayOnlySafetyHint": "Hermes Link will not automatically change Windows/WSL bridge, firewall, or portproxy settings because those are system-level network exposure choices.",
|
|
266
286
|
"pair.autostartUnchanged": "Existing paired devices found. Boot autostart settings were left unchanged.",
|
|
267
287
|
"pair.autostartFailed": "Pairing succeeded, but boot autostart could not be enabled: {message}",
|
|
268
288
|
"doctor.description": "Run local diagnostics",
|
|
@@ -270,6 +290,8 @@ var messages = {
|
|
|
270
290
|
"doctor.installId": "Install ID: {value}",
|
|
271
291
|
"doctor.linkId": "Link ID: {value}",
|
|
272
292
|
"doctor.notAssigned": "not assigned",
|
|
293
|
+
"doctor.lanHost": "Configured LAN host: {value}",
|
|
294
|
+
"doctor.networkWarning": "Network note: {message}",
|
|
273
295
|
"doctor.apiReady": "Hermes API Server: ready",
|
|
274
296
|
"doctor.apiStarted": "Hermes API Server: started and ready",
|
|
275
297
|
"doctor.apiUnavailable": "Hermes API Server: unavailable. {message}",
|
|
@@ -290,6 +312,9 @@ var messages = {
|
|
|
290
312
|
"status.runtime": "\u8FD0\u884C\u76EE\u5F55\uFF1A{value}",
|
|
291
313
|
"status.mode": "\u6A21\u5F0F\uFF1A{value}",
|
|
292
314
|
"status.port": "\u672C\u5730\u7AEF\u53E3\uFF1A{value}",
|
|
315
|
+
"status.lanHost": "\u5DF2\u914D\u7F6E\u5C40\u57DF\u7F51\u4E3B\u673A\uFF1A{value}",
|
|
316
|
+
"status.notSet": "\u672A\u8BBE\u7F6E",
|
|
317
|
+
"status.environmentWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
|
|
293
318
|
"status.linkId": "Link ID\uFF1A{value}",
|
|
294
319
|
"status.notPaired": "\u5C1A\u672A\u914D\u5BF9",
|
|
295
320
|
"start.description": "\u542F\u52A8 Hermes Link \u670D\u52A1",
|
|
@@ -303,6 +328,15 @@ var messages = {
|
|
|
303
328
|
"stop.stopped": "Hermes Link \u5DF2\u505C\u6B62\u3002",
|
|
304
329
|
"stop.notRunning": "Hermes Link \u6CA1\u6709\u5728\u8FD0\u884C\u3002",
|
|
305
330
|
"restart.description": "\u91CD\u542F\u540E\u53F0 Hermes Link \u670D\u52A1",
|
|
331
|
+
"config.description": "\u7BA1\u7406\u672C\u673A Hermes Link \u914D\u7F6E",
|
|
332
|
+
"config.set.description": "\u8BBE\u7F6E\u914D\u7F6E\u9879",
|
|
333
|
+
"config.unset.description": "\u6E05\u9664\u914D\u7F6E\u9879",
|
|
334
|
+
"config.unknownKey": "\u672A\u77E5\u914D\u7F6E\u9879\uFF1A{key}",
|
|
335
|
+
"config.lanHostInvalid": "lan-host \u5FC5\u987B\u662F\u5C40\u57DF\u7F51 IPv4 \u5730\u5740\uFF0C\u4F8B\u5982 192.168.1.23\u3002",
|
|
336
|
+
"config.lanHostSet": "\u5DF2\u914D\u7F6E\u5C40\u57DF\u7F51\u4E3B\u673A\uFF1A{value}",
|
|
337
|
+
"config.lanHostUnset": "\u5DF2\u6E05\u9664\u5C40\u57DF\u7F51\u4E3B\u673A\u914D\u7F6E\u3002",
|
|
338
|
+
"config.reported": "\u5DF2\u628A\u6700\u65B0\u5C40\u57DF\u7F51\u5730\u5740\u66F4\u65B0\u5230 HermesPilot Server\u3002",
|
|
339
|
+
"config.reportSkippedUnpaired": "Hermes Link \u8FD8\u6CA1\u6709\u914D\u5BF9\uFF0C\u5C40\u57DF\u7F51\u5730\u5740\u4F1A\u5728\u914D\u5BF9\u540E\u4E0A\u62A5\u3002",
|
|
306
340
|
"daemon.description": "\u4EE5\u524D\u53F0\u65B9\u5F0F\u8FD0\u884C Hermes Link",
|
|
307
341
|
"daemon.foreground": "Hermes Link \u524D\u53F0\u670D\u52A1\u6B63\u5728\u8FD0\u884C\u3002\u6309 Ctrl+C \u505C\u6B62\u3002",
|
|
308
342
|
"logs.description": "\u663E\u793A Hermes Link \u65E5\u5FD7\u8DEF\u5F84",
|
|
@@ -332,6 +366,9 @@ var messages = {
|
|
|
332
366
|
"pair.expires": "\u914D\u5BF9\u4F1A\u8BDD 10 \u5206\u949F\u540E\u8FC7\u671F\u3002\u6309 Ctrl+C \u9000\u51FA\u7B49\u5F85\u3002",
|
|
333
367
|
"pair.claimed": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002\u6B63\u5728\u628A Hermes Link \u5207\u6362\u5230\u540E\u53F0\u8FD0\u884C...",
|
|
334
368
|
"pair.claimedRunning": "\u914D\u5BF9\u5DF2\u6210\u529F\u3002Hermes Link \u5DF2\u5728\u540E\u53F0\u6301\u7EED\u8FD0\u884C\u3002",
|
|
369
|
+
"pair.relayOnlyNotice": "\u7F51\u7EDC\u63D0\u793A\uFF1A\u5F53\u524D\u662F {kind} \u73AF\u5883\uFF0C\u9ED8\u8BA4\u4E0D\u4F1A\u66B4\u9732\u624B\u673A\u53EF\u8BBF\u95EE\u7684\u5C40\u57DF\u7F51\u6216\u516C\u7F51\u76F4\u8FDE\u5730\u5740\u3002App \u4F1A\u901A\u8FC7 Relay \u8FDE\u63A5\u3002",
|
|
370
|
+
"pair.relayOnlyLanHostHint": "\u5982\u679C\u4F60\u5DF2\u7ECF\u5728 Windows \u6216\u8DEF\u7531\u5668\u4FA7\u624B\u52A8\u628A\u8FD9\u4E2A Link \u66B4\u9732\u5230\u5C40\u57DF\u7F51\uFF0C\u53EF\u4EE5\u8FD0\u884C `hermeslink config set lan-host <Windows \u5C40\u57DF\u7F51 IP>` \u66F4\u65B0\u53EF\u8BBF\u95EE\u5730\u5740\u3002",
|
|
371
|
+
"pair.relayOnlySafetyHint": "Hermes Link \u4E0D\u4F1A\u81EA\u52A8\u4FEE\u6539 Windows/WSL \u6865\u63A5\u3001\u9632\u706B\u5899\u6216\u7AEF\u53E3\u4EE3\u7406\u914D\u7F6E\uFF0C\u56E0\u4E3A\u8FD9\u4E9B\u5C5E\u4E8E\u7CFB\u7EDF\u7EA7\u7F51\u7EDC\u66B4\u9732\u8BBE\u7F6E\u3002",
|
|
335
372
|
"pair.autostartUnchanged": "\u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u5BF9\u8BBE\u5907\uFF0C\u5F00\u673A\u81EA\u542F\u8BBE\u7F6E\u4FDD\u6301\u4E0D\u53D8\u3002",
|
|
336
373
|
"pair.autostartFailed": "\u914D\u5BF9\u5DF2\u6210\u529F\uFF0C\u4F46\u542F\u7528\u5F00\u673A\u81EA\u542F\u5931\u8D25\uFF1A{message}",
|
|
337
374
|
"doctor.description": "\u8FD0\u884C\u672C\u673A\u8BCA\u65AD",
|
|
@@ -339,6 +376,8 @@ var messages = {
|
|
|
339
376
|
"doctor.installId": "Install ID\uFF1A{value}",
|
|
340
377
|
"doctor.linkId": "Link ID\uFF1A{value}",
|
|
341
378
|
"doctor.notAssigned": "\u5C1A\u672A\u5206\u914D",
|
|
379
|
+
"doctor.lanHost": "\u5DF2\u914D\u7F6E\u5C40\u57DF\u7F51\u4E3B\u673A\uFF1A{value}",
|
|
380
|
+
"doctor.networkWarning": "\u7F51\u7EDC\u63D0\u793A\uFF1A{message}",
|
|
342
381
|
"doctor.apiReady": "Hermes API Server\uFF1A\u5DF2\u5C31\u7EEA",
|
|
343
382
|
"doctor.apiStarted": "Hermes API Server\uFF1A\u5DF2\u81EA\u52A8\u542F\u52A8\u5E76\u5C31\u7EEA",
|
|
344
383
|
"doctor.apiUnavailable": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528\u3002{message}",
|
|
@@ -598,6 +637,8 @@ program.command("status").option("--json", helpText("status.json")).description(
|
|
|
598
637
|
paired: Boolean(identity?.link_id),
|
|
599
638
|
mode: identity?.link_id ? "paired" : "local-only",
|
|
600
639
|
port: config.port,
|
|
640
|
+
lanHost: config.lanHost,
|
|
641
|
+
environment: detectRuntimeEnvironment(),
|
|
601
642
|
identity: identity ? getIdentityStatus(identity) : null,
|
|
602
643
|
relay: {
|
|
603
644
|
configured: Boolean(config.relayBaseUrl),
|
|
@@ -612,8 +653,43 @@ program.command("status").option("--json", helpText("status.json")).description(
|
|
|
612
653
|
console.log(t("status.runtime", { value: payload.runtimeHome }));
|
|
613
654
|
console.log(t("status.mode", { value: payload.mode }));
|
|
614
655
|
console.log(t("status.port", { value: payload.port }));
|
|
656
|
+
console.log(t("status.lanHost", { value: payload.lanHost ?? t("status.notSet") }));
|
|
657
|
+
if (payload.environment.warning) {
|
|
658
|
+
console.log(t("status.environmentWarning", { message: payload.environment.warning }));
|
|
659
|
+
}
|
|
615
660
|
console.log(t("status.linkId", { value: payload.identity?.linkId ?? t("status.notPaired") }));
|
|
616
661
|
});
|
|
662
|
+
var configCommand = program.command("config").description(helpText("config.description"));
|
|
663
|
+
configCommand.command("set").argument("<key>").argument("<value>").description(helpText("config.set.description")).action(async (key, value) => {
|
|
664
|
+
const paths = resolveRuntimePaths();
|
|
665
|
+
const current = await loadConfig(paths);
|
|
666
|
+
const language = resolveLanguage(current.language);
|
|
667
|
+
const t = translate.bind(null, language);
|
|
668
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
669
|
+
if (normalizedKey !== "lan-host") {
|
|
670
|
+
throw new Error(t("config.unknownKey", { key }));
|
|
671
|
+
}
|
|
672
|
+
const lanHost = normalizeLanHost(value);
|
|
673
|
+
if (!lanHost) {
|
|
674
|
+
throw new Error(t("config.lanHostInvalid"));
|
|
675
|
+
}
|
|
676
|
+
const next = await saveConfig({ lanHost }, paths);
|
|
677
|
+
console.log(t("config.lanHostSet", { value: next.lanHost ?? lanHost }));
|
|
678
|
+
await reportConfigNetworkUpdate(paths, t);
|
|
679
|
+
});
|
|
680
|
+
configCommand.command("unset").argument("<key>").description(helpText("config.unset.description")).action(async (key) => {
|
|
681
|
+
const paths = resolveRuntimePaths();
|
|
682
|
+
const current = await loadConfig(paths);
|
|
683
|
+
const language = resolveLanguage(current.language);
|
|
684
|
+
const t = translate.bind(null, language);
|
|
685
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
686
|
+
if (normalizedKey !== "lan-host") {
|
|
687
|
+
throw new Error(t("config.unknownKey", { key }));
|
|
688
|
+
}
|
|
689
|
+
await saveConfig({ lanHost: null }, paths);
|
|
690
|
+
console.log(t("config.lanHostUnset"));
|
|
691
|
+
await reportConfigNetworkUpdate(paths, t);
|
|
692
|
+
});
|
|
617
693
|
program.command("start").description(helpText("start.description")).action(async () => {
|
|
618
694
|
const [config, status] = await Promise.all([loadConfig(), getDaemonStatus()]);
|
|
619
695
|
const language = resolveLanguage(config.language);
|
|
@@ -661,11 +737,17 @@ program.command("daemon-supervisor", { hidden: true }).action(async () => {
|
|
|
661
737
|
});
|
|
662
738
|
program.command("pair").description(helpText("pair.description")).action(async () => {
|
|
663
739
|
const paths = resolveRuntimePaths();
|
|
664
|
-
|
|
665
|
-
const
|
|
740
|
+
let config = await loadConfig(paths);
|
|
741
|
+
const languageChoice = await resolvePairingLanguage(paths, config);
|
|
742
|
+
config = languageChoice.config;
|
|
743
|
+
const language = languageChoice.language;
|
|
666
744
|
const t = translate.bind(null, language);
|
|
667
745
|
console.log(t("pair.preflight"));
|
|
668
746
|
const preflight = await assertPairingPreflightReady({ paths });
|
|
747
|
+
const environment = detectRuntimeEnvironment();
|
|
748
|
+
if (environment.warning) {
|
|
749
|
+
console.log(t("doctor.networkWarning", { message: environment.warning }));
|
|
750
|
+
}
|
|
669
751
|
console.log(t("pair.hermesHome", { path: preflight.hermesHome }));
|
|
670
752
|
console.log(t("pair.apiReady", { port: preflight.apiServer.port ?? "unknown" }));
|
|
671
753
|
console.log(t("pair.preparing"));
|
|
@@ -705,6 +787,7 @@ program.command("pair").description(helpText("pair.description")).action(async (
|
|
|
705
787
|
if (result === "claimed") {
|
|
706
788
|
await clearPairingClaim(prepared.sessionId, paths);
|
|
707
789
|
console.log(t(reusedRunningService ? "pair.claimedRunning" : "pair.claimed"));
|
|
790
|
+
printPostPairingNetworkNotice(prepared.routes.environment, config, t);
|
|
708
791
|
try {
|
|
709
792
|
if (hadActiveDevices) {
|
|
710
793
|
console.log(t("pair.autostartUnchanged"));
|
|
@@ -789,6 +872,11 @@ program.command("doctor").description(helpText("doctor.description")).action(asy
|
|
|
789
872
|
console.log(t("doctor.identityOk"));
|
|
790
873
|
console.log(t("doctor.installId", { value: identity.install_id }));
|
|
791
874
|
console.log(t("doctor.linkId", { value: identity.link_id ?? t("doctor.notAssigned") }));
|
|
875
|
+
const environment = detectRuntimeEnvironment();
|
|
876
|
+
if (environment.warning) {
|
|
877
|
+
console.log(t("doctor.networkWarning", { message: environment.warning }));
|
|
878
|
+
}
|
|
879
|
+
console.log(t("doctor.lanHost", { value: config.lanHost ?? t("status.notSet") }));
|
|
792
880
|
if (hermesConfig.notice) {
|
|
793
881
|
console.log(hermesConfig.notice);
|
|
794
882
|
if (hermesConfig.backupPath) {
|
|
@@ -811,6 +899,48 @@ async function loadCliLanguage() {
|
|
|
811
899
|
const config = await loadConfig();
|
|
812
900
|
return resolveLanguage(config.language);
|
|
813
901
|
}
|
|
902
|
+
async function resolvePairingLanguage(paths, config) {
|
|
903
|
+
if (config.language !== "auto") {
|
|
904
|
+
return { config, language: resolveLanguage(config.language) };
|
|
905
|
+
}
|
|
906
|
+
const selected = await promptForLanguage();
|
|
907
|
+
if (!selected) {
|
|
908
|
+
return { config, language: resolveLanguage(config.language) };
|
|
909
|
+
}
|
|
910
|
+
const next = await saveConfig({ language: selected }, paths);
|
|
911
|
+
return { config: next, language: selected };
|
|
912
|
+
}
|
|
913
|
+
async function promptForLanguage() {
|
|
914
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
const rl = createInterface({
|
|
918
|
+
input: process.stdin,
|
|
919
|
+
output: process.stdout
|
|
920
|
+
});
|
|
921
|
+
try {
|
|
922
|
+
for (; ; ) {
|
|
923
|
+
const answer = await rl.question(
|
|
924
|
+
[
|
|
925
|
+
"\u8BF7\u9009\u62E9 Hermes Link \u663E\u793A\u8BED\u8A00 / Choose Hermes Link language:",
|
|
926
|
+
" 1. \u4E2D\u6587",
|
|
927
|
+
" 2. English",
|
|
928
|
+
"\u8F93\u5165 1 \u6216 2 \u540E\u56DE\u8F66 / Enter 1 or 2: "
|
|
929
|
+
].join("\n")
|
|
930
|
+
);
|
|
931
|
+
const normalized = answer.trim().toLowerCase();
|
|
932
|
+
if (normalized === "1" || normalized === "zh" || normalized === "zh-cn" || normalized === "\u4E2D\u6587") {
|
|
933
|
+
return "zh-CN";
|
|
934
|
+
}
|
|
935
|
+
if (normalized === "2" || normalized === "en" || normalized === "english") {
|
|
936
|
+
return "en";
|
|
937
|
+
}
|
|
938
|
+
console.log("\u8BF7\u8F93\u5165 1 \u6216 2\u3002 / Please enter 1 or 2.");
|
|
939
|
+
}
|
|
940
|
+
} finally {
|
|
941
|
+
rl.close();
|
|
942
|
+
}
|
|
943
|
+
}
|
|
814
944
|
async function waitForShutdown(cleanup) {
|
|
815
945
|
await new Promise((resolve) => {
|
|
816
946
|
const stop = () => resolve();
|
|
@@ -843,3 +973,20 @@ async function waitForPairingOrShutdown(sessionId, paths) {
|
|
|
843
973
|
function sleep(ms) {
|
|
844
974
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
845
975
|
}
|
|
976
|
+
async function reportConfigNetworkUpdate(paths, t) {
|
|
977
|
+
const identity = await loadIdentity(paths);
|
|
978
|
+
if (!identity?.link_id) {
|
|
979
|
+
console.log(t("config.reportSkippedUnpaired"));
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
await reportLinkStatusToServer({ paths });
|
|
983
|
+
console.log(t("config.reported"));
|
|
984
|
+
}
|
|
985
|
+
function printPostPairingNetworkNotice(environment, config, t) {
|
|
986
|
+
if (environment.lanAutoDiscoveryUsable || config.lanHost) {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
console.log(t("pair.relayOnlyNotice", { kind: environment.kind }));
|
|
990
|
+
console.log(t("pair.relayOnlyLanHostHint"));
|
|
991
|
+
console.log(t("pair.relayOnlySafetyHint"));
|
|
992
|
+
}
|
package/dist/http/app.js
CHANGED