@lhremote/core 0.0.0 → 0.1.0
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/LICENSE +661 -0
- package/dist/cdp/client.d.ts +100 -0
- package/dist/cdp/client.d.ts.map +1 -0
- package/dist/cdp/client.integration.test.d.ts +2 -0
- package/dist/cdp/client.integration.test.d.ts.map +1 -0
- package/dist/cdp/client.integration.test.js +70 -0
- package/dist/cdp/client.integration.test.js.map +1 -0
- package/dist/cdp/client.js +286 -0
- package/dist/cdp/client.js.map +1 -0
- package/dist/cdp/client.test.d.ts +2 -0
- package/dist/cdp/client.test.d.ts.map +1 -0
- package/dist/cdp/client.test.js +269 -0
- package/dist/cdp/client.test.js.map +1 -0
- package/dist/cdp/discovery.d.ts +14 -0
- package/dist/cdp/discovery.d.ts.map +1 -0
- package/dist/cdp/discovery.integration.test.d.ts +2 -0
- package/dist/cdp/discovery.integration.test.d.ts.map +1 -0
- package/dist/cdp/discovery.integration.test.js +25 -0
- package/dist/cdp/discovery.integration.test.js.map +1 -0
- package/dist/cdp/discovery.js +31 -0
- package/dist/cdp/discovery.js.map +1 -0
- package/dist/cdp/discovery.test.d.ts +2 -0
- package/dist/cdp/discovery.test.d.ts.map +1 -0
- package/dist/cdp/discovery.test.js +54 -0
- package/dist/cdp/discovery.test.js.map +1 -0
- package/dist/cdp/errors.d.ts +28 -0
- package/dist/cdp/errors.d.ts.map +1 -0
- package/dist/cdp/errors.js +40 -0
- package/dist/cdp/errors.js.map +1 -0
- package/dist/cdp/errors.test.d.ts +2 -0
- package/dist/cdp/errors.test.d.ts.map +1 -0
- package/dist/cdp/errors.test.js +35 -0
- package/dist/cdp/errors.test.js.map +1 -0
- package/dist/cdp/index.d.ts +5 -0
- package/dist/cdp/index.d.ts.map +1 -0
- package/dist/cdp/index.js +5 -0
- package/dist/cdp/index.js.map +1 -0
- package/dist/cdp/instance-discovery.d.ts +30 -0
- package/dist/cdp/instance-discovery.d.ts.map +1 -0
- package/dist/cdp/instance-discovery.integration.test.d.ts +2 -0
- package/dist/cdp/instance-discovery.integration.test.d.ts.map +1 -0
- package/dist/cdp/instance-discovery.integration.test.js +34 -0
- package/dist/cdp/instance-discovery.integration.test.js.map +1 -0
- package/dist/cdp/instance-discovery.js +130 -0
- package/dist/cdp/instance-discovery.js.map +1 -0
- package/dist/cdp/instance-discovery.test.d.ts +2 -0
- package/dist/cdp/instance-discovery.test.d.ts.map +1 -0
- package/dist/cdp/instance-discovery.test.js +110 -0
- package/dist/cdp/instance-discovery.test.js.map +1 -0
- package/dist/cdp/testing/launch-chromium.d.ts +24 -0
- package/dist/cdp/testing/launch-chromium.d.ts.map +1 -0
- package/dist/cdp/testing/launch-chromium.js +90 -0
- package/dist/cdp/testing/launch-chromium.js.map +1 -0
- package/dist/db/client.d.ts +13 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.integration.test.d.ts +2 -0
- package/dist/db/client.integration.test.d.ts.map +1 -0
- package/dist/db/client.integration.test.js +59 -0
- package/dist/db/client.integration.test.js.map +1 -0
- package/dist/db/client.js +17 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/client.test.d.ts +2 -0
- package/dist/db/client.test.d.ts.map +1 -0
- package/dist/db/client.test.js +46 -0
- package/dist/db/client.test.js.map +1 -0
- package/dist/db/discovery.d.ts +14 -0
- package/dist/db/discovery.d.ts.map +1 -0
- package/dist/db/discovery.integration.test.d.ts +2 -0
- package/dist/db/discovery.integration.test.d.ts.map +1 -0
- package/dist/db/discovery.integration.test.js +99 -0
- package/dist/db/discovery.integration.test.js.map +1 -0
- package/dist/db/discovery.js +74 -0
- package/dist/db/discovery.js.map +1 -0
- package/dist/db/discovery.test.d.ts +2 -0
- package/dist/db/discovery.test.d.ts.map +1 -0
- package/dist/db/discovery.test.js +123 -0
- package/dist/db/discovery.test.js.map +1 -0
- package/dist/db/errors.d.ts +21 -0
- package/dist/db/errors.d.ts.map +1 -0
- package/dist/db/errors.js +33 -0
- package/dist/db/errors.js.map +1 -0
- package/dist/db/errors.test.d.ts +2 -0
- package/dist/db/errors.test.d.ts.map +1 -0
- package/dist/db/errors.test.js +32 -0
- package/dist/db/errors.test.js.map +1 -0
- package/dist/db/index.d.ts +5 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +5 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/repositories/index.d.ts +2 -0
- package/dist/db/repositories/index.d.ts.map +1 -0
- package/dist/db/repositories/index.js +2 -0
- package/dist/db/repositories/index.js.map +1 -0
- package/dist/db/repositories/profile.d.ts +32 -0
- package/dist/db/repositories/profile.d.ts.map +1 -0
- package/dist/db/repositories/profile.integration.test.d.ts +2 -0
- package/dist/db/repositories/profile.integration.test.d.ts.map +1 -0
- package/dist/db/repositories/profile.integration.test.js +119 -0
- package/dist/db/repositories/profile.integration.test.js.map +1 -0
- package/dist/db/repositories/profile.js +126 -0
- package/dist/db/repositories/profile.js.map +1 -0
- package/dist/db/repositories/profile.test.d.ts +2 -0
- package/dist/db/repositories/profile.test.d.ts.map +1 -0
- package/dist/db/repositories/profile.test.js +126 -0
- package/dist/db/repositories/profile.test.js.map +1 -0
- package/dist/db/testing/create-fixture.d.ts +8 -0
- package/dist/db/testing/create-fixture.d.ts.map +1 -0
- package/dist/db/testing/create-fixture.js +286 -0
- package/dist/db/testing/create-fixture.js.map +1 -0
- package/dist/db/testing/open-fixture.d.ts +14 -0
- package/dist/db/testing/open-fixture.d.ts.map +1 -0
- package/dist/db/testing/open-fixture.js +21 -0
- package/dist/db/testing/open-fixture.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/services/app.d.ts +62 -0
- package/dist/services/app.d.ts.map +1 -0
- package/dist/services/app.js +198 -0
- package/dist/services/app.js.map +1 -0
- package/dist/services/app.test.d.ts +2 -0
- package/dist/services/app.test.d.ts.map +1 -0
- package/dist/services/app.test.js +265 -0
- package/dist/services/app.test.js.map +1 -0
- package/dist/services/errors.d.ts +45 -0
- package/dist/services/errors.d.ts.map +1 -0
- package/dist/services/errors.js +66 -0
- package/dist/services/errors.js.map +1 -0
- package/dist/services/errors.test.d.ts +2 -0
- package/dist/services/errors.test.d.ts.map +1 -0
- package/dist/services/errors.test.js +71 -0
- package/dist/services/errors.test.js.map +1 -0
- package/dist/services/index.d.ts +8 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/instance-lifecycle.d.ts +38 -0
- package/dist/services/instance-lifecycle.d.ts.map +1 -0
- package/dist/services/instance-lifecycle.js +87 -0
- package/dist/services/instance-lifecycle.js.map +1 -0
- package/dist/services/instance-lifecycle.test.d.ts +2 -0
- package/dist/services/instance-lifecycle.test.d.ts.map +1 -0
- package/dist/services/instance-lifecycle.test.js +152 -0
- package/dist/services/instance-lifecycle.test.js.map +1 -0
- package/dist/services/instance.d.ts +50 -0
- package/dist/services/instance.d.ts.map +1 -0
- package/dist/services/instance.js +121 -0
- package/dist/services/instance.js.map +1 -0
- package/dist/services/instance.test.d.ts +2 -0
- package/dist/services/instance.test.d.ts.map +1 -0
- package/dist/services/instance.test.js +181 -0
- package/dist/services/instance.test.js.map +1 -0
- package/dist/services/launcher.d.ts +51 -0
- package/dist/services/launcher.d.ts.map +1 -0
- package/dist/services/launcher.js +147 -0
- package/dist/services/launcher.js.map +1 -0
- package/dist/services/launcher.test.d.ts +2 -0
- package/dist/services/launcher.test.d.ts.map +1 -0
- package/dist/services/launcher.test.js +126 -0
- package/dist/services/launcher.test.js.map +1 -0
- package/dist/services/profile.d.ts +44 -0
- package/dist/services/profile.d.ts.map +1 -0
- package/dist/services/profile.js +83 -0
- package/dist/services/profile.js.map +1 -0
- package/dist/services/profile.test.d.ts +2 -0
- package/dist/services/profile.test.d.ts.map +1 -0
- package/dist/services/profile.test.js +145 -0
- package/dist/services/profile.test.js.map +1 -0
- package/dist/services/status.d.ts +33 -0
- package/dist/services/status.d.ts.map +1 -0
- package/dist/services/status.js +76 -0
- package/dist/services/status.js.map +1 -0
- package/dist/services/status.test.d.ts +2 -0
- package/dist/services/status.test.d.ts.map +1 -0
- package/dist/services/status.test.js +207 -0
- package/dist/services/status.test.js.map +1 -0
- package/dist/testing/e2e-helpers.d.ts +41 -0
- package/dist/testing/e2e-helpers.d.ts.map +1 -0
- package/dist/testing/e2e-helpers.js +111 -0
- package/dist/testing/e2e-helpers.js.map +1 -0
- package/dist/types/account.d.ts +13 -0
- package/dist/types/account.d.ts.map +1 -0
- package/dist/types/account.js +2 -0
- package/dist/types/account.js.map +1 -0
- package/dist/types/account.test.d.ts +2 -0
- package/dist/types/account.test.d.ts.map +1 -0
- package/dist/types/account.test.js +24 -0
- package/dist/types/account.test.js.map +1 -0
- package/dist/types/cdp.d.ts +18 -0
- package/dist/types/cdp.d.ts.map +1 -0
- package/dist/types/cdp.js +2 -0
- package/dist/types/cdp.js.map +1 -0
- package/dist/types/cdp.test.d.ts +2 -0
- package/dist/types/cdp.test.d.ts.map +1 -0
- package/dist/types/cdp.test.js +28 -0
- package/dist/types/cdp.test.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/instance.d.ts +36 -0
- package/dist/types/instance.d.ts.map +1 -0
- package/dist/types/instance.js +8 -0
- package/dist/types/instance.js.map +1 -0
- package/dist/types/instance.test.d.ts +2 -0
- package/dist/types/instance.test.d.ts.map +1 -0
- package/dist/types/instance.test.js +57 -0
- package/dist/types/instance.test.js.map +1 -0
- package/dist/types/profile.d.ts +50 -0
- package/dist/types/profile.d.ts.map +1 -0
- package/dist/types/profile.js +8 -0
- package/dist/types/profile.js.map +1 -0
- package/dist/types/profile.test.d.ts +2 -0
- package/dist/types/profile.test.d.ts.map +1 -0
- package/dist/types/profile.test.js +103 -0
- package/dist/types/profile.test.js.map +1 -0
- package/package.json +20 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-lifecycle.js","sourceRoot":"","sources":["../../src/services/instance-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAEtC,mFAAmF;AACnF,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAErC,qDAAqD;AACrD,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAEtC,kEAAkE;AAClE,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAUnC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,QAAyB,EACzB,SAAiB,EACjB,YAAoB;IAEpB,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IACE,KAAK,YAAY,kBAAkB;YACnC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EACzC,CAAC;YACD,MAAM,YAAY,GAAG,MAAM,oBAAoB,CAAC,YAAY,CAAC,CAAC;YAC9D,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;gBAC1B,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;YAC3D,CAAC;YAED,+BAA+B;YAC/B,MAAM,QAAQ,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAClC,MAAM,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,YAAY,CAAC,CAAC;IACrD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC/B,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAAoB;IAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,sBAAsB,CAAC;IAErD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,YAAY,CAAC,CAAC;QACtD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,YAAoB;IAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,qBAAqB,CAAC;IAEpD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,YAAY,CAAC,CAAC;QACtD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QACD,MAAM,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-lifecycle.test.d.ts","sourceRoot":"","sources":["../../src/services/instance-lifecycle.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
vi.mock("../cdp/index.js", async (importOriginal) => {
|
|
3
|
+
const actual = await importOriginal();
|
|
4
|
+
return {
|
|
5
|
+
...actual,
|
|
6
|
+
discoverInstancePort: vi.fn(),
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
import { discoverInstancePort } from "../cdp/index.js";
|
|
10
|
+
import { StartInstanceError } from "./errors.js";
|
|
11
|
+
import { startInstanceWithRecovery, waitForInstancePort, waitForInstanceShutdown, } from "./instance-lifecycle.js";
|
|
12
|
+
function createMockLauncher(overrides = {}) {
|
|
13
|
+
return {
|
|
14
|
+
connect: vi.fn().mockResolvedValue(undefined),
|
|
15
|
+
disconnect: vi.fn(),
|
|
16
|
+
startInstance: vi.fn().mockResolvedValue(undefined),
|
|
17
|
+
stopInstance: vi.fn().mockResolvedValue(undefined),
|
|
18
|
+
listAccounts: vi.fn().mockResolvedValue([]),
|
|
19
|
+
...overrides,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
describe("startInstanceWithRecovery", () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
vi.clearAllMocks();
|
|
25
|
+
vi.useFakeTimers({ shouldAdvanceTime: true });
|
|
26
|
+
});
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.useRealTimers();
|
|
29
|
+
vi.restoreAllMocks();
|
|
30
|
+
});
|
|
31
|
+
it("returns started with port on successful start", async () => {
|
|
32
|
+
const launcher = createMockLauncher();
|
|
33
|
+
vi.mocked(discoverInstancePort).mockResolvedValue(55123);
|
|
34
|
+
const result = await startInstanceWithRecovery(launcher, 42, 9222);
|
|
35
|
+
expect(launcher.startInstance).toHaveBeenCalledWith(42);
|
|
36
|
+
expect(result).toEqual({ status: "started", port: 55123 });
|
|
37
|
+
});
|
|
38
|
+
it("returns already_running when instance is running and port discoverable", async () => {
|
|
39
|
+
const launcher = createMockLauncher({
|
|
40
|
+
startInstance: vi
|
|
41
|
+
.fn()
|
|
42
|
+
.mockRejectedValue(new StartInstanceError(42, "account is already running")),
|
|
43
|
+
});
|
|
44
|
+
vi.mocked(discoverInstancePort).mockResolvedValue(55123);
|
|
45
|
+
const result = await startInstanceWithRecovery(launcher, 42, 9222);
|
|
46
|
+
expect(result).toEqual({ status: "already_running", port: 55123 });
|
|
47
|
+
expect(launcher.stopInstance).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
it("performs crash recovery when already running but no port", async () => {
|
|
50
|
+
const startInstance = vi
|
|
51
|
+
.fn()
|
|
52
|
+
.mockRejectedValueOnce(new StartInstanceError(42, "account is already running"))
|
|
53
|
+
.mockResolvedValueOnce(undefined);
|
|
54
|
+
const launcher = createMockLauncher({ startInstance });
|
|
55
|
+
// First call (already running check): no port → crash recovery
|
|
56
|
+
// After recovery + restart: port available
|
|
57
|
+
vi.mocked(discoverInstancePort)
|
|
58
|
+
.mockResolvedValueOnce(null)
|
|
59
|
+
.mockResolvedValue(55999);
|
|
60
|
+
const result = await startInstanceWithRecovery(launcher, 42, 9222);
|
|
61
|
+
expect(launcher.stopInstance).toHaveBeenCalledWith(42);
|
|
62
|
+
expect(startInstance).toHaveBeenCalledTimes(2);
|
|
63
|
+
expect(result).toEqual({ status: "started", port: 55999 });
|
|
64
|
+
});
|
|
65
|
+
it("returns timeout when port never becomes available", async () => {
|
|
66
|
+
const launcher = createMockLauncher();
|
|
67
|
+
vi.mocked(discoverInstancePort).mockResolvedValue(null);
|
|
68
|
+
const resultPromise = startInstanceWithRecovery(launcher, 42, 9222);
|
|
69
|
+
await vi.advanceTimersByTimeAsync(46_000);
|
|
70
|
+
const result = await resultPromise;
|
|
71
|
+
expect(result).toEqual({ status: "timeout" });
|
|
72
|
+
});
|
|
73
|
+
it("rethrows non-already-running StartInstanceError", async () => {
|
|
74
|
+
const launcher = createMockLauncher({
|
|
75
|
+
startInstance: vi
|
|
76
|
+
.fn()
|
|
77
|
+
.mockRejectedValue(new StartInstanceError(42, "license expired")),
|
|
78
|
+
});
|
|
79
|
+
await expect(startInstanceWithRecovery(launcher, 42, 9222)).rejects.toThrow("license expired");
|
|
80
|
+
});
|
|
81
|
+
it("rethrows non-StartInstanceError", async () => {
|
|
82
|
+
const launcher = createMockLauncher({
|
|
83
|
+
startInstance: vi
|
|
84
|
+
.fn()
|
|
85
|
+
.mockRejectedValue(new Error("network error")),
|
|
86
|
+
});
|
|
87
|
+
await expect(startInstanceWithRecovery(launcher, 42, 9222)).rejects.toThrow("network error");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe("waitForInstancePort", () => {
|
|
91
|
+
beforeEach(() => {
|
|
92
|
+
vi.clearAllMocks();
|
|
93
|
+
vi.useFakeTimers({ shouldAdvanceTime: true });
|
|
94
|
+
});
|
|
95
|
+
afterEach(() => {
|
|
96
|
+
vi.useRealTimers();
|
|
97
|
+
vi.restoreAllMocks();
|
|
98
|
+
});
|
|
99
|
+
it("returns port immediately when available", async () => {
|
|
100
|
+
vi.mocked(discoverInstancePort).mockResolvedValue(55123);
|
|
101
|
+
const result = await waitForInstancePort(9222);
|
|
102
|
+
expect(result).toBe(55123);
|
|
103
|
+
});
|
|
104
|
+
it("polls until port becomes available", async () => {
|
|
105
|
+
vi.mocked(discoverInstancePort)
|
|
106
|
+
.mockResolvedValueOnce(null)
|
|
107
|
+
.mockResolvedValueOnce(null)
|
|
108
|
+
.mockResolvedValue(55123);
|
|
109
|
+
const result = await waitForInstancePort(9222);
|
|
110
|
+
expect(result).toBe(55123);
|
|
111
|
+
expect(discoverInstancePort).toHaveBeenCalledTimes(3);
|
|
112
|
+
});
|
|
113
|
+
it("returns null on timeout", async () => {
|
|
114
|
+
vi.mocked(discoverInstancePort).mockResolvedValue(null);
|
|
115
|
+
const resultPromise = waitForInstancePort(9222);
|
|
116
|
+
await vi.advanceTimersByTimeAsync(46_000);
|
|
117
|
+
const result = await resultPromise;
|
|
118
|
+
expect(result).toBeNull();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe("waitForInstanceShutdown", () => {
|
|
122
|
+
beforeEach(() => {
|
|
123
|
+
vi.clearAllMocks();
|
|
124
|
+
vi.useFakeTimers({ shouldAdvanceTime: true });
|
|
125
|
+
});
|
|
126
|
+
afterEach(() => {
|
|
127
|
+
vi.useRealTimers();
|
|
128
|
+
vi.restoreAllMocks();
|
|
129
|
+
});
|
|
130
|
+
it("resolves immediately when no instance port is found", async () => {
|
|
131
|
+
vi.mocked(discoverInstancePort).mockResolvedValue(null);
|
|
132
|
+
await waitForInstanceShutdown(9222);
|
|
133
|
+
expect(discoverInstancePort).toHaveBeenCalledTimes(1);
|
|
134
|
+
});
|
|
135
|
+
it("polls until port disappears", async () => {
|
|
136
|
+
vi.mocked(discoverInstancePort)
|
|
137
|
+
.mockResolvedValueOnce(55123)
|
|
138
|
+
.mockResolvedValueOnce(55123)
|
|
139
|
+
.mockResolvedValue(null);
|
|
140
|
+
await waitForInstanceShutdown(9222);
|
|
141
|
+
expect(discoverInstancePort).toHaveBeenCalledTimes(3);
|
|
142
|
+
});
|
|
143
|
+
it("resolves after timeout even if port persists", async () => {
|
|
144
|
+
vi.mocked(discoverInstancePort).mockResolvedValue(55123);
|
|
145
|
+
const promise = waitForInstanceShutdown(9222);
|
|
146
|
+
await vi.advanceTimersByTimeAsync(46_000);
|
|
147
|
+
await promise;
|
|
148
|
+
// Should have polled multiple times then given up
|
|
149
|
+
expect(vi.mocked(discoverInstancePort).mock.calls.length).toBeGreaterThan(1);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=instance-lifecycle.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-lifecycle.test.js","sourceRoot":"","sources":["../../src/services/instance-lifecycle.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controls a running LinkedHelper instance via CDP.
|
|
3
|
+
*
|
|
4
|
+
* An instance has two CDP targets on the same port:
|
|
5
|
+
* - **LinkedIn webview**: The Chromium page rendering linkedin.com
|
|
6
|
+
* - **Instance UI**: The Electron page hosting the LinkedHelper UI
|
|
7
|
+
*
|
|
8
|
+
* This service connects to both targets and provides methods for
|
|
9
|
+
* profile navigation and data extraction.
|
|
10
|
+
*/
|
|
11
|
+
export declare class InstanceService {
|
|
12
|
+
private readonly port;
|
|
13
|
+
private readonly host;
|
|
14
|
+
private linkedInClient;
|
|
15
|
+
private uiClient;
|
|
16
|
+
constructor(port: number, options?: {
|
|
17
|
+
host?: string;
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Connect to both instance CDP targets (LinkedIn page and UI).
|
|
21
|
+
*
|
|
22
|
+
* The instance may still be loading LinkedIn after startup, so this
|
|
23
|
+
* method polls until both targets appear or the timeout is reached.
|
|
24
|
+
*
|
|
25
|
+
* @throws {InstanceNotRunningError} if the expected targets are not found within the timeout.
|
|
26
|
+
*/
|
|
27
|
+
connect(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Disconnect from both targets.
|
|
30
|
+
*/
|
|
31
|
+
disconnect(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Navigate the LinkedIn webview to a profile URL.
|
|
34
|
+
*
|
|
35
|
+
* Enables the Page domain, navigates, and waits for the load event.
|
|
36
|
+
*/
|
|
37
|
+
navigateToProfile(url: string): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Trigger the SaveCurrentProfile action via the instance UI.
|
|
40
|
+
*
|
|
41
|
+
* This tells LinkedHelper to extract data from the currently
|
|
42
|
+
* displayed LinkedIn profile and save it to the database.
|
|
43
|
+
*/
|
|
44
|
+
triggerExtraction(): Promise<void>;
|
|
45
|
+
/** Whether both clients are currently connected. */
|
|
46
|
+
get isConnected(): boolean;
|
|
47
|
+
private ensureLinkedInClient;
|
|
48
|
+
private ensureUiClient;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=instance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/services/instance.ts"],"names":[],"mappings":"AAUA;;;;;;;;;GASG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAA0B;gBAE9B,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;IAKrD;;;;;;;OAOG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAyC9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAOlB;;;;OAIG;IACG,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnD;;;;;OAKG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAaxC,oDAAoD;IACpD,IAAI,WAAW,IAAI,OAAO,CAOzB;IAED,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,cAAc;CAMvB"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { CDPClient, discoverTargets } from "../cdp/index.js";
|
|
2
|
+
import { InstanceNotRunningError, ServiceError } from "./errors.js";
|
|
3
|
+
/** Maximum time to wait for both CDP targets to appear (ms). */
|
|
4
|
+
const CONNECT_TIMEOUT = 30_000;
|
|
5
|
+
/** Interval between target discovery polls (ms). */
|
|
6
|
+
const CONNECT_POLL_INTERVAL = 1_000;
|
|
7
|
+
/**
|
|
8
|
+
* Controls a running LinkedHelper instance via CDP.
|
|
9
|
+
*
|
|
10
|
+
* An instance has two CDP targets on the same port:
|
|
11
|
+
* - **LinkedIn webview**: The Chromium page rendering linkedin.com
|
|
12
|
+
* - **Instance UI**: The Electron page hosting the LinkedHelper UI
|
|
13
|
+
*
|
|
14
|
+
* This service connects to both targets and provides methods for
|
|
15
|
+
* profile navigation and data extraction.
|
|
16
|
+
*/
|
|
17
|
+
export class InstanceService {
|
|
18
|
+
port;
|
|
19
|
+
host;
|
|
20
|
+
linkedInClient = null;
|
|
21
|
+
uiClient = null;
|
|
22
|
+
constructor(port, options) {
|
|
23
|
+
this.port = port;
|
|
24
|
+
this.host = options?.host ?? "127.0.0.1";
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Connect to both instance CDP targets (LinkedIn page and UI).
|
|
28
|
+
*
|
|
29
|
+
* The instance may still be loading LinkedIn after startup, so this
|
|
30
|
+
* method polls until both targets appear or the timeout is reached.
|
|
31
|
+
*
|
|
32
|
+
* @throws {InstanceNotRunningError} if the expected targets are not found within the timeout.
|
|
33
|
+
*/
|
|
34
|
+
async connect() {
|
|
35
|
+
const deadline = Date.now() + CONNECT_TIMEOUT;
|
|
36
|
+
let targets = [];
|
|
37
|
+
let linkedInTarget;
|
|
38
|
+
let uiTarget;
|
|
39
|
+
while (Date.now() < deadline) {
|
|
40
|
+
targets = await discoverTargets(this.port, this.host);
|
|
41
|
+
linkedInTarget = targets.find(isLinkedInTarget);
|
|
42
|
+
uiTarget = targets.find(isUiTarget);
|
|
43
|
+
if (linkedInTarget && uiTarget) {
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
await new Promise((resolve) => setTimeout(resolve, CONNECT_POLL_INTERVAL));
|
|
47
|
+
}
|
|
48
|
+
if (!linkedInTarget) {
|
|
49
|
+
throw new InstanceNotRunningError(`LinkedIn webview target not found among ${String(targets.length)} CDP target(s) on port ${String(this.port)}`);
|
|
50
|
+
}
|
|
51
|
+
if (!uiTarget) {
|
|
52
|
+
throw new InstanceNotRunningError(`Instance UI target not found among ${String(targets.length)} CDP target(s) on port ${String(this.port)}`);
|
|
53
|
+
}
|
|
54
|
+
const liClient = new CDPClient(this.port, { host: this.host });
|
|
55
|
+
await liClient.connect(linkedInTarget.id);
|
|
56
|
+
const ui = new CDPClient(this.port, { host: this.host });
|
|
57
|
+
await ui.connect(uiTarget.id);
|
|
58
|
+
this.linkedInClient = liClient;
|
|
59
|
+
this.uiClient = ui;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Disconnect from both targets.
|
|
63
|
+
*/
|
|
64
|
+
disconnect() {
|
|
65
|
+
this.linkedInClient?.disconnect();
|
|
66
|
+
this.linkedInClient = null;
|
|
67
|
+
this.uiClient?.disconnect();
|
|
68
|
+
this.uiClient = null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Navigate the LinkedIn webview to a profile URL.
|
|
72
|
+
*
|
|
73
|
+
* Enables the Page domain, navigates, and waits for the load event.
|
|
74
|
+
*/
|
|
75
|
+
async navigateToProfile(url) {
|
|
76
|
+
const client = this.ensureLinkedInClient();
|
|
77
|
+
await client.send("Page.enable");
|
|
78
|
+
await client.navigate(url);
|
|
79
|
+
await client.waitForEvent("Page.loadEventFired");
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Trigger the SaveCurrentProfile action via the instance UI.
|
|
83
|
+
*
|
|
84
|
+
* This tells LinkedHelper to extract data from the currently
|
|
85
|
+
* displayed LinkedIn profile and save it to the database.
|
|
86
|
+
*/
|
|
87
|
+
async triggerExtraction() {
|
|
88
|
+
const client = this.ensureUiClient();
|
|
89
|
+
await client.evaluate(`(async () => {
|
|
90
|
+
const mws = window.mainWindowService;
|
|
91
|
+
if (!mws) throw new Error('mainWindowService not found on window');
|
|
92
|
+
return await mws.call('executeSingleAction', 'SaveCurrentProfile', {});
|
|
93
|
+
})()`, true);
|
|
94
|
+
}
|
|
95
|
+
/** Whether both clients are currently connected. */
|
|
96
|
+
get isConnected() {
|
|
97
|
+
return (this.linkedInClient !== null &&
|
|
98
|
+
this.linkedInClient.isConnected &&
|
|
99
|
+
this.uiClient !== null &&
|
|
100
|
+
this.uiClient.isConnected);
|
|
101
|
+
}
|
|
102
|
+
ensureLinkedInClient() {
|
|
103
|
+
if (!this.linkedInClient) {
|
|
104
|
+
throw new ServiceError("InstanceService is not connected (LinkedIn target)");
|
|
105
|
+
}
|
|
106
|
+
return this.linkedInClient;
|
|
107
|
+
}
|
|
108
|
+
ensureUiClient() {
|
|
109
|
+
if (!this.uiClient) {
|
|
110
|
+
throw new ServiceError("InstanceService is not connected (UI target)");
|
|
111
|
+
}
|
|
112
|
+
return this.uiClient;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function isLinkedInTarget(target) {
|
|
116
|
+
return target.type === "page" && target.url.includes("linkedin.com");
|
|
117
|
+
}
|
|
118
|
+
function isUiTarget(target) {
|
|
119
|
+
return target.type === "page" && target.url.includes("index.html");
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=instance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.js","sourceRoot":"","sources":["../../src/services/instance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.test.d.ts","sourceRoot":"","sources":["../../src/services/instance.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { ServiceError } from "./errors.js";
|
|
3
|
+
import { InstanceService } from "./instance.js";
|
|
4
|
+
/** All created client mocks, in creation order. */
|
|
5
|
+
let clientInstances = [];
|
|
6
|
+
/** Lookup by target ID after connect() is called. */
|
|
7
|
+
let clientsByTargetId = new Map();
|
|
8
|
+
vi.mock("../cdp/index.js", () => ({
|
|
9
|
+
CDPClient: vi.fn().mockImplementation(function () {
|
|
10
|
+
const mocks = {
|
|
11
|
+
connect: vi.fn().mockImplementation(async (targetId) => {
|
|
12
|
+
if (targetId) {
|
|
13
|
+
clientsByTargetId.set(targetId, mocks);
|
|
14
|
+
}
|
|
15
|
+
}),
|
|
16
|
+
disconnect: vi.fn(),
|
|
17
|
+
send: vi.fn().mockResolvedValue(undefined),
|
|
18
|
+
navigate: vi.fn().mockResolvedValue({ frameId: "F1" }),
|
|
19
|
+
evaluate: vi.fn().mockResolvedValue(undefined),
|
|
20
|
+
waitForEvent: vi.fn().mockResolvedValue(undefined),
|
|
21
|
+
isConnected: vi.fn().mockReturnValue(true),
|
|
22
|
+
};
|
|
23
|
+
clientInstances.push(mocks);
|
|
24
|
+
this.connect = mocks.connect;
|
|
25
|
+
this.disconnect = mocks.disconnect;
|
|
26
|
+
this.send = mocks.send;
|
|
27
|
+
this.navigate = mocks.navigate;
|
|
28
|
+
this.evaluate = mocks.evaluate;
|
|
29
|
+
this.waitForEvent = mocks.waitForEvent;
|
|
30
|
+
Object.defineProperty(this, "isConnected", {
|
|
31
|
+
get: mocks.isConnected,
|
|
32
|
+
});
|
|
33
|
+
}),
|
|
34
|
+
discoverTargets: vi.fn(),
|
|
35
|
+
}));
|
|
36
|
+
import { discoverTargets } from "../cdp/index.js";
|
|
37
|
+
const mockedDiscoverTargets = vi.mocked(discoverTargets);
|
|
38
|
+
function makeTarget(overrides) {
|
|
39
|
+
return {
|
|
40
|
+
description: "",
|
|
41
|
+
devtoolsFrontendUrl: "",
|
|
42
|
+
id: "DEFAULT",
|
|
43
|
+
title: "Test",
|
|
44
|
+
type: "page",
|
|
45
|
+
url: "about:blank",
|
|
46
|
+
webSocketDebuggerUrl: "ws://127.0.0.1:9223/devtools/page/DEFAULT",
|
|
47
|
+
...overrides,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const LINKEDIN_TARGET = makeTarget({
|
|
51
|
+
id: "LI1",
|
|
52
|
+
url: "https://www.linkedin.com/feed/",
|
|
53
|
+
title: "LinkedIn Feed",
|
|
54
|
+
});
|
|
55
|
+
const UI_TARGET = makeTarget({
|
|
56
|
+
id: "UI1",
|
|
57
|
+
url: "chrome-extension://abc/index.html#/",
|
|
58
|
+
title: "LinkedHelper",
|
|
59
|
+
});
|
|
60
|
+
function getClientMocks(targetId) {
|
|
61
|
+
const mocks = clientsByTargetId.get(targetId);
|
|
62
|
+
if (!mocks) {
|
|
63
|
+
throw new Error(`No CDPClient mock found for target ${targetId}`);
|
|
64
|
+
}
|
|
65
|
+
return mocks;
|
|
66
|
+
}
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
clientInstances = [];
|
|
69
|
+
clientsByTargetId = new Map();
|
|
70
|
+
});
|
|
71
|
+
afterEach(() => {
|
|
72
|
+
vi.useRealTimers();
|
|
73
|
+
vi.restoreAllMocks();
|
|
74
|
+
});
|
|
75
|
+
describe("InstanceService", () => {
|
|
76
|
+
let service;
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
service = new InstanceService(9223);
|
|
79
|
+
});
|
|
80
|
+
describe("connect", () => {
|
|
81
|
+
it("discovers targets and connects to both on first poll", async () => {
|
|
82
|
+
mockedDiscoverTargets.mockResolvedValue([LINKEDIN_TARGET, UI_TARGET]);
|
|
83
|
+
await service.connect();
|
|
84
|
+
expect(service.isConnected).toBe(true);
|
|
85
|
+
expect(clientInstances).toHaveLength(2);
|
|
86
|
+
expect(clientsByTargetId.has("LI1")).toBe(true);
|
|
87
|
+
expect(clientsByTargetId.has("UI1")).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
it("polls until both targets appear", async () => {
|
|
90
|
+
vi.useFakeTimers();
|
|
91
|
+
mockedDiscoverTargets
|
|
92
|
+
.mockResolvedValueOnce([UI_TARGET])
|
|
93
|
+
.mockResolvedValueOnce([UI_TARGET])
|
|
94
|
+
.mockResolvedValue([LINKEDIN_TARGET, UI_TARGET]);
|
|
95
|
+
const connectPromise = service.connect();
|
|
96
|
+
await vi.advanceTimersByTimeAsync(5_000);
|
|
97
|
+
await connectPromise;
|
|
98
|
+
expect(service.isConnected).toBe(true);
|
|
99
|
+
expect(mockedDiscoverTargets.mock.calls.length).toBeGreaterThanOrEqual(3);
|
|
100
|
+
vi.useRealTimers();
|
|
101
|
+
});
|
|
102
|
+
it("throws InstanceNotRunningError when no LinkedIn target", async () => {
|
|
103
|
+
vi.useFakeTimers();
|
|
104
|
+
mockedDiscoverTargets.mockResolvedValue([UI_TARGET]);
|
|
105
|
+
const promise = service.connect();
|
|
106
|
+
const assertion = expect(promise).rejects.toThrow(/LinkedIn webview target not found/);
|
|
107
|
+
await vi.advanceTimersByTimeAsync(31_000);
|
|
108
|
+
await assertion;
|
|
109
|
+
vi.useRealTimers();
|
|
110
|
+
});
|
|
111
|
+
it("throws InstanceNotRunningError when no UI target", async () => {
|
|
112
|
+
vi.useFakeTimers();
|
|
113
|
+
mockedDiscoverTargets.mockResolvedValue([LINKEDIN_TARGET]);
|
|
114
|
+
const promise = service.connect();
|
|
115
|
+
const assertion = expect(promise).rejects.toThrow(/Instance UI target not found/);
|
|
116
|
+
await vi.advanceTimersByTimeAsync(31_000);
|
|
117
|
+
await assertion;
|
|
118
|
+
vi.useRealTimers();
|
|
119
|
+
});
|
|
120
|
+
it("throws InstanceNotRunningError when no targets at all", async () => {
|
|
121
|
+
vi.useFakeTimers();
|
|
122
|
+
mockedDiscoverTargets.mockResolvedValue([]);
|
|
123
|
+
const promise = service.connect();
|
|
124
|
+
const assertion = expect(promise).rejects.toThrow(/LinkedIn webview target not found.*0 CDP target/);
|
|
125
|
+
await vi.advanceTimersByTimeAsync(31_000);
|
|
126
|
+
await assertion;
|
|
127
|
+
vi.useRealTimers();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
describe("disconnect", () => {
|
|
131
|
+
it("disconnects both clients", async () => {
|
|
132
|
+
mockedDiscoverTargets.mockResolvedValue([LINKEDIN_TARGET, UI_TARGET]);
|
|
133
|
+
await service.connect();
|
|
134
|
+
service.disconnect();
|
|
135
|
+
const liClient = getClientMocks("LI1");
|
|
136
|
+
const uiClient = getClientMocks("UI1");
|
|
137
|
+
expect(liClient.disconnect).toHaveBeenCalledTimes(1);
|
|
138
|
+
expect(uiClient.disconnect).toHaveBeenCalledTimes(1);
|
|
139
|
+
});
|
|
140
|
+
it("does not throw when not connected", () => {
|
|
141
|
+
expect(() => service.disconnect()).not.toThrow();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
describe("navigateToProfile", () => {
|
|
145
|
+
it("calls Page.enable, navigate, and waitForEvent on the LinkedIn client", async () => {
|
|
146
|
+
mockedDiscoverTargets.mockResolvedValue([LINKEDIN_TARGET, UI_TARGET]);
|
|
147
|
+
await service.connect();
|
|
148
|
+
await service.navigateToProfile("https://www.linkedin.com/in/test-user");
|
|
149
|
+
const liClient = getClientMocks("LI1");
|
|
150
|
+
const uiClient = getClientMocks("UI1");
|
|
151
|
+
// LinkedIn client should have received navigation calls
|
|
152
|
+
expect(liClient.send).toHaveBeenCalledWith("Page.enable");
|
|
153
|
+
expect(liClient.navigate).toHaveBeenCalledWith("https://www.linkedin.com/in/test-user");
|
|
154
|
+
expect(liClient.waitForEvent).toHaveBeenCalledWith("Page.loadEventFired");
|
|
155
|
+
// UI client should NOT have received any navigation calls
|
|
156
|
+
expect(uiClient.send).not.toHaveBeenCalled();
|
|
157
|
+
expect(uiClient.navigate).not.toHaveBeenCalled();
|
|
158
|
+
expect(uiClient.waitForEvent).not.toHaveBeenCalled();
|
|
159
|
+
});
|
|
160
|
+
it("throws ServiceError when not connected", async () => {
|
|
161
|
+
await expect(service.navigateToProfile("https://www.linkedin.com/in/test")).rejects.toThrow(ServiceError);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
describe("triggerExtraction", () => {
|
|
165
|
+
it("evaluates SaveCurrentProfile on the UI client only", async () => {
|
|
166
|
+
mockedDiscoverTargets.mockResolvedValue([LINKEDIN_TARGET, UI_TARGET]);
|
|
167
|
+
await service.connect();
|
|
168
|
+
await service.triggerExtraction();
|
|
169
|
+
const liClient = getClientMocks("LI1");
|
|
170
|
+
const uiClient = getClientMocks("UI1");
|
|
171
|
+
// UI client should have received the extraction call
|
|
172
|
+
expect(uiClient.evaluate).toHaveBeenCalledWith(expect.stringContaining("SaveCurrentProfile"), true);
|
|
173
|
+
// LinkedIn client should NOT have received any evaluate call
|
|
174
|
+
expect(liClient.evaluate).not.toHaveBeenCalled();
|
|
175
|
+
});
|
|
176
|
+
it("throws ServiceError when not connected", async () => {
|
|
177
|
+
await expect(service.triggerExtraction()).rejects.toThrow(ServiceError);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
//# sourceMappingURL=instance.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.test.js","sourceRoot":"","sources":["../../src/services/instance.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Account, InstanceStatus } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Controls the LinkedHelper launcher process via CDP.
|
|
4
|
+
*
|
|
5
|
+
* The launcher is the main Electron window that manages LinkedIn
|
|
6
|
+
* account instances. This service connects to it and provides
|
|
7
|
+
* methods to start/stop instances and query accounts.
|
|
8
|
+
*/
|
|
9
|
+
export declare class LauncherService {
|
|
10
|
+
private readonly port;
|
|
11
|
+
private readonly host;
|
|
12
|
+
private client;
|
|
13
|
+
constructor(port?: number, options?: {
|
|
14
|
+
host?: string;
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* Connect to the LinkedHelper launcher via CDP.
|
|
18
|
+
*
|
|
19
|
+
* @throws {LinkedHelperNotRunningError} if the launcher is not reachable.
|
|
20
|
+
*/
|
|
21
|
+
connect(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Disconnect from the launcher.
|
|
24
|
+
*/
|
|
25
|
+
disconnect(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Start a LinkedHelper instance for the given account.
|
|
28
|
+
*
|
|
29
|
+
* @throws {StartInstanceError} if the instance fails to start.
|
|
30
|
+
*/
|
|
31
|
+
startInstance(accountId: number): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Stop a running LinkedHelper instance.
|
|
34
|
+
*/
|
|
35
|
+
stopInstance(accountId: number): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Query the status of an instance for the given account.
|
|
38
|
+
*/
|
|
39
|
+
getInstanceStatus(accountId: number): Promise<InstanceStatus>;
|
|
40
|
+
/**
|
|
41
|
+
* List all accounts configured in the LinkedHelper Electron store.
|
|
42
|
+
*
|
|
43
|
+
* Accounts are discovered from the `linkedInPasswords` store key whose
|
|
44
|
+
* entries use the format `userId:li:accountId`.
|
|
45
|
+
*/
|
|
46
|
+
listAccounts(): Promise<Account[]>;
|
|
47
|
+
/** Whether the service is currently connected to the launcher. */
|
|
48
|
+
get isConnected(): boolean;
|
|
49
|
+
private ensureConnected;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=launcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../../src/services/launcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EAEf,MAAM,mBAAmB,CAAC;AAU3B;;;;;;GAMG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,MAAM,CAA0B;gBAGtC,IAAI,GAAE,MAA8B,EACpC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;IAM7B;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAa9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkCrD;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAapD;;OAEG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAmBnE;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IA6BxC,kEAAkE;IAClE,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,OAAO,CAAC,eAAe;CAMxB"}
|