@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,119 @@
1
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
2
+ import { DatabaseClient } from "../client.js";
3
+ import { ProfileNotFoundError } from "../errors.js";
4
+ import { FIXTURE_PATH } from "../testing/open-fixture.js";
5
+ import { ProfileRepository } from "./profile.js";
6
+ describe("ProfileRepository (integration)", () => {
7
+ let client;
8
+ let repo;
9
+ beforeAll(() => {
10
+ client = new DatabaseClient(FIXTURE_PATH);
11
+ repo = new ProfileRepository(client);
12
+ });
13
+ afterAll(() => {
14
+ client.close();
15
+ });
16
+ describe("findById", () => {
17
+ it("assembles a full profile from the real schema", () => {
18
+ const profile = repo.findById(1);
19
+ expect(profile.id).toBe(1);
20
+ // Mini profile
21
+ expect(profile.miniProfile.firstName).toBe("Ada");
22
+ expect(profile.miniProfile.lastName).toBe("Lovelace");
23
+ expect(profile.miniProfile.headline).toBe("Principal Analytical Engine Programmer");
24
+ expect(profile.miniProfile.avatar).toBe("https://example.test/avatars/ada.jpg");
25
+ // External IDs
26
+ expect(profile.externalIds.length).toBeGreaterThanOrEqual(2);
27
+ const publicId = profile.externalIds.find((e) => e.typeGroup === "public");
28
+ expect(publicId?.externalId).toBe("ada-lovelace-test");
29
+ const memberId = profile.externalIds.find((e) => e.typeGroup === "member");
30
+ expect(memberId?.externalId).toBe("100000001");
31
+ expect(memberId?.isMemberId).toBe(true);
32
+ // Current position
33
+ expect(profile.currentPosition).not.toBeNull();
34
+ expect(profile.currentPosition?.company).toBe("Babbage Industries");
35
+ expect(profile.currentPosition?.title).toBe("Lead Programmer");
36
+ // Position history with year-month formatting
37
+ expect(profile.positions.length).toBeGreaterThanOrEqual(2);
38
+ const currentPos = profile.positions.find((p) => p.isCurrent);
39
+ expect(currentPos?.company).toBe("Babbage Industries");
40
+ expect(currentPos?.startDate).toBe("2020-03");
41
+ expect(currentPos?.endDate).toBeNull();
42
+ const pastPos = profile.positions.find((p) => !p.isCurrent);
43
+ expect(pastPos?.company).toBe("Difference Engine Co");
44
+ expect(pastPos?.startDate).toBe("2015-09");
45
+ expect(pastPos?.endDate).toBe("2019-12");
46
+ // Education with year-only formatting
47
+ expect(profile.education.length).toBeGreaterThanOrEqual(1);
48
+ const edu = profile.education.find((e) => e.school === "University of Mathematica");
49
+ expect(edu?.degree).toBe("BSc");
50
+ expect(edu?.field).toBe("Mathematics");
51
+ expect(edu?.startDate).toBe("2011");
52
+ expect(edu?.endDate).toBe("2015");
53
+ // Skills (joined from skills table)
54
+ expect(profile.skills.length).toBeGreaterThanOrEqual(2);
55
+ const skillNames = profile.skills.map((s) => s.name);
56
+ expect(skillNames).toContain("Algorithm Design");
57
+ expect(skillNames).toContain("Mechanical Computing");
58
+ // Emails
59
+ expect(profile.emails).toContain("ada@example.test");
60
+ });
61
+ it("assembles a minimal profile without optional data", () => {
62
+ const profile = repo.findById(2);
63
+ expect(profile.id).toBe(2);
64
+ expect(profile.miniProfile.firstName).toBe("Charlie");
65
+ expect(profile.miniProfile.lastName).toBeNull();
66
+ expect(profile.miniProfile.headline).toBeNull();
67
+ expect(profile.miniProfile.avatar).toBeNull();
68
+ expect(profile.currentPosition).toBeNull();
69
+ expect(profile.positions).toEqual([]);
70
+ expect(profile.education).toEqual([]);
71
+ expect(profile.skills).toEqual([]);
72
+ expect(profile.emails).toEqual([]);
73
+ });
74
+ it("assembles a profile with multiple emails", () => {
75
+ const profile = repo.findById(3);
76
+ expect(profile.emails).toHaveLength(2);
77
+ expect(profile.emails).toContain("grace@example.test");
78
+ expect(profile.emails).toContain("grace.personal@example.test");
79
+ });
80
+ it("throws ProfileNotFoundError for a nonexistent ID", () => {
81
+ expect(() => repo.findById(999)).toThrow(ProfileNotFoundError);
82
+ });
83
+ });
84
+ describe("findByPublicId", () => {
85
+ it("resolves a public ID to the correct profile", () => {
86
+ const profile = repo.findByPublicId("ada-lovelace-test");
87
+ expect(profile.id).toBe(1);
88
+ expect(profile.miniProfile.firstName).toBe("Ada");
89
+ });
90
+ it("resolves another public ID", () => {
91
+ const profile = repo.findByPublicId("grace-hopper-test");
92
+ expect(profile.id).toBe(3);
93
+ expect(profile.miniProfile.firstName).toBe("Grace");
94
+ });
95
+ it("throws ProfileNotFoundError for an unknown public ID", () => {
96
+ expect(() => repo.findByPublicId("no-such-person")).toThrow(ProfileNotFoundError);
97
+ });
98
+ });
99
+ describe("cross-table consistency", () => {
100
+ it("external IDs reference the correct person", () => {
101
+ const profile = repo.findById(1);
102
+ // Every external ID should belong to person 1 — verified by
103
+ // the JOIN in the query, but this tests the assembly is coherent.
104
+ for (const extId of profile.externalIds) {
105
+ expect(extId.externalId).toBeTruthy();
106
+ expect(["member", "public", "hash", "avatar"]).toContain(extId.typeGroup);
107
+ }
108
+ });
109
+ it("current position and position history agree on current role", () => {
110
+ const profile = repo.findById(1);
111
+ const currentPos = profile.positions.find((p) => p.isCurrent);
112
+ expect(profile.currentPosition).not.toBeNull();
113
+ expect(currentPos).toBeDefined();
114
+ // The current_position table and positions table should show the same company
115
+ expect(profile.currentPosition?.company).toBe(currentPos?.company);
116
+ });
117
+ });
118
+ });
119
+ //# sourceMappingURL=profile.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.integration.test.js","sourceRoot":"","sources":["../../../src/db/repositories/profile.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ import { ProfileNotFoundError } from "../errors.js";
2
+ function formatDate(year, month) {
3
+ if (year == null)
4
+ return null;
5
+ if (month == null)
6
+ return String(year);
7
+ return `${String(year)}-${String(month).padStart(2, "0")}`;
8
+ }
9
+ /**
10
+ * Read-only repository for assembling {@link Profile} objects from
11
+ * LinkedHelper's SQLite database.
12
+ */
13
+ export class ProfileRepository {
14
+ stmtPersonById;
15
+ stmtPersonByPublicId;
16
+ stmtMiniProfile;
17
+ stmtExternalIds;
18
+ stmtCurrentPosition;
19
+ stmtPositions;
20
+ stmtEducation;
21
+ stmtSkills;
22
+ stmtEmails;
23
+ constructor(client) {
24
+ const { db } = client;
25
+ this.stmtPersonById = db.prepare("SELECT id FROM people WHERE id = ?");
26
+ this.stmtPersonByPublicId = db.prepare(`SELECT p.id
27
+ FROM people p
28
+ JOIN person_external_ids pei ON p.id = pei.person_id
29
+ WHERE pei.type_group = 'public' AND pei.external_id = ?`);
30
+ this.stmtMiniProfile = db.prepare(`SELECT first_name, last_name, headline, avatar
31
+ FROM person_mini_profile WHERE person_id = ?`);
32
+ this.stmtExternalIds = db.prepare(`SELECT external_id, type_group, is_member_id
33
+ FROM person_external_ids WHERE person_id = ?`);
34
+ this.stmtCurrentPosition = db.prepare(`SELECT company, position
35
+ FROM person_current_position WHERE person_id = ?`);
36
+ this.stmtPositions = db.prepare(`SELECT company_name, title, start_year, start_month,
37
+ end_year, end_month, is_default
38
+ FROM person_positions WHERE person_id = ?`);
39
+ this.stmtEducation = db.prepare(`SELECT school_name, degree_name, field_of_study, start_year, end_year
40
+ FROM person_education WHERE person_id = ?`);
41
+ this.stmtSkills = db.prepare(`SELECT s.name
42
+ FROM person_skill ps
43
+ JOIN skills s ON ps.skill_id = s.id
44
+ WHERE ps.person_id = ?`);
45
+ this.stmtEmails = db.prepare(`SELECT email FROM person_email WHERE person_id = ?`);
46
+ }
47
+ /**
48
+ * Looks up a profile by its internal database ID.
49
+ *
50
+ * @throws {ProfileNotFoundError} if no person exists with the given ID.
51
+ */
52
+ findById(id) {
53
+ const row = this.stmtPersonById.get(id);
54
+ if (!row)
55
+ throw new ProfileNotFoundError(id);
56
+ return this.assembleProfile(row.id);
57
+ }
58
+ /**
59
+ * Looks up a profile by LinkedIn public ID (the slug from a profile URL).
60
+ *
61
+ * @throws {ProfileNotFoundError} if no person matches the public ID.
62
+ */
63
+ findByPublicId(slug) {
64
+ const row = this.stmtPersonByPublicId.get(slug);
65
+ if (!row)
66
+ throw new ProfileNotFoundError(slug);
67
+ return this.assembleProfile(row.id);
68
+ }
69
+ assembleProfile(personId) {
70
+ const miniRow = this.stmtMiniProfile.get(personId);
71
+ const miniProfile = miniRow
72
+ ? {
73
+ firstName: miniRow.first_name,
74
+ lastName: miniRow.last_name,
75
+ headline: miniRow.headline,
76
+ avatar: miniRow.avatar,
77
+ }
78
+ : { firstName: "", lastName: null, headline: null, avatar: null };
79
+ const externalIds = this.stmtExternalIds
80
+ .all(personId)
81
+ .map((r) => ({
82
+ externalId: r.external_id,
83
+ typeGroup: r.type_group,
84
+ isMemberId: r.is_member_id === 1,
85
+ }));
86
+ const cpRow = this.stmtCurrentPosition.get(personId);
87
+ const currentPosition = cpRow
88
+ ? { company: cpRow.company, title: cpRow.position }
89
+ : null;
90
+ const positions = this.stmtPositions
91
+ .all(personId)
92
+ .map((r) => ({
93
+ company: r.company_name,
94
+ title: r.title,
95
+ startDate: formatDate(r.start_year, r.start_month),
96
+ endDate: formatDate(r.end_year, r.end_month),
97
+ isCurrent: r.is_default != null,
98
+ }));
99
+ const education = this.stmtEducation
100
+ .all(personId)
101
+ .map((r) => ({
102
+ school: r.school_name,
103
+ degree: r.degree_name,
104
+ field: r.field_of_study,
105
+ startDate: formatDate(r.start_year, null),
106
+ endDate: formatDate(r.end_year, null),
107
+ }));
108
+ const skills = this.stmtSkills
109
+ .all(personId)
110
+ .map((r) => ({ name: r.name }));
111
+ const emails = this.stmtEmails
112
+ .all(personId)
113
+ .map((r) => r.email);
114
+ return {
115
+ id: personId,
116
+ miniProfile,
117
+ externalIds,
118
+ currentPosition,
119
+ positions,
120
+ education,
121
+ skills,
122
+ emails,
123
+ };
124
+ }
125
+ }
126
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../../src/db/repositories/profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=profile.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.test.d.ts","sourceRoot":"","sources":["../../../src/db/repositories/profile.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,126 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import { DatabaseClient } from "../client.js";
3
+ import { ProfileNotFoundError } from "../errors.js";
4
+ import { openFixture } from "../testing/open-fixture.js";
5
+ import { ProfileRepository } from "./profile.js";
6
+ describe("ProfileRepository", () => {
7
+ let db;
8
+ let client;
9
+ let repo;
10
+ beforeEach(() => {
11
+ db = openFixture();
12
+ client = { db };
13
+ repo = new ProfileRepository(client);
14
+ });
15
+ afterEach(() => {
16
+ db.close();
17
+ });
18
+ describe("findById", () => {
19
+ it("returns a fully assembled profile", () => {
20
+ const profile = repo.findById(1);
21
+ expect(profile.id).toBe(1);
22
+ expect(profile.miniProfile).toEqual({
23
+ firstName: "Ada",
24
+ lastName: "Lovelace",
25
+ headline: "Principal Analytical Engine Programmer",
26
+ avatar: "https://example.test/avatars/ada.jpg",
27
+ });
28
+ expect(profile.externalIds).toHaveLength(3);
29
+ expect(profile.externalIds).toContainEqual({
30
+ externalId: "ada-lovelace-test",
31
+ typeGroup: "public",
32
+ isMemberId: false,
33
+ });
34
+ expect(profile.externalIds).toContainEqual({
35
+ externalId: "100000001",
36
+ typeGroup: "member",
37
+ isMemberId: true,
38
+ });
39
+ expect(profile.externalIds).toContainEqual({
40
+ externalId: "h4sh-ada-001",
41
+ typeGroup: "hash",
42
+ isMemberId: false,
43
+ });
44
+ expect(profile.currentPosition).toEqual({
45
+ company: "Babbage Industries",
46
+ title: "Lead Programmer",
47
+ });
48
+ expect(profile.positions).toHaveLength(2);
49
+ expect(profile.positions).toContainEqual({
50
+ company: "Babbage Industries",
51
+ title: "Lead Programmer",
52
+ startDate: "2020-03",
53
+ endDate: null,
54
+ isCurrent: true,
55
+ });
56
+ expect(profile.positions).toContainEqual({
57
+ company: "Difference Engine Co",
58
+ title: "Junior Analyst",
59
+ startDate: "2015-09",
60
+ endDate: "2019-12",
61
+ isCurrent: false,
62
+ });
63
+ expect(profile.education).toHaveLength(2);
64
+ expect(profile.education).toContainEqual({
65
+ school: "University of Mathematica",
66
+ degree: "BSc",
67
+ field: "Mathematics",
68
+ startDate: "2011",
69
+ endDate: "2015",
70
+ });
71
+ expect(profile.education).toContainEqual({
72
+ school: "Royal Polytechnic",
73
+ degree: "MSc",
74
+ field: "Computational Logic",
75
+ startDate: "2015",
76
+ endDate: "2017",
77
+ });
78
+ expect(profile.skills).toEqual([
79
+ { name: "Algorithm Design" },
80
+ { name: "Mechanical Computing" },
81
+ ]);
82
+ expect(profile.emails).toEqual(["ada@example.test"]);
83
+ });
84
+ it("throws ProfileNotFoundError for a missing ID", () => {
85
+ expect(() => repo.findById(999)).toThrow(ProfileNotFoundError);
86
+ expect(() => repo.findById(999)).toThrow("Profile not found for id 999");
87
+ });
88
+ it("handles a person with minimal data", () => {
89
+ const profile = repo.findById(2);
90
+ expect(profile.id).toBe(2);
91
+ expect(profile.miniProfile.firstName).toBe("Charlie");
92
+ expect(profile.miniProfile.lastName).toBeNull();
93
+ expect(profile.miniProfile.headline).toBeNull();
94
+ expect(profile.miniProfile.avatar).toBeNull();
95
+ expect(profile.externalIds).toHaveLength(1);
96
+ expect(profile.currentPosition).toBeNull();
97
+ expect(profile.positions).toEqual([]);
98
+ expect(profile.education).toEqual([]);
99
+ expect(profile.skills).toEqual([]);
100
+ expect(profile.emails).toEqual([]);
101
+ });
102
+ it("handles multiple emails", () => {
103
+ const profile = repo.findById(3);
104
+ expect(profile.emails).toHaveLength(2);
105
+ expect(profile.emails).toContain("grace@example.test");
106
+ expect(profile.emails).toContain("grace.personal@example.test");
107
+ });
108
+ });
109
+ describe("findByPublicId", () => {
110
+ it("finds a profile by LinkedIn public ID slug", () => {
111
+ const profile = repo.findByPublicId("ada-lovelace-test");
112
+ expect(profile.id).toBe(1);
113
+ expect(profile.miniProfile.firstName).toBe("Ada");
114
+ });
115
+ it("finds another profile by public ID", () => {
116
+ const profile = repo.findByPublicId("grace-hopper-test");
117
+ expect(profile.id).toBe(3);
118
+ expect(profile.miniProfile.firstName).toBe("Grace");
119
+ });
120
+ it("throws ProfileNotFoundError for an unknown slug", () => {
121
+ expect(() => repo.findByPublicId("nonexistent")).toThrow(ProfileNotFoundError);
122
+ expect(() => repo.findByPublicId("nonexistent")).toThrow('Profile not found for public ID "nonexistent"');
123
+ });
124
+ });
125
+ });
126
+ //# sourceMappingURL=profile.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.test.js","sourceRoot":"","sources":["../../../src/db/repositories/profile.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
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
+ export {};
8
+ //# sourceMappingURL=create-fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-fixture.d.ts","sourceRoot":"","sources":["../../../src/db/testing/create-fixture.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}