@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.
Files changed (218) hide show
  1. package/LICENSE +661 -0
  2. package/dist/cdp/client.d.ts +100 -0
  3. package/dist/cdp/client.d.ts.map +1 -0
  4. package/dist/cdp/client.integration.test.d.ts +2 -0
  5. package/dist/cdp/client.integration.test.d.ts.map +1 -0
  6. package/dist/cdp/client.integration.test.js +70 -0
  7. package/dist/cdp/client.integration.test.js.map +1 -0
  8. package/dist/cdp/client.js +286 -0
  9. package/dist/cdp/client.js.map +1 -0
  10. package/dist/cdp/client.test.d.ts +2 -0
  11. package/dist/cdp/client.test.d.ts.map +1 -0
  12. package/dist/cdp/client.test.js +269 -0
  13. package/dist/cdp/client.test.js.map +1 -0
  14. package/dist/cdp/discovery.d.ts +14 -0
  15. package/dist/cdp/discovery.d.ts.map +1 -0
  16. package/dist/cdp/discovery.integration.test.d.ts +2 -0
  17. package/dist/cdp/discovery.integration.test.d.ts.map +1 -0
  18. package/dist/cdp/discovery.integration.test.js +25 -0
  19. package/dist/cdp/discovery.integration.test.js.map +1 -0
  20. package/dist/cdp/discovery.js +31 -0
  21. package/dist/cdp/discovery.js.map +1 -0
  22. package/dist/cdp/discovery.test.d.ts +2 -0
  23. package/dist/cdp/discovery.test.d.ts.map +1 -0
  24. package/dist/cdp/discovery.test.js +54 -0
  25. package/dist/cdp/discovery.test.js.map +1 -0
  26. package/dist/cdp/errors.d.ts +28 -0
  27. package/dist/cdp/errors.d.ts.map +1 -0
  28. package/dist/cdp/errors.js +40 -0
  29. package/dist/cdp/errors.js.map +1 -0
  30. package/dist/cdp/errors.test.d.ts +2 -0
  31. package/dist/cdp/errors.test.d.ts.map +1 -0
  32. package/dist/cdp/errors.test.js +35 -0
  33. package/dist/cdp/errors.test.js.map +1 -0
  34. package/dist/cdp/index.d.ts +5 -0
  35. package/dist/cdp/index.d.ts.map +1 -0
  36. package/dist/cdp/index.js +5 -0
  37. package/dist/cdp/index.js.map +1 -0
  38. package/dist/cdp/instance-discovery.d.ts +30 -0
  39. package/dist/cdp/instance-discovery.d.ts.map +1 -0
  40. package/dist/cdp/instance-discovery.integration.test.d.ts +2 -0
  41. package/dist/cdp/instance-discovery.integration.test.d.ts.map +1 -0
  42. package/dist/cdp/instance-discovery.integration.test.js +34 -0
  43. package/dist/cdp/instance-discovery.integration.test.js.map +1 -0
  44. package/dist/cdp/instance-discovery.js +130 -0
  45. package/dist/cdp/instance-discovery.js.map +1 -0
  46. package/dist/cdp/instance-discovery.test.d.ts +2 -0
  47. package/dist/cdp/instance-discovery.test.d.ts.map +1 -0
  48. package/dist/cdp/instance-discovery.test.js +110 -0
  49. package/dist/cdp/instance-discovery.test.js.map +1 -0
  50. package/dist/cdp/testing/launch-chromium.d.ts +24 -0
  51. package/dist/cdp/testing/launch-chromium.d.ts.map +1 -0
  52. package/dist/cdp/testing/launch-chromium.js +90 -0
  53. package/dist/cdp/testing/launch-chromium.js.map +1 -0
  54. package/dist/db/client.d.ts +13 -0
  55. package/dist/db/client.d.ts.map +1 -0
  56. package/dist/db/client.integration.test.d.ts +2 -0
  57. package/dist/db/client.integration.test.d.ts.map +1 -0
  58. package/dist/db/client.integration.test.js +59 -0
  59. package/dist/db/client.integration.test.js.map +1 -0
  60. package/dist/db/client.js +17 -0
  61. package/dist/db/client.js.map +1 -0
  62. package/dist/db/client.test.d.ts +2 -0
  63. package/dist/db/client.test.d.ts.map +1 -0
  64. package/dist/db/client.test.js +46 -0
  65. package/dist/db/client.test.js.map +1 -0
  66. package/dist/db/discovery.d.ts +14 -0
  67. package/dist/db/discovery.d.ts.map +1 -0
  68. package/dist/db/discovery.integration.test.d.ts +2 -0
  69. package/dist/db/discovery.integration.test.d.ts.map +1 -0
  70. package/dist/db/discovery.integration.test.js +99 -0
  71. package/dist/db/discovery.integration.test.js.map +1 -0
  72. package/dist/db/discovery.js +74 -0
  73. package/dist/db/discovery.js.map +1 -0
  74. package/dist/db/discovery.test.d.ts +2 -0
  75. package/dist/db/discovery.test.d.ts.map +1 -0
  76. package/dist/db/discovery.test.js +123 -0
  77. package/dist/db/discovery.test.js.map +1 -0
  78. package/dist/db/errors.d.ts +21 -0
  79. package/dist/db/errors.d.ts.map +1 -0
  80. package/dist/db/errors.js +33 -0
  81. package/dist/db/errors.js.map +1 -0
  82. package/dist/db/errors.test.d.ts +2 -0
  83. package/dist/db/errors.test.d.ts.map +1 -0
  84. package/dist/db/errors.test.js +32 -0
  85. package/dist/db/errors.test.js.map +1 -0
  86. package/dist/db/index.d.ts +5 -0
  87. package/dist/db/index.d.ts.map +1 -0
  88. package/dist/db/index.js +5 -0
  89. package/dist/db/index.js.map +1 -0
  90. package/dist/db/repositories/index.d.ts +2 -0
  91. package/dist/db/repositories/index.d.ts.map +1 -0
  92. package/dist/db/repositories/index.js +2 -0
  93. package/dist/db/repositories/index.js.map +1 -0
  94. package/dist/db/repositories/profile.d.ts +32 -0
  95. package/dist/db/repositories/profile.d.ts.map +1 -0
  96. package/dist/db/repositories/profile.integration.test.d.ts +2 -0
  97. package/dist/db/repositories/profile.integration.test.d.ts.map +1 -0
  98. package/dist/db/repositories/profile.integration.test.js +119 -0
  99. package/dist/db/repositories/profile.integration.test.js.map +1 -0
  100. package/dist/db/repositories/profile.js +126 -0
  101. package/dist/db/repositories/profile.js.map +1 -0
  102. package/dist/db/repositories/profile.test.d.ts +2 -0
  103. package/dist/db/repositories/profile.test.d.ts.map +1 -0
  104. package/dist/db/repositories/profile.test.js +126 -0
  105. package/dist/db/repositories/profile.test.js.map +1 -0
  106. package/dist/db/testing/create-fixture.d.ts +8 -0
  107. package/dist/db/testing/create-fixture.d.ts.map +1 -0
  108. package/dist/db/testing/create-fixture.js +286 -0
  109. package/dist/db/testing/create-fixture.js.map +1 -0
  110. package/dist/db/testing/open-fixture.d.ts +14 -0
  111. package/dist/db/testing/open-fixture.d.ts.map +1 -0
  112. package/dist/db/testing/open-fixture.js +21 -0
  113. package/dist/db/testing/open-fixture.js.map +1 -0
  114. package/dist/index.d.ts +5 -1
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +7 -1
  117. package/dist/index.js.map +1 -1
  118. package/dist/services/app.d.ts +62 -0
  119. package/dist/services/app.d.ts.map +1 -0
  120. package/dist/services/app.js +198 -0
  121. package/dist/services/app.js.map +1 -0
  122. package/dist/services/app.test.d.ts +2 -0
  123. package/dist/services/app.test.d.ts.map +1 -0
  124. package/dist/services/app.test.js +265 -0
  125. package/dist/services/app.test.js.map +1 -0
  126. package/dist/services/errors.d.ts +45 -0
  127. package/dist/services/errors.d.ts.map +1 -0
  128. package/dist/services/errors.js +66 -0
  129. package/dist/services/errors.js.map +1 -0
  130. package/dist/services/errors.test.d.ts +2 -0
  131. package/dist/services/errors.test.d.ts.map +1 -0
  132. package/dist/services/errors.test.js +71 -0
  133. package/dist/services/errors.test.js.map +1 -0
  134. package/dist/services/index.d.ts +8 -0
  135. package/dist/services/index.d.ts.map +1 -0
  136. package/dist/services/index.js +8 -0
  137. package/dist/services/index.js.map +1 -0
  138. package/dist/services/instance-lifecycle.d.ts +38 -0
  139. package/dist/services/instance-lifecycle.d.ts.map +1 -0
  140. package/dist/services/instance-lifecycle.js +87 -0
  141. package/dist/services/instance-lifecycle.js.map +1 -0
  142. package/dist/services/instance-lifecycle.test.d.ts +2 -0
  143. package/dist/services/instance-lifecycle.test.d.ts.map +1 -0
  144. package/dist/services/instance-lifecycle.test.js +152 -0
  145. package/dist/services/instance-lifecycle.test.js.map +1 -0
  146. package/dist/services/instance.d.ts +50 -0
  147. package/dist/services/instance.d.ts.map +1 -0
  148. package/dist/services/instance.js +121 -0
  149. package/dist/services/instance.js.map +1 -0
  150. package/dist/services/instance.test.d.ts +2 -0
  151. package/dist/services/instance.test.d.ts.map +1 -0
  152. package/dist/services/instance.test.js +181 -0
  153. package/dist/services/instance.test.js.map +1 -0
  154. package/dist/services/launcher.d.ts +51 -0
  155. package/dist/services/launcher.d.ts.map +1 -0
  156. package/dist/services/launcher.js +147 -0
  157. package/dist/services/launcher.js.map +1 -0
  158. package/dist/services/launcher.test.d.ts +2 -0
  159. package/dist/services/launcher.test.d.ts.map +1 -0
  160. package/dist/services/launcher.test.js +126 -0
  161. package/dist/services/launcher.test.js.map +1 -0
  162. package/dist/services/profile.d.ts +44 -0
  163. package/dist/services/profile.d.ts.map +1 -0
  164. package/dist/services/profile.js +83 -0
  165. package/dist/services/profile.js.map +1 -0
  166. package/dist/services/profile.test.d.ts +2 -0
  167. package/dist/services/profile.test.d.ts.map +1 -0
  168. package/dist/services/profile.test.js +145 -0
  169. package/dist/services/profile.test.js.map +1 -0
  170. package/dist/services/status.d.ts +33 -0
  171. package/dist/services/status.d.ts.map +1 -0
  172. package/dist/services/status.js +76 -0
  173. package/dist/services/status.js.map +1 -0
  174. package/dist/services/status.test.d.ts +2 -0
  175. package/dist/services/status.test.d.ts.map +1 -0
  176. package/dist/services/status.test.js +207 -0
  177. package/dist/services/status.test.js.map +1 -0
  178. package/dist/testing/e2e-helpers.d.ts +41 -0
  179. package/dist/testing/e2e-helpers.d.ts.map +1 -0
  180. package/dist/testing/e2e-helpers.js +111 -0
  181. package/dist/testing/e2e-helpers.js.map +1 -0
  182. package/dist/types/account.d.ts +13 -0
  183. package/dist/types/account.d.ts.map +1 -0
  184. package/dist/types/account.js +2 -0
  185. package/dist/types/account.js.map +1 -0
  186. package/dist/types/account.test.d.ts +2 -0
  187. package/dist/types/account.test.d.ts.map +1 -0
  188. package/dist/types/account.test.js +24 -0
  189. package/dist/types/account.test.js.map +1 -0
  190. package/dist/types/cdp.d.ts +18 -0
  191. package/dist/types/cdp.d.ts.map +1 -0
  192. package/dist/types/cdp.js +2 -0
  193. package/dist/types/cdp.js.map +1 -0
  194. package/dist/types/cdp.test.d.ts +2 -0
  195. package/dist/types/cdp.test.d.ts.map +1 -0
  196. package/dist/types/cdp.test.js +28 -0
  197. package/dist/types/cdp.test.js.map +1 -0
  198. package/dist/types/index.d.ts +4 -0
  199. package/dist/types/index.d.ts.map +1 -0
  200. package/dist/types/index.js +2 -0
  201. package/dist/types/index.js.map +1 -0
  202. package/dist/types/instance.d.ts +36 -0
  203. package/dist/types/instance.d.ts.map +1 -0
  204. package/dist/types/instance.js +8 -0
  205. package/dist/types/instance.js.map +1 -0
  206. package/dist/types/instance.test.d.ts +2 -0
  207. package/dist/types/instance.test.d.ts.map +1 -0
  208. package/dist/types/instance.test.js +57 -0
  209. package/dist/types/instance.test.js.map +1 -0
  210. package/dist/types/profile.d.ts +50 -0
  211. package/dist/types/profile.d.ts.map +1 -0
  212. package/dist/types/profile.js +8 -0
  213. package/dist/types/profile.js.map +1 -0
  214. package/dist/types/profile.test.d.ts +2 -0
  215. package/dist/types/profile.test.d.ts.map +1 -0
  216. package/dist/types/profile.test.js +103 -0
  217. package/dist/types/profile.test.js.map +1 -0
  218. package/package.json +20 -8
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Generates a test fixture SQLite database with the real LinkedHelper
3
+ * schema populated with synthetic (non-personal) mock data.
4
+ *
5
+ * Run: npx tsx src/db/testing/create-fixture.ts
6
+ */
7
+ import { writeFileSync } from "node:fs";
8
+ import { dirname, join } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import Database from "better-sqlite3";
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const FIXTURE_PATH = join(__dirname, "fixture.db");
13
+ const db = new Database("");
14
+ // ── Schema (matches real LinkedHelper DDL) ──────────────────────────
15
+ db.exec(`
16
+ CREATE TABLE disabled_triggers(
17
+ id INTEGER PRIMARY KEY,
18
+ trigger_name TEXT,
19
+ UNIQUE (trigger_name)
20
+ );
21
+
22
+ CREATE TABLE people(
23
+ id INTEGER PRIMARY KEY,
24
+ original_id INTEGER,
25
+ created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
26
+ updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW'))
27
+ );
28
+ CREATE INDEX people_original_id_idx ON people(original_id);
29
+
30
+ CREATE TABLE person_mini_profile(
31
+ id INTEGER PRIMARY KEY,
32
+ person_id INTEGER NOT NULL,
33
+ first_name TEXT NOT NULL,
34
+ first_name_uppercase TEXT,
35
+ last_name TEXT,
36
+ last_name_uppercase TEXT,
37
+ headline TEXT,
38
+ headline_uppercase TEXT,
39
+ avatar TEXT,
40
+ first_mutual_full_name TEXT,
41
+ second_mutual_full_name TEXT,
42
+ created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
43
+ updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
44
+ UNIQUE (person_id),
45
+ FOREIGN KEY(person_id) REFERENCES people(id)
46
+ );
47
+
48
+ CREATE TABLE person_external_ids(
49
+ id INTEGER PRIMARY KEY,
50
+ person_id INTEGER NOT NULL,
51
+ external_id TEXT NOT NULL,
52
+ external_id_uppercase TEXT NOT NULL,
53
+ type_group TEXT NOT NULL CHECK(type_group IN ('member', 'public', 'hash', 'avatar')),
54
+ is_member_id INTEGER,
55
+ created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
56
+ updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
57
+ UNIQUE(external_id, type_group),
58
+ FOREIGN KEY(person_id) REFERENCES people(id)
59
+ );
60
+ CREATE INDEX person_external_ids_person_idx ON person_external_ids(person_id);
61
+
62
+ CREATE TABLE person_current_position(
63
+ id INTEGER PRIMARY KEY,
64
+ person_id INTEGER NOT NULL,
65
+ company TEXT,
66
+ company_uppercase TEXT,
67
+ position TEXT,
68
+ position_uppercase TEXT,
69
+ created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
70
+ updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
71
+ UNIQUE(person_id),
72
+ FOREIGN KEY(person_id) REFERENCES people(id)
73
+ );
74
+
75
+ CREATE TABLE person_positions(
76
+ id INTEGER PRIMARY KEY,
77
+ person_id INTEGER NOT NULL,
78
+ title TEXT NOT NULL,
79
+ company_name TEXT NOT NULL,
80
+ company_id TEXT,
81
+ start DATETIME,
82
+ start_year INTEGER,
83
+ start_month INTEGER,
84
+ "end" DATETIME,
85
+ end_year INTEGER,
86
+ end_month INTEGER,
87
+ location_name TEXT,
88
+ description TEXT,
89
+ is_default INTEGER,
90
+ created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
91
+ updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
92
+ sent_at_to_pas DATETIME,
93
+ actual_at DATETIME NOT NULL,
94
+ UNIQUE(person_id, is_default),
95
+ FOREIGN KEY(person_id) REFERENCES people(id),
96
+ CHECK(is_default IS NULL OR (is_default IS NOT NULL AND "end" IS NULL))
97
+ );
98
+
99
+ CREATE TABLE person_education(
100
+ id INTEGER PRIMARY KEY,
101
+ person_id INTEGER NOT NULL,
102
+ school_name TEXT NOT NULL,
103
+ degree_name TEXT,
104
+ field_of_study TEXT,
105
+ description TEXT,
106
+ start_year INTEGER,
107
+ start_month INTEGER,
108
+ end_year INTEGER,
109
+ end_month INTEGER,
110
+ created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
111
+ updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
112
+ sent_at_to_pas DATETIME,
113
+ actual_at DATETIME NOT NULL,
114
+ FOREIGN KEY(person_id) REFERENCES people(id)
115
+ );
116
+ CREATE INDEX person_education_person_idx ON person_education(person_id);
117
+
118
+ CREATE TABLE skills(
119
+ id INTEGER PRIMARY KEY,
120
+ name TEXT NOT NULL CHECK (length(name) > 0),
121
+ created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
122
+ updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
123
+ UNIQUE (name)
124
+ );
125
+
126
+ CREATE TABLE person_skill(
127
+ id INTEGER PRIMARY KEY,
128
+ person_id INTEGER NOT NULL,
129
+ skill_id INTEGER NOT NULL,
130
+ endorsements_count INTEGER CHECK (endorsements_count IS NULL OR typeof(endorsements_count) = 'integer' AND endorsements_count >= 0),
131
+ created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
132
+ updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
133
+ sent_at_to_pas DATETIME,
134
+ actual_at DATETIME NOT NULL,
135
+ UNIQUE (person_id, skill_id),
136
+ FOREIGN KEY(person_id) REFERENCES people(id),
137
+ FOREIGN KEY(skill_id) REFERENCES skills(id)
138
+ );
139
+
140
+ CREATE TABLE person_email(
141
+ id INTEGER PRIMARY KEY,
142
+ person_id INTEGER NOT NULL,
143
+ email TEXT NOT NULL,
144
+ type TEXT NOT NULL CHECK (type IN ('personal', 'business')),
145
+ created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
146
+ updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')),
147
+ sent_at_to_pas DATETIME,
148
+ actual_at DATETIME NOT NULL,
149
+ UNIQUE (person_id, email),
150
+ FOREIGN KEY(person_id) REFERENCES people(id)
151
+ );
152
+ `);
153
+ // ── Mock Data (obviously synthetic, no real PII) ────────────────────
154
+ const NOW = "2025-01-15T12:00:00.000Z";
155
+ // Person 1: full profile with all fields populated
156
+ db.exec(`
157
+ INSERT INTO people (id, original_id, created_at, updated_at)
158
+ VALUES (1, 1, '${NOW}', '${NOW}');
159
+
160
+ INSERT INTO person_mini_profile
161
+ (person_id, first_name, first_name_uppercase, last_name, last_name_uppercase,
162
+ headline, headline_uppercase, avatar)
163
+ VALUES
164
+ (1, 'Ada', 'ADA', 'Lovelace', 'LOVELACE',
165
+ 'Principal Analytical Engine Programmer',
166
+ 'PRINCIPAL ANALYTICAL ENGINE PROGRAMMER',
167
+ 'https://example.test/avatars/ada.jpg');
168
+
169
+ INSERT INTO person_external_ids
170
+ (person_id, external_id, external_id_uppercase, type_group, is_member_id)
171
+ VALUES
172
+ (1, 'ada-lovelace-test', 'ADA-LOVELACE-TEST', 'public', NULL),
173
+ (1, '100000001', '100000001', 'member', 1),
174
+ (1, 'h4sh-ada-001', 'H4SH-ADA-001', 'hash', NULL);
175
+
176
+ INSERT INTO person_current_position
177
+ (person_id, company, company_uppercase, position, position_uppercase)
178
+ VALUES
179
+ (1, 'Babbage Industries', 'BABBAGE INDUSTRIES',
180
+ 'Lead Programmer', 'LEAD PROGRAMMER');
181
+
182
+ INSERT INTO person_positions
183
+ (person_id, title, company_name, company_id, start_year, start_month,
184
+ is_default, actual_at)
185
+ VALUES
186
+ (1, 'Lead Programmer', 'Babbage Industries', 'C001',
187
+ 2020, 3, 1, '${NOW}');
188
+
189
+ INSERT INTO person_positions
190
+ (person_id, title, company_name, company_id, start_year, start_month,
191
+ end_year, end_month, actual_at)
192
+ VALUES
193
+ (1, 'Junior Analyst', 'Difference Engine Co', 'C002',
194
+ 2015, 9, 2019, 12, '${NOW}');
195
+
196
+ INSERT INTO person_education
197
+ (person_id, school_name, degree_name, field_of_study,
198
+ start_year, end_year, actual_at)
199
+ VALUES
200
+ (1, 'University of Mathematica', 'BSc', 'Mathematics',
201
+ 2011, 2015, '${NOW}');
202
+
203
+ INSERT INTO person_education
204
+ (person_id, school_name, degree_name, field_of_study,
205
+ start_year, end_year, actual_at)
206
+ VALUES
207
+ (1, 'Royal Polytechnic', 'MSc', 'Computational Logic',
208
+ 2015, 2017, '${NOW}');
209
+
210
+ INSERT INTO skills (id, name) VALUES (1, 'Algorithm Design');
211
+ INSERT INTO skills (id, name) VALUES (2, 'Mechanical Computing');
212
+ INSERT INTO skills (id, name) VALUES (3, 'Technical Writing');
213
+
214
+ INSERT INTO person_skill (person_id, skill_id, endorsements_count, actual_at)
215
+ VALUES (1, 1, 42, '${NOW}');
216
+ INSERT INTO person_skill (person_id, skill_id, endorsements_count, actual_at)
217
+ VALUES (1, 2, 17, '${NOW}');
218
+
219
+ INSERT INTO person_email (person_id, email, type, actual_at)
220
+ VALUES (1, 'ada@example.test', 'business', '${NOW}');
221
+ `);
222
+ // Person 2: minimal profile (only required fields)
223
+ db.exec(`
224
+ INSERT INTO people (id, original_id, created_at, updated_at)
225
+ VALUES (2, 2, '${NOW}', '${NOW}');
226
+
227
+ INSERT INTO person_mini_profile
228
+ (person_id, first_name, first_name_uppercase)
229
+ VALUES (2, 'Charlie', 'CHARLIE');
230
+
231
+ INSERT INTO person_external_ids
232
+ (person_id, external_id, external_id_uppercase, type_group)
233
+ VALUES (2, 'charlie-test', 'CHARLIE-TEST', 'public');
234
+ `);
235
+ // Person 3: another full profile for variety
236
+ db.exec(`
237
+ INSERT INTO people (id, original_id, created_at, updated_at)
238
+ VALUES (3, 3, '${NOW}', '${NOW}');
239
+
240
+ INSERT INTO person_mini_profile
241
+ (person_id, first_name, first_name_uppercase, last_name, last_name_uppercase,
242
+ headline, headline_uppercase)
243
+ VALUES
244
+ (3, 'Grace', 'GRACE', 'Hopper', 'HOPPER',
245
+ 'Compiler Pioneer at COBOL Systems',
246
+ 'COMPILER PIONEER AT COBOL SYSTEMS');
247
+
248
+ INSERT INTO person_external_ids
249
+ (person_id, external_id, external_id_uppercase, type_group, is_member_id)
250
+ VALUES
251
+ (3, 'grace-hopper-test', 'GRACE-HOPPER-TEST', 'public', NULL),
252
+ (3, '100000003', '100000003', 'member', 1);
253
+
254
+ INSERT INTO person_current_position
255
+ (person_id, company, company_uppercase, position, position_uppercase)
256
+ VALUES
257
+ (3, 'COBOL Systems Inc', 'COBOL SYSTEMS INC',
258
+ 'Distinguished Engineer', 'DISTINGUISHED ENGINEER');
259
+
260
+ INSERT INTO person_positions
261
+ (person_id, title, company_name, start_year, start_month,
262
+ is_default, actual_at)
263
+ VALUES
264
+ (3, 'Distinguished Engineer', 'COBOL Systems Inc',
265
+ 2018, 1, 1, '${NOW}');
266
+
267
+ INSERT INTO person_education
268
+ (person_id, school_name, degree_name, field_of_study,
269
+ start_year, end_year, actual_at)
270
+ VALUES
271
+ (3, 'Vassar College', 'BA', 'Mathematics and Physics',
272
+ 1924, 1928, '${NOW}');
273
+
274
+ INSERT INTO person_skill (person_id, skill_id, endorsements_count, actual_at)
275
+ VALUES (3, 3, 99, '${NOW}');
276
+
277
+ INSERT INTO person_email (person_id, email, type, actual_at)
278
+ VALUES (3, 'grace@example.test', 'business', '${NOW}');
279
+ INSERT INTO person_email (person_id, email, type, actual_at)
280
+ VALUES (3, 'grace.personal@example.test', 'personal', '${NOW}');
281
+ `);
282
+ // ── Write to disk ───────────────────────────────────────────────────
283
+ writeFileSync(FIXTURE_PATH, db.serialize());
284
+ db.close();
285
+ console.log(`Fixture written to ${FIXTURE_PATH}`);
286
+ //# sourceMappingURL=create-fixture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-fixture.js","sourceRoot":"","sources":["../../../src/db/testing/create-fixture.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AAEnD,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC,CAAC;AAE5B,uEAAuE;AAEvE,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyIP,CAAC,CAAC;AAEH,uEAAuE;AAEvE,MAAM,GAAG,GAAG,0BAA0B,CAAC;AAEvC,mDAAmD;AACnD,EAAE,CAAC,IAAI,CAAC;;mBAEW,GAAG,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBA6BZ,GAAG;;;;;;;2BAOI,GAAG;;;;;;;oBAOV,GAAG;;;;;;;oBAOH,GAAG;;;;;;;uBAOA,GAAG;;uBAEH,GAAG;;;gDAGsB,GAAG;CAClD,CAAC,CAAC;AAEH,mDAAmD;AACnD,EAAE,CAAC,IAAI,CAAC;;mBAEW,GAAG,OAAO,GAAG;;;;;;;;;CAS/B,CAAC,CAAC;AAEH,6CAA6C;AAC7C,EAAE,CAAC,IAAI,CAAC;;mBAEW,GAAG,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;oBA2BZ,GAAG;;;;;;;oBAOH,GAAG;;;uBAGA,GAAG;;;kDAGwB,GAAG;;2DAEM,GAAG;CAC7D,CAAC,CAAC;AAEH,uEAAuE;AAEvE,aAAa,CAAC,YAAY,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;AAC5C,EAAE,CAAC,KAAK,EAAE,CAAC;AAEX,OAAO,CAAC,GAAG,CAAC,sBAAsB,YAAY,EAAE,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import Database from "better-sqlite3";
2
+ /** Absolute path to the test fixture database file. */
3
+ export declare const FIXTURE_PATH: string;
4
+ /**
5
+ * Opens the fixture database as a writable in-memory copy.
6
+ *
7
+ * Each call returns an independent database instance so tests cannot
8
+ * interfere with each other. The real LinkedHelper schema (tables,
9
+ * indexes, CHECK constraints) and synthetic mock data are included.
10
+ *
11
+ * Call `.close()` when done.
12
+ */
13
+ export declare function openFixture(): Database.Database;
14
+ //# sourceMappingURL=open-fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-fixture.d.ts","sourceRoot":"","sources":["../../../src/db/testing/open-fixture.ts"],"names":[],"mappings":"AAGA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,uDAAuD;AACvD,eAAO,MAAM,YAAY,QAAgC,CAAC;AAE1D;;;;;;;;GAQG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAAC,QAAQ,CAG/C"}
@@ -0,0 +1,21 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import Database from "better-sqlite3";
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ /** Absolute path to the test fixture database file. */
7
+ export const FIXTURE_PATH = join(__dirname, "fixture.db");
8
+ /**
9
+ * Opens the fixture database as a writable in-memory copy.
10
+ *
11
+ * Each call returns an independent database instance so tests cannot
12
+ * interfere with each other. The real LinkedHelper schema (tables,
13
+ * indexes, CHECK constraints) and synthetic mock data are included.
14
+ *
15
+ * Call `.close()` when done.
16
+ */
17
+ export function openFixture() {
18
+ const buffer = readFileSync(FIXTURE_PATH);
19
+ return new Database(buffer);
20
+ }
21
+ //# sourceMappingURL=open-fixture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-fixture.js","sourceRoot":"","sources":["../../../src/db/testing/open-fixture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,uDAAuD;AACvD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AAE1D;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAC1C,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,6 @@
1
- export {};
1
+ export type { Account, CurrentPosition, Education, ExternalId, ExternalIdTypeGroup, InstanceInfo, InstanceStatus, MiniProfile, Position, Profile, Skill, StartInstanceParams, StartInstanceResult, } from "./types/index.js";
2
+ export { AppLaunchError, AppNotFoundError, AppService, type AppServiceOptions, ExtractionTimeoutError, extractSlug, InstanceNotRunningError, InstanceService, LauncherService, LinkedHelperNotRunningError, ProfileService, ServiceError, StartInstanceError, startInstanceWithRecovery, type StartInstanceOutcome, type VisitAndExtractOptions, checkStatus, type AccountInstanceStatus, type DatabaseStatus, type LauncherStatus, type StatusReport, waitForInstancePort, } from "./services/index.js";
3
+ export { DatabaseClient, discoverAllDatabases, discoverDatabase, ProfileRepository, } from "./db/index.js";
4
+ export { DatabaseError, DatabaseNotFoundError, ProfileNotFoundError, } from "./db/index.js";
5
+ export { CDPConnectionError, CDPError, CDPEvaluationError, CDPTimeoutError, discoverInstancePort, } from "./cdp/index.js";
2
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,OAAO,EACP,eAAe,EACf,SAAS,EACT,UAAU,EACV,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,WAAW,EACX,QAAQ,EACR,OAAO,EACP,KAAK,EACL,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,KAAK,iBAAiB,EACtB,sBAAsB,EACtB,WAAW,EACX,uBAAuB,EACvB,eAAe,EACf,eAAe,EACf,2BAA2B,EAC3B,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,yBAAyB,EACzB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,WAAW,EACX,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,kBAAkB,EAClB,QAAQ,EACR,kBAAkB,EAClB,eAAe,EACf,oBAAoB,GACrB,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,8 @@
1
- export {};
1
+ // Services
2
+ export { AppLaunchError, AppNotFoundError, AppService, ExtractionTimeoutError, extractSlug, InstanceNotRunningError, InstanceService, LauncherService, LinkedHelperNotRunningError, ProfileService, ServiceError, StartInstanceError, startInstanceWithRecovery, checkStatus, waitForInstancePort, } from "./services/index.js";
3
+ // Data access
4
+ export { DatabaseClient, discoverAllDatabases, discoverDatabase, ProfileRepository, } from "./db/index.js";
5
+ // Errors (DB + CDP errors can propagate through the service layer)
6
+ export { DatabaseError, DatabaseNotFoundError, ProfileNotFoundError, } from "./db/index.js";
7
+ export { CDPConnectionError, CDPError, CDPEvaluationError, CDPTimeoutError, discoverInstancePort, } from "./cdp/index.js";
2
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,WAAW;AACX,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,UAAU,EAEV,sBAAsB,EACtB,WAAW,EACX,uBAAuB,EACvB,eAAe,EACf,eAAe,EACf,2BAA2B,EAC3B,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,yBAAyB,EAGzB,WAAW,EAKX,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,cAAc;AACd,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAEvB,mEAAmE;AACnE,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,kBAAkB,EAClB,QAAQ,EACR,kBAAkB,EAClB,eAAe,EACf,oBAAoB,GACrB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,62 @@
1
+ export interface AppServiceOptions {
2
+ /** Delay in ms after spawn before checking if the app is reachable (default 3000). */
3
+ launchProbeDelay?: number;
4
+ }
5
+ /**
6
+ * Manages the LinkedHelper application process lifecycle.
7
+ *
8
+ * Provides methods to launch, quit, and probe the LinkedHelper
9
+ * Electron application. When no explicit CDP port is provided,
10
+ * a free port is selected automatically at launch time.
11
+ */
12
+ export declare class AppService {
13
+ private assignedPort;
14
+ private childProcess;
15
+ private readonly launchProbeDelay;
16
+ /**
17
+ * @param cdpPort - Explicit CDP port. When omitted, `launch()` will
18
+ * select a free port automatically via `get-port`.
19
+ * @param options - Additional configuration options.
20
+ */
21
+ constructor(cdpPort?: number, options?: AppServiceOptions);
22
+ /**
23
+ * The CDP port currently in use.
24
+ *
25
+ * @throws {Error} if neither an explicit port was provided nor
26
+ * `launch()` has been called yet.
27
+ */
28
+ get cdpPort(): number;
29
+ /**
30
+ * Launch the LinkedHelper application with CDP enabled.
31
+ *
32
+ * If no CDP port was specified in the constructor, a free port
33
+ * is selected automatically.
34
+ *
35
+ * @throws {AppNotFoundError} if the binary cannot be found.
36
+ * @throws {AppLaunchError} if the process fails to start.
37
+ */
38
+ launch(): Promise<void>;
39
+ /**
40
+ * Quit the LinkedHelper application.
41
+ *
42
+ * When a child process handle is available, sends `SIGTERM` and waits
43
+ * for the process to exit. If it does not exit within
44
+ * {@link QUIT_GRACEFUL_TIMEOUT}, escalates to `SIGKILL`.
45
+ *
46
+ * When no child process handle is available (app was launched
47
+ * externally), attempts to close via CDP.
48
+ */
49
+ quit(): Promise<void>;
50
+ /**
51
+ * Check whether LinkedHelper is running by probing its CDP endpoint.
52
+ */
53
+ isRunning(): Promise<boolean>;
54
+ /**
55
+ * Locate the LinkedHelper binary for the current platform.
56
+ *
57
+ * @throws {AppNotFoundError} if the binary does not exist at the
58
+ * expected location.
59
+ */
60
+ static findBinary(): string;
61
+ }
62
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/services/app.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,iBAAiB;IAChC,sFAAsF;IACtF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAE1C;;;;OAIG;gBACS,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB;IAKzD;;;;;OAKG;IACH,IAAI,OAAO,IAAI,MAAM,CAKpB;IAED;;;;;;;;OAQG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IA0C7B;;;;;;;;;OASG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkC3B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAYnC;;;;;OAKG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM;CAW5B"}
@@ -0,0 +1,198 @@
1
+ import { spawn } from "node:child_process";
2
+ import { accessSync, constants } from "node:fs";
3
+ import { join } from "node:path";
4
+ import getPort from "get-port";
5
+ import { discoverTargets } from "../cdp/index.js";
6
+ import { AppLaunchError, AppNotFoundError } from "./errors.js";
7
+ /** Default delay after spawn before checking if the app is reachable (ms). */
8
+ const DEFAULT_LAUNCH_PROBE_DELAY = 3000;
9
+ /** Maximum time to wait for the process to exit after SIGTERM (ms). */
10
+ const QUIT_GRACEFUL_TIMEOUT = 10_000;
11
+ /** Maximum time to wait for the process to exit after SIGKILL (ms). */
12
+ const QUIT_FORCE_TIMEOUT = 5_000;
13
+ /**
14
+ * Manages the LinkedHelper application process lifecycle.
15
+ *
16
+ * Provides methods to launch, quit, and probe the LinkedHelper
17
+ * Electron application. When no explicit CDP port is provided,
18
+ * a free port is selected automatically at launch time.
19
+ */
20
+ export class AppService {
21
+ assignedPort;
22
+ childProcess = null;
23
+ launchProbeDelay;
24
+ /**
25
+ * @param cdpPort - Explicit CDP port. When omitted, `launch()` will
26
+ * select a free port automatically via `get-port`.
27
+ * @param options - Additional configuration options.
28
+ */
29
+ constructor(cdpPort, options) {
30
+ this.assignedPort = cdpPort ?? null;
31
+ this.launchProbeDelay = options?.launchProbeDelay ?? DEFAULT_LAUNCH_PROBE_DELAY;
32
+ }
33
+ /**
34
+ * The CDP port currently in use.
35
+ *
36
+ * @throws {Error} if neither an explicit port was provided nor
37
+ * `launch()` has been called yet.
38
+ */
39
+ get cdpPort() {
40
+ if (this.assignedPort === null) {
41
+ throw new Error("CDP port not yet assigned — call launch() first or provide a port to the constructor");
42
+ }
43
+ return this.assignedPort;
44
+ }
45
+ /**
46
+ * Launch the LinkedHelper application with CDP enabled.
47
+ *
48
+ * If no CDP port was specified in the constructor, a free port
49
+ * is selected automatically.
50
+ *
51
+ * @throws {AppNotFoundError} if the binary cannot be found.
52
+ * @throws {AppLaunchError} if the process fails to start.
53
+ */
54
+ async launch() {
55
+ if (this.assignedPort !== null && await this.isRunning()) {
56
+ return;
57
+ }
58
+ if (this.assignedPort === null) {
59
+ this.assignedPort = await getPort();
60
+ }
61
+ const binary = AppService.findBinary();
62
+ const args = [`--remote-debugging-port=${String(this.assignedPort)}`];
63
+ const child = spawn(binary, args, {
64
+ detached: true,
65
+ stdio: "ignore",
66
+ });
67
+ child.unref();
68
+ // Wait for an early error (e.g. ENOENT from spawn) before probing
69
+ await new Promise((resolve, reject) => {
70
+ const onError = (err) => {
71
+ cleanup();
72
+ reject(new AppLaunchError(`Failed to launch LinkedHelper: ${err.message}`, { cause: err }));
73
+ };
74
+ const timer = setTimeout(() => {
75
+ cleanup();
76
+ resolve();
77
+ }, this.launchProbeDelay);
78
+ function cleanup() {
79
+ child.removeListener("error", onError);
80
+ clearTimeout(timer);
81
+ }
82
+ child.on("error", onError);
83
+ });
84
+ this.childProcess = child;
85
+ }
86
+ /**
87
+ * Quit the LinkedHelper application.
88
+ *
89
+ * When a child process handle is available, sends `SIGTERM` and waits
90
+ * for the process to exit. If it does not exit within
91
+ * {@link QUIT_GRACEFUL_TIMEOUT}, escalates to `SIGKILL`.
92
+ *
93
+ * When no child process handle is available (app was launched
94
+ * externally), attempts to close via CDP.
95
+ */
96
+ async quit() {
97
+ if (this.childProcess) {
98
+ const child = this.childProcess;
99
+ this.childProcess = null;
100
+ child.kill("SIGTERM");
101
+ const exited = await waitForExit(child, QUIT_GRACEFUL_TIMEOUT);
102
+ if (!exited) {
103
+ child.kill("SIGKILL");
104
+ await waitForExit(child, QUIT_FORCE_TIMEOUT);
105
+ }
106
+ return;
107
+ }
108
+ if (this.assignedPort === null) {
109
+ return;
110
+ }
111
+ // Fallback: close via CDP Browser.close
112
+ try {
113
+ const targets = await discoverTargets(this.assignedPort);
114
+ const first = targets[0];
115
+ if (first) {
116
+ await fetch(`http://127.0.0.1:${String(this.assignedPort)}/json/close/${first.id}`);
117
+ }
118
+ }
119
+ catch {
120
+ // App may already be closed
121
+ }
122
+ }
123
+ /**
124
+ * Check whether LinkedHelper is running by probing its CDP endpoint.
125
+ */
126
+ async isRunning() {
127
+ if (this.assignedPort === null) {
128
+ return false;
129
+ }
130
+ try {
131
+ await discoverTargets(this.assignedPort);
132
+ return true;
133
+ }
134
+ catch {
135
+ return false;
136
+ }
137
+ }
138
+ /**
139
+ * Locate the LinkedHelper binary for the current platform.
140
+ *
141
+ * @throws {AppNotFoundError} if the binary does not exist at the
142
+ * expected location.
143
+ */
144
+ static findBinary() {
145
+ const envPath = process.env["LINKEDHELPER_PATH"];
146
+ if (envPath) {
147
+ assertFileExists(envPath);
148
+ return envPath;
149
+ }
150
+ const path = getDefaultBinaryPath();
151
+ assertFileExists(path);
152
+ return path;
153
+ }
154
+ }
155
+ function getDefaultBinaryPath() {
156
+ switch (process.platform) {
157
+ case "darwin":
158
+ return "/Applications/linked-helper.app/Contents/MacOS/linked-helper";
159
+ case "win32":
160
+ return join(process.env["LOCALAPPDATA"] ?? join(process.env["USERPROFILE"] ?? "C:\\Users\\Default", "AppData", "Local"), "Programs", "linked-helper", "linked-helper.exe");
161
+ default:
162
+ return "/opt/linked-helper/linked-helper";
163
+ }
164
+ }
165
+ /**
166
+ * Wait for a child process to exit, with a timeout.
167
+ *
168
+ * @returns `true` if the process exited within the timeout, `false` otherwise.
169
+ */
170
+ function waitForExit(child, timeout) {
171
+ if (child.exitCode !== null) {
172
+ return Promise.resolve(true);
173
+ }
174
+ return new Promise((resolve) => {
175
+ const timer = setTimeout(() => {
176
+ cleanup();
177
+ resolve(false);
178
+ }, timeout);
179
+ const onExit = () => {
180
+ cleanup();
181
+ resolve(true);
182
+ };
183
+ function cleanup() {
184
+ child.removeListener("exit", onExit);
185
+ clearTimeout(timer);
186
+ }
187
+ child.on("exit", onExit);
188
+ });
189
+ }
190
+ function assertFileExists(path) {
191
+ try {
192
+ accessSync(path, constants.X_OK);
193
+ }
194
+ catch {
195
+ throw new AppNotFoundError(`LinkedHelper binary not found at ${path}. Set LINKEDHELPER_PATH to override.`);
196
+ }
197
+ }
198
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/services/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=app.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.test.d.ts","sourceRoot":"","sources":["../../src/services/app.test.ts"],"names":[],"mappings":""}