hunter-mate 0.1.24 → 0.1.25

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 (47) hide show
  1. package/dist/assets/extension/build-info.json +1 -1
  2. package/dist/assets/extension/manifest.json +3 -3
  3. package/dist/assets/server/chunks/{chunk-SAJB6JRK.mjs → chunk-VL7WHUEV.mjs} +556 -8
  4. package/dist/assets/server/chunks/{script-rule-ZJN6CEYX.mjs → script-rule-4RZQ2PQE.mjs} +1 -2
  5. package/dist/assets/server/main.mjs +153 -88
  6. package/dist/index.js +159 -20
  7. package/dist/web/dist/404.html +1 -1
  8. package/dist/web/dist/admin/data.html +1 -1
  9. package/dist/web/dist/admin/data.txt +1 -1
  10. package/dist/web/dist/auth/verify.html +1 -1
  11. package/dist/web/dist/auth/verify.txt +1 -1
  12. package/dist/web/dist/companies.html +1 -1
  13. package/dist/web/dist/companies.txt +1 -1
  14. package/dist/web/dist/company/admin.html +1 -1
  15. package/dist/web/dist/company/admin.txt +1 -1
  16. package/dist/web/dist/entity.html +1 -1
  17. package/dist/web/dist/entity.txt +1 -1
  18. package/dist/web/dist/index.html +1 -1
  19. package/dist/web/dist/index.txt +1 -1
  20. package/dist/web/dist/jobs.html +1 -1
  21. package/dist/web/dist/jobs.txt +1 -1
  22. package/dist/web/dist/logs.html +1 -1
  23. package/dist/web/dist/logs.txt +1 -1
  24. package/dist/web/dist/matching/jobs/placeholder/talents.html +1 -1
  25. package/dist/web/dist/matching/jobs/placeholder/talents.txt +1 -1
  26. package/dist/web/dist/matching/portraits/placeholder/jobs.html +1 -1
  27. package/dist/web/dist/matching/portraits/placeholder/jobs.txt +1 -1
  28. package/dist/web/dist/parselog.html +1 -1
  29. package/dist/web/dist/parselog.txt +1 -1
  30. package/dist/web/dist/recordings.html +1 -1
  31. package/dist/web/dist/recordings.txt +1 -1
  32. package/dist/web/dist/resource-usage.html +1 -1
  33. package/dist/web/dist/resource-usage.txt +1 -1
  34. package/dist/web/dist/shared/placeholder.html +1 -1
  35. package/dist/web/dist/shared/placeholder.txt +1 -1
  36. package/dist/web/dist/snapshots/placeholder/agent-prompt.html +1 -1
  37. package/dist/web/dist/snapshots/placeholder/agent-prompt.txt +1 -1
  38. package/dist/web/dist/talents.html +1 -1
  39. package/dist/web/dist/talents.txt +1 -1
  40. package/dist/web/dist/team/insights.html +1 -1
  41. package/dist/web/dist/team/insights.txt +1 -1
  42. package/package.json +1 -1
  43. package/dist/assets/server/chunks/chunk-BLXHCSZD.mjs +0 -565
  44. package/dist/assets/server/chunks/esm-4U746B76.mjs +0 -29
  45. /package/dist/assets/extension/background/{service-worker.20261017012007.js → service-worker.20261017183328.js} +0 -0
  46. /package/dist/web/dist/_next/static/{hBLezfvVOMiGqm4V9F15i → 5MA8faUttk6FzlxGWnOlM}/_buildManifest.js +0 -0
  47. /package/dist/web/dist/_next/static/{hBLezfvVOMiGqm4V9F15i → 5MA8faUttk6FzlxGWnOlM}/_ssgManifest.js +0 -0
@@ -21,11 +21,9 @@ import {
21
21
  trace
22
22
  } from "./chunks/chunk-U7FVFSKP.mjs";
23
23
  import {
24
- applyScriptRule
25
- } from "./chunks/chunk-BLXHCSZD.mjs";
26
- import {
24
+ applyScriptRule,
27
25
  load
28
- } from "./chunks/chunk-SAJB6JRK.mjs";
26
+ } from "./chunks/chunk-VL7WHUEV.mjs";
29
27
  import {
30
28
  __commonJS,
31
29
  __esm,
@@ -179242,7 +179240,7 @@ var require_src4 = __commonJS({
179242
179240
  return new createAgent.Agent(callback, opts);
179243
179241
  }
179244
179242
  (function(createAgent2) {
179245
- class Agent3 extends events_1.EventEmitter {
179243
+ class Agent4 extends events_1.EventEmitter {
179246
179244
  constructor(callback, _opts) {
179247
179245
  super();
179248
179246
  let opts = _opts;
@@ -179394,7 +179392,7 @@ var require_src4 = __commonJS({
179394
179392
  debug3("Destroying agent %o", this.constructor.name);
179395
179393
  }
179396
179394
  }
179397
- createAgent2.Agent = Agent3;
179395
+ createAgent2.Agent = Agent4;
179398
179396
  createAgent2.prototype = createAgent2.Agent.prototype;
179399
179397
  })(createAgent || (createAgent = {}));
179400
179398
  module2.exports = createAgent;
@@ -217671,7 +217669,6 @@ __decorate7([
217671
217669
  __metadata6("design:type", Number)
217672
217670
  ], RecordingEvent.prototype, "id", void 0);
217673
217671
  __decorate7([
217674
- Index(),
217675
217672
  Column({ type: "varchar", length: 64 }),
217676
217673
  __metadata6("design:type", String)
217677
217674
  ], RecordingEvent.prototype, "sessionId", void 0);
@@ -217696,7 +217693,8 @@ __decorate7([
217696
217693
  __metadata6("design:type", Date)
217697
217694
  ], RecordingEvent.prototype, "createdAt", void 0);
217698
217695
  RecordingEvent = __decorate7([
217699
- Entity("recording_events")
217696
+ Entity("recording_events"),
217697
+ Index("IDX_recording_events_session_lookup", ["sessionId", "createdAt", "sourceUrl", "tabId"])
217700
217698
  ], RecordingEvent);
217701
217699
 
217702
217700
  // dist/.server-tsc/jobcase/jobcase.entity.js
@@ -222321,7 +222319,7 @@ var AuthService = AuthService_1 = class AuthService2 {
222321
222319
  const decodedEmail = decoded?.data?.email ?? email ?? "";
222322
222320
  const existing = await this.saasTokenRepo.findOne({ where: { hmUserId } });
222323
222321
  if (existing) {
222324
- await this.saasTokenRepo.update({ id: existing.id }, { token, email: decodedEmail });
222322
+ await this.saasTokenRepo.update({ id: existing.id }, { token, email: decodedEmail, savedAt: /* @__PURE__ */ new Date() });
222325
222323
  } else {
222326
222324
  await this.saasTokenRepo.save({ hmUserId, email: decodedEmail, token });
222327
222325
  }
@@ -222815,11 +222813,13 @@ var DatasyncService = class DatasyncService2 {
222815
222813
  changeLog;
222816
222814
  tenant;
222817
222815
  logger = new import_common18.Logger(DatasyncService_1.name);
222818
- static SYNC_VIEW_TTL_MS = 2e4;
222816
+ static SYNC_VIEW_TTL_MS = 6e4;
222819
222817
  static SYNC_VIEW_STALE_GRACE_MS = 6e5;
222818
+ static SYNC_VIEW_ERROR_CACHE_MS = 6e4;
222820
222819
  timer;
222821
222820
  syncViewCache = null;
222822
222821
  syncViewRefresh = null;
222822
+ syncViewError = null;
222823
222823
  pushing = false;
222824
222824
  pulling = false;
222825
222825
  authFailed = false;
@@ -223016,9 +223016,22 @@ var DatasyncService = class DatasyncService2 {
223016
223016
  return { ...base, loggedIn: true, ...cached2.view, activeTenantId: await this.getActiveTenantId() };
223017
223017
  }
223018
223018
  }
223019
+ const lastErr = this.syncViewError;
223020
+ if (lastErr && lastErr.uid === uid && Date.now() - lastErr.at < DatasyncService_1.SYNC_VIEW_ERROR_CACHE_MS) {
223021
+ return { ...base, loggedIn: true, remoteError: lastErr.message };
223022
+ }
223019
223023
  try {
223024
+ if (this.syncViewRefresh) {
223025
+ await this.syncViewRefresh;
223026
+ const refreshed = this.syncViewCache;
223027
+ if (refreshed && refreshed.uid === uid) {
223028
+ return { ...base, loggedIn: true, ...refreshed.view, activeTenantId: await this.getActiveTenantId() };
223029
+ }
223030
+ throw new Error("sync view refresh failed");
223031
+ }
223020
223032
  const view = await this.fetchSyncView(uid, token.token);
223021
223033
  this.syncViewCache = { uid, at: Date.now(), view };
223034
+ this.syncViewError = null;
223022
223035
  return {
223023
223036
  ...base,
223024
223037
  loggedIn: true,
@@ -223026,12 +223039,14 @@ var DatasyncService = class DatasyncService2 {
223026
223039
  activeTenantId: await this.getActiveTenantId()
223027
223040
  };
223028
223041
  } catch (err) {
223042
+ this.syncViewError = { uid, message: err.message ?? String(err), at: Date.now() };
223029
223043
  return { ...base, loggedIn: true, remoteError: err.message ?? String(err) };
223030
223044
  }
223031
223045
  }
223032
223046
  async fetchSyncView(uid, jwt5) {
223033
223047
  const res = await fetch(`${this.saasBaseUrl}/hunter-mate/sync/state?heads=0`, {
223034
- headers: { Authorization: `HMJWT ${jwt5}` }
223048
+ headers: { Authorization: `HMJWT ${jwt5}` },
223049
+ signal: AbortSignal.timeout(1e4)
223035
223050
  });
223036
223051
  if (!res.ok)
223037
223052
  throw new Error(`HTTP ${res.status}`);
@@ -223077,6 +223092,7 @@ var DatasyncService = class DatasyncService2 {
223077
223092
  "Content-Type": "application/json",
223078
223093
  Authorization: `HMJWT ${token.token}`
223079
223094
  },
223095
+ signal: AbortSignal.timeout(3e4),
223080
223096
  ...body !== void 0 ? { body: JSON.stringify(body) } : {}
223081
223097
  });
223082
223098
  const text = await res.text();
@@ -223343,19 +223359,23 @@ var DatasyncService = class DatasyncService2 {
223343
223359
  await this.reconcileMembership(token.token);
223344
223360
  await this.syncTenantMembers(token.token);
223345
223361
  const myId = this.hmUserIdOf(token.token);
223346
- for (const cfg of SYNC_REGISTRY) {
223347
- if (cfg.direction !== "both")
223348
- continue;
223349
- const table = this.tableOf(cfg);
223350
- try {
223351
- const r = await this.pullEntity(cfg, token.token, myId);
223352
- result[table] = `${r.applied}u/${r.conflicts}c/${r.deleted}d/${r.pooled}p`;
223353
- } catch (err) {
223354
- const msg = err.message ?? String(err);
223355
- this.logger.warn(`pull entity ${table} failed: ${msg}`);
223356
- result[table] = `ERR: ${msg}`;
223362
+ const targets = SYNC_REGISTRY.filter((c) => c.direction === "both");
223363
+ const CONCURRENCY = 4;
223364
+ let next = 0;
223365
+ await Promise.all(Array.from({ length: Math.min(CONCURRENCY, targets.length) }, async () => {
223366
+ while (next < targets.length) {
223367
+ const cfg = targets[next++];
223368
+ const table = this.tableOf(cfg);
223369
+ try {
223370
+ const r = await this.pullEntity(cfg, token.token, myId);
223371
+ result[table] = `${r.applied}u/${r.conflicts}c/${r.deleted}d/${r.pooled}p`;
223372
+ } catch (err) {
223373
+ const msg = err.message ?? String(err);
223374
+ this.logger.warn(`pull entity ${table} failed: ${msg}`);
223375
+ result[table] = `ERR: ${msg}`;
223376
+ }
223357
223377
  }
223358
- }
223378
+ }));
223359
223379
  return result;
223360
223380
  } finally {
223361
223381
  this.pulling = false;
@@ -223363,8 +223383,9 @@ var DatasyncService = class DatasyncService2 {
223363
223383
  }
223364
223384
  async reconcileMembership(jwt5) {
223365
223385
  try {
223366
- const res = await fetch(`${this.saasBaseUrl}/hunter-mate/sync/state`, {
223367
- headers: { Authorization: `HMJWT ${jwt5}` }
223386
+ const res = await fetch(`${this.saasBaseUrl}/hunter-mate/sync/state?heads=0`, {
223387
+ headers: { Authorization: `HMJWT ${jwt5}` },
223388
+ signal: AbortSignal.timeout(3e4)
223368
223389
  });
223369
223390
  if (res.status === 401) {
223370
223391
  this.authFailed = true;
@@ -224528,6 +224549,7 @@ SearchlogController = __decorate73([
224528
224549
  var import_common31 = __toESM(require_common(), 1);
224529
224550
  var import_axios4 = __toESM(require_axios2(), 1);
224530
224551
  var import_typeorm69 = __toESM(require_typeorm2(), 1);
224552
+ import { Agent } from "https";
224531
224553
 
224532
224554
  // dist/.server-tsc/auth/auth.controller.js
224533
224555
  var import_common26 = __toESM(require_common(), 1);
@@ -224881,7 +224903,15 @@ var AuthModule = class AuthModule2 {
224881
224903
  };
224882
224904
  AuthModule = __decorate79([
224883
224905
  (0, import_common31.Module)({
224884
- imports: [import_axios4.HttpModule.register({ proxy: false }), import_typeorm69.TypeOrmModule.forFeature([SaasToken]), OpLogModule],
224906
+ imports: [
224907
+ import_axios4.HttpModule.register({
224908
+ proxy: false,
224909
+ timeout: 15e3,
224910
+ httpsAgent: new Agent({ keepAlive: true, maxSockets: 8 })
224911
+ }),
224912
+ import_typeorm69.TypeOrmModule.forFeature([SaasToken]),
224913
+ OpLogModule
224914
+ ],
224885
224915
  providers: [AuthService, OptionalAuthMiddleware],
224886
224916
  controllers: [AuthController],
224887
224917
  exports: [AuthService]
@@ -245985,7 +246015,7 @@ import * as tls from "node:tls";
245985
246015
  import * as http3 from "node:http";
245986
246016
  var _a;
245987
246017
  var INTERNAL = /* @__PURE__ */ Symbol("AgentBaseInternalState");
245988
- var Agent2 = class extends (_a = http3.Agent, _a) {
246018
+ var Agent3 = class extends (_a = http3.Agent, _a) {
245989
246019
  constructor(opts) {
245990
246020
  super(opts);
245991
246021
  this[INTERNAL] = {};
@@ -246132,7 +246162,7 @@ function parseProxyResponse(socket) {
246132
246162
  function debugLog2(...args) {
246133
246163
  debug.log("[https-proxy-agent]", ...args);
246134
246164
  }
246135
- var HttpsProxyAgent = class extends Agent2 {
246165
+ var HttpsProxyAgent = class extends Agent3 {
246136
246166
  constructor(proxy, opts) {
246137
246167
  super(opts);
246138
246168
  this.options = {};
@@ -265089,7 +265119,11 @@ var __param25 = function(paramIndex, decorator) {
265089
265119
  decorator(target, key, paramIndex);
265090
265120
  };
265091
265121
  };
265122
+ var RecordingService_1;
265092
265123
  var RecordingService = class RecordingService2 {
265124
+ static {
265125
+ RecordingService_1 = this;
265126
+ }
265093
265127
  eventRepo;
265094
265128
  snapshotService;
265095
265129
  eventBus;
@@ -265171,8 +265205,10 @@ var RecordingService = class RecordingService2 {
265171
265205
  }
265172
265206
  return { sessionId, eventsDeleted, snapshotsDeleted };
265173
265207
  }
265208
+ static DEFAULT_WINDOW_MS = 90 * 24 * 60 * 60 * 1e3;
265174
265209
  async listRecordings(limit = 100, options = {}) {
265175
- const { q, from, to } = options;
265210
+ const { q, to } = options;
265211
+ const from = options.from ?? (!to ? new Date(Date.now() - RecordingService_1.DEFAULT_WINDOW_MS) : void 0);
265176
265212
  const qb = this.eventRepo.createQueryBuilder("e").select("e.sessionId", "sessionId").addSelect("COUNT(*)", "eventCount").addSelect("MIN(e.createdAt)", "startedAt").addSelect("MAX(e.createdAt)", "lastEventAt").addSelect("MAX(e.sourceUrl)", "sourceUrl").addSelect("MAX(e.tabId)", "tabId").groupBy("e.sessionId");
265177
265213
  if (from)
265178
265214
  qb.andWhere("e.createdAt >= :from", { from });
@@ -265197,7 +265233,7 @@ var RecordingService = class RecordingService2 {
265197
265233
  };
265198
265234
  }
265199
265235
  };
265200
- RecordingService = __decorate94([
265236
+ RecordingService = RecordingService_1 = __decorate94([
265201
265237
  (0, import_common51.Injectable)(),
265202
265238
  __param25(0, (0, import_typeorm79.InjectRepository)(RecordingEvent)),
265203
265239
  __metadata80("design:paramtypes", [
@@ -265855,7 +265891,7 @@ async function pool(items, limit, fn) {
265855
265891
  });
265856
265892
  await Promise.all(workers);
265857
265893
  }
265858
- async function folderSize(dir) {
265894
+ async function sizeOfDir(dir) {
265859
265895
  let total = 0;
265860
265896
  let entries;
265861
265897
  try {
@@ -265867,7 +265903,7 @@ async function folderSize(dir) {
265867
265903
  const full = path6.join(dir, ent.name);
265868
265904
  try {
265869
265905
  if (ent.isDirectory()) {
265870
- const sub = await folderSize(full);
265906
+ const sub = await sizeOfDir(full);
265871
265907
  total += sub;
265872
265908
  } else if (ent.isFile()) {
265873
265909
  const st = await fsp.stat(full);
@@ -265878,19 +265914,19 @@ async function folderSize(dir) {
265878
265914
  });
265879
265915
  return total;
265880
265916
  }
265881
- async function topLevelBreakdown(dir, limit = TOP_ENTRIES_LIMIT) {
265917
+ async function sizeWithBreakdown(dir, limit = TOP_ENTRIES_LIMIT) {
265882
265918
  let entries;
265883
265919
  try {
265884
265920
  entries = await fsp.readdir(dir, { withFileTypes: true });
265885
265921
  } catch {
265886
- return [];
265922
+ return { totalBytes: 0, topEntries: [] };
265887
265923
  }
265888
265924
  const sized = [];
265889
265925
  await pool(entries, WALK_CONCURRENCY, async (ent) => {
265890
265926
  const full = path6.join(dir, ent.name);
265891
265927
  try {
265892
265928
  if (ent.isDirectory()) {
265893
- const sub = await folderSize(full);
265929
+ const sub = await sizeOfDir(full);
265894
265930
  sized.push({ name: ent.name + "/", bytes: sub });
265895
265931
  } else if (ent.isFile()) {
265896
265932
  const st = await fsp.stat(full);
@@ -265899,13 +265935,14 @@ async function topLevelBreakdown(dir, limit = TOP_ENTRIES_LIMIT) {
265899
265935
  } catch {
265900
265936
  }
265901
265937
  });
265938
+ const totalBytes = sized.reduce((acc, e) => acc + e.bytes, 0);
265902
265939
  sized.sort((a, b2) => b2.bytes - a.bytes);
265903
265940
  if (sized.length <= limit)
265904
- return sized;
265941
+ return { totalBytes, topEntries: sized };
265905
265942
  const head = sized.slice(0, limit);
265906
265943
  const restBytes = sized.slice(limit).reduce((acc, e) => acc + e.bytes, 0);
265907
265944
  head.push({ name: `others(${sized.length - limit})`, bytes: restBytes });
265908
- return head;
265945
+ return { totalBytes, topEntries: head };
265909
265946
  }
265910
265947
  function findInstallRoot(startDir, maxUp = 6) {
265911
265948
  let dir = startDir;
@@ -265972,27 +266009,26 @@ var ResourceCollector = ResourceCollector_1 = class ResourceCollector2 {
265972
266009
  }
265973
266010
  async collectPaths(specs = this.resolvePathSpecs()) {
265974
266011
  const out = [];
265975
- for (const spec of specs) {
266012
+ let slot = 0;
266013
+ await pool(specs, WALK_CONCURRENCY, async (spec) => {
266014
+ const idx = slot++;
265976
266015
  try {
265977
266016
  if (!fs7.existsSync(spec.path)) {
265978
- out.push({ key: spec.key, path: spec.path, exists: false, totalBytes: 0, topEntries: [], group: spec.group });
265979
- continue;
266017
+ out[idx] = { key: spec.key, path: spec.path, exists: false, totalBytes: 0, topEntries: [], group: spec.group };
266018
+ return;
265980
266019
  }
265981
266020
  const st = await fsp.stat(spec.path);
265982
266021
  if (st.isFile()) {
265983
- out.push({ key: spec.key, path: spec.path, exists: true, totalBytes: st.size, topEntries: [], group: spec.group });
265984
- continue;
266022
+ out[idx] = { key: spec.key, path: spec.path, exists: true, totalBytes: st.size, topEntries: [], group: spec.group };
266023
+ return;
265985
266024
  }
265986
- const [totalBytes, topEntries] = await Promise.all([
265987
- folderSize(spec.path),
265988
- topLevelBreakdown(spec.path)
265989
- ]);
265990
- out.push({ key: spec.key, path: spec.path, exists: true, totalBytes, topEntries, group: spec.group });
266025
+ const { totalBytes, topEntries } = await sizeWithBreakdown(spec.path);
266026
+ out[idx] = { key: spec.key, path: spec.path, exists: true, totalBytes, topEntries, group: spec.group };
265991
266027
  } catch (err) {
265992
266028
  this.logger.warn(`\u91C7\u96C6\u8DEF\u5F84\u5360\u7528\u5931\u8D25 ${spec.path}: ${err.message}`);
265993
- out.push({ key: spec.key, path: spec.path, exists: false, totalBytes: 0, topEntries: [], group: spec.group });
266029
+ out[idx] = { key: spec.key, path: spec.path, exists: false, totalBytes: 0, topEntries: [], group: spec.group };
265994
266030
  }
265995
- }
266031
+ });
265996
266032
  return out;
265997
266033
  }
265998
266034
  async collectProcesses() {
@@ -291376,6 +291412,9 @@ ExtractionRuleService = __decorate101([
291376
291412
  ], ExtractionRuleService);
291377
291413
 
291378
291414
  // dist/.server-tsc/extraction/structured-data.js
291415
+ function toCheerio(html) {
291416
+ return typeof html === "string" ? load(html) : html;
291417
+ }
291379
291418
  function pageClassFromJsonLdTypes(types2) {
291380
291419
  const t = new Set(types2.map((x) => x.toLowerCase()));
291381
291420
  if (t.has("person"))
@@ -291411,7 +291450,7 @@ function flattenEntity(entity, prefix = "", out = {}) {
291411
291450
  return out;
291412
291451
  }
291413
291452
  function extractJsonLd(html) {
291414
- const $ = load(html);
291453
+ const $ = toCheerio(html);
291415
291454
  const entities = [];
291416
291455
  $('script[type="application/ld+json"]').each((_i, el) => {
291417
291456
  try {
@@ -291441,7 +291480,7 @@ function extractJsonLd(html) {
291441
291480
  return { types: types2, data };
291442
291481
  }
291443
291482
  function extractOpenGraph(html) {
291444
- const $ = load(html);
291483
+ const $ = toCheerio(html);
291445
291484
  const out = {};
291446
291485
  $('meta[property^="og:"], meta[name^="og:"]').each((_i, el) => {
291447
291486
  const key = $(el).attr("property") || $(el).attr("name") || "";
@@ -291546,7 +291585,7 @@ function applySelectorRule(payload, html) {
291546
291585
  if (payload?.fields || payload?.lists || payload?.entityList) {
291547
291586
  return applyScriptRule(html, payload);
291548
291587
  }
291549
- const $ = load(html);
291588
+ const $ = typeof html === "string" ? load(html) : html;
291550
291589
  const result = {};
291551
291590
  const mapping = payload.mapping || {};
291552
291591
  for (const [field, selector] of Object.entries(mapping)) {
@@ -291628,13 +291667,14 @@ var ExtractionService = class ExtractionService2 {
291628
291667
  applyRulesToHtml(sourceUrl, html, rules) {
291629
291668
  const matched = rules.filter((r) => r.enabled && matchRule(r, sourceUrl)).sort((a, b2) => b2.priority - a.priority);
291630
291669
  const extracted = {};
291670
+ const $ = load(html);
291631
291671
  for (const rule of matched) {
291632
291672
  if (rule.ruleType === "selector")
291633
- Object.assign(extracted, applySelectorRule(rule.rulePayload, html));
291673
+ Object.assign(extracted, applySelectorRule(rule.rulePayload, $));
291634
291674
  else if (rule.ruleType === "regex")
291635
291675
  Object.assign(extracted, applyRegexRule(rule.rulePayload, html));
291636
291676
  else if (rule.ruleType === "script")
291637
- Object.assign(extracted, applyScriptRule(html, rule.rulePayload));
291677
+ Object.assign(extracted, applyScriptRule($, rule.rulePayload));
291638
291678
  }
291639
291679
  this.applyProfileUrlFallback(extracted, sourceUrl, matched);
291640
291680
  return {
@@ -291712,8 +291752,9 @@ var ExtractionService = class ExtractionService2 {
291712
291752
  });
291713
291753
  return { ...result, status: "no-snapshot", message: "Missing sourceUrl or rrweb full snapshot." };
291714
291754
  }
291715
- const jsonld = extractJsonLd(html);
291716
- const og = extractOpenGraph(html);
291755
+ const $ = load(html);
291756
+ const jsonld = extractJsonLd($);
291757
+ const og = extractOpenGraph($);
291717
291758
  const rules = await this.ruleService.findEnabled();
291718
291759
  const adapterRules = (await this.adapterRuleRepo.find({ where: { enabled: true } })).map((r) => ({
291719
291760
  ruleId: r.externalId || `${r.platform}/${r.hostPattern}`,
@@ -291730,11 +291771,11 @@ var ExtractionService = class ExtractionService2 {
291730
291771
  const ruleExtracted = {};
291731
291772
  for (const rule of matched) {
291732
291773
  if (rule.ruleType === "selector")
291733
- Object.assign(ruleExtracted, applySelectorRule(rule.rulePayload, html));
291774
+ Object.assign(ruleExtracted, applySelectorRule(rule.rulePayload, $));
291734
291775
  else if (rule.ruleType === "regex")
291735
291776
  Object.assign(ruleExtracted, applyRegexRule(rule.rulePayload, html));
291736
291777
  else if (rule.ruleType === "script")
291737
- Object.assign(ruleExtracted, applyScriptRule(html, rule.rulePayload));
291778
+ Object.assign(ruleExtracted, applyScriptRule($, rule.rulePayload));
291738
291779
  }
291739
291780
  const merged = { ...og, ...jsonld?.data || {}, ...ruleExtracted };
291740
291781
  for (const [k2, v] of Object.entries({ ...jsonld?.data || {}, ...og || {} })) {
@@ -292086,8 +292127,9 @@ var ExtractionService = class ExtractionService2 {
292086
292127
  return { sessionId, error: "missing snapshot or sourceUrl" };
292087
292128
  }
292088
292129
  const parsed = new URL(sourceUrl);
292089
- const jsonld = extractJsonLd(html);
292090
- const og = extractOpenGraph(html);
292130
+ const $ = load(html);
292131
+ const jsonld = extractJsonLd($);
292132
+ const og = extractOpenGraph($);
292091
292133
  const pageClass = jsonld ? pageClassFromJsonLdTypes(jsonld.types) : null;
292092
292134
  const draft = {
292093
292135
  ruleId: `${etldPlus1(parsed.hostname).replace(/\./g, "-")}-${pageClass || "page"}-auto`,
@@ -294489,6 +294531,8 @@ var AdapterService = class AdapterService2 {
294489
294531
  const sourceUrl = snapshot.sourceUrl || "";
294490
294532
  const html = snapshot.html;
294491
294533
  const matched = sourceUrl ? await this.findRulesForUrl(sourceUrl) : [];
294534
+ let cached$ = null;
294535
+ const $ = () => cached$ ??= load(html);
294492
294536
  const ruleExtracted = {};
294493
294537
  const isEmptyVal = (v) => v == null || v === "" || Array.isArray(v) && v.length === 0;
294494
294538
  const mergeRuleOutput = (out) => {
@@ -294502,15 +294546,13 @@ var AdapterService = class AdapterService2 {
294502
294546
  if (rule.ruleType === "selector") {
294503
294547
  const payload = rule.rulePayload;
294504
294548
  if (payload?.fields || payload?.lists) {
294505
- const { applyScriptRule: applyScriptRule2 } = await import("./chunks/script-rule-ZJN6CEYX.mjs");
294506
- mergeRuleOutput(applyScriptRule2(html, payload));
294549
+ const { applyScriptRule: applyScriptRule2 } = await import("./chunks/script-rule-4RZQ2PQE.mjs");
294550
+ mergeRuleOutput(applyScriptRule2($(), payload));
294507
294551
  } else {
294508
- const { load: load2 } = await import("./chunks/esm-4U746B76.mjs");
294509
- const $ = load2(html);
294510
294552
  const mapping = payload.mapping || {};
294511
294553
  const out = {};
294512
294554
  for (const [field, selector] of Object.entries(mapping)) {
294513
- const el = $(selector).first();
294555
+ const el = $()(selector).first();
294514
294556
  out[field] = el.text().trim() || el.attr("content") || el.attr("value") || null;
294515
294557
  }
294516
294558
  mergeRuleOutput(out);
@@ -294524,13 +294566,13 @@ var AdapterService = class AdapterService2 {
294524
294566
  }
294525
294567
  mergeRuleOutput(out);
294526
294568
  } else if (rule.ruleType === "script") {
294527
- const { applyScriptRule: applyScriptRule2 } = await import("./chunks/script-rule-ZJN6CEYX.mjs");
294528
- mergeRuleOutput(applyScriptRule2(html, rule.rulePayload));
294569
+ const { applyScriptRule: applyScriptRule2 } = await import("./chunks/script-rule-4RZQ2PQE.mjs");
294570
+ mergeRuleOutput(applyScriptRule2($(), rule.rulePayload));
294529
294571
  } else if (rule.ruleType === "jsonld") {
294530
294572
  }
294531
294573
  }
294532
- const jsonld = extractJsonLd(html);
294533
- const og = extractOpenGraph(html);
294574
+ const jsonld = extractJsonLd($());
294575
+ const og = extractOpenGraph($());
294534
294576
  const merged = { ...og, ...jsonld?.data || {}, ...ruleExtracted };
294535
294577
  for (const [k2, v] of Object.entries({ ...jsonld?.data || {}, ...og || {} })) {
294536
294578
  if (ruleExtracted[k2] == null && v != null)
@@ -305346,6 +305388,11 @@ var CustomerService = class CustomerService2 {
305346
305388
  datasync;
305347
305389
  tenant;
305348
305390
  logger = new import_common136.Logger(CustomerService_1.name);
305391
+ static COLLECT_TTL_MS = 6e4;
305392
+ collectCache = null;
305393
+ invalidateCollectCache() {
305394
+ this.collectCache = null;
305395
+ }
305349
305396
  constructor(repo, jobCaseRepo, remarkRepo, companyProfileRepo, talentProfileRepo, jobPostingRepo, parseLogRepo, datasync, tenant) {
305350
305397
  this.repo = repo;
305351
305398
  this.jobCaseRepo = jobCaseRepo;
@@ -305358,7 +305405,9 @@ var CustomerService = class CustomerService2 {
305358
305405
  this.tenant = tenant;
305359
305406
  }
305360
305407
  async batchDelete(ids) {
305361
- return this.datasync.deleteWithTombstones(this.repo, "customers", ids);
305408
+ const result = await this.datasync.deleteWithTombstones(this.repo, "customers", ids);
305409
+ this.invalidateCollectCache();
305410
+ return result;
305362
305411
  }
305363
305412
  async onModuleInit() {
305364
305413
  await this.repo.query("UPDATE customers SET isCustomer = 1 WHERE isCustomer IS NULL");
@@ -305439,6 +305488,7 @@ var CustomerService = class CustomerService2 {
305439
305488
  if (changed) {
305440
305489
  customer.aliases = [...aliases];
305441
305490
  await this.repo.save(customer);
305491
+ this.invalidateCollectCache();
305442
305492
  }
305443
305493
  return { customer, created: false, merged: true };
305444
305494
  };
@@ -305472,6 +305522,7 @@ var CustomerService = class CustomerService2 {
305472
305522
  });
305473
305523
  try {
305474
305524
  const saved = await this.repo.save(entity);
305525
+ this.invalidateCollectCache();
305475
305526
  return { customer: saved, created: true, merged: false };
305476
305527
  } catch (err) {
305477
305528
  if (String(err?.code).startsWith("SQLITE_CONSTRAINT")) {
@@ -305521,7 +305572,9 @@ var CustomerService = class CustomerService2 {
305521
305572
  }
305522
305573
  customer.profile = next;
305523
305574
  }
305524
- return this.repo.save(customer);
305575
+ const saved = await this.repo.save(customer);
305576
+ this.invalidateCollectCache();
305577
+ return saved;
305525
305578
  }
305526
305579
  async duplicates(id) {
305527
305580
  const customer = await this.findOne(id);
@@ -305595,6 +305648,7 @@ var CustomerService = class CustomerService2 {
305595
305648
  if ((keep.isCustomer ?? 0) !== 1 && (remove.isCustomer ?? 0) === 1)
305596
305649
  keep.isCustomer = 1;
305597
305650
  await this.repo.save(keep);
305651
+ this.invalidateCollectCache();
305598
305652
  await this.jobCaseRepo.update({ customerId: removeId }, { customerId: keepId });
305599
305653
  await this.remarkRepo.update({ targetType: "customer", targetId: String(removeId) }, { targetId: String(keepId) });
305600
305654
  await this.datasync.deleteWithTombstones(this.repo, "customers", [removeId]);
@@ -305618,7 +305672,15 @@ var CustomerService = class CustomerService2 {
305618
305672
  });
305619
305673
  return [...new Set(parts)];
305620
305674
  }
305621
- async collectCompanies() {
305675
+ async collectCompanies(force = false) {
305676
+ if (!force && this.collectCache && Date.now() - this.collectCache.at < CustomerService_1.COLLECT_TTL_MS) {
305677
+ return this.collectCache.result;
305678
+ }
305679
+ const result = await this.runCollectCompanies();
305680
+ this.collectCache = { at: Date.now(), result };
305681
+ return result;
305682
+ }
305683
+ async runCollectCompanies() {
305622
305684
  const talents = await this.talentProfileRepo.find();
305623
305685
  const talentNames = new Set(talents.map((t) => (t.name ?? "").trim().toLowerCase()).filter(Boolean));
305624
305686
  const existing = await this.repo.find();
@@ -305656,7 +305718,7 @@ var CustomerService = class CustomerService2 {
305656
305718
  }
305657
305719
  }
305658
305720
  const profileKeys = /* @__PURE__ */ new Set();
305659
- for (const p of await this.companyProfileRepo.find()) {
305721
+ for (const p of profiles) {
305660
305722
  const k2 = normalizeCustomerName(p.name ?? "");
305661
305723
  if (k2)
305662
305724
  profileKeys.add(k2);
@@ -305671,7 +305733,9 @@ var CustomerService = class CustomerService2 {
305671
305733
  }
305672
305734
  }
305673
305735
  const caseCustomerIds = new Set((await this.jobCaseRepo.find({ select: ["customerId"] })).map((jc) => jc.customerId).filter((id) => id != null));
305674
- for (const c of await this.repo.find()) {
305736
+ for (const c of await this.repo.find({
305737
+ select: ["id", "canonicalName", "dedupKey", "aliases", "isCustomer", "ownerId"]
305738
+ })) {
305675
305739
  if (!(c.canonicalName ?? "").trim()) {
305676
305740
  if (caseCustomerIds.has(c.id))
305677
305741
  continue;
@@ -305707,13 +305771,13 @@ var CustomerService = class CustomerService2 {
305707
305771
  qb.select([...CustomerService_1.LIST_COLS]);
305708
305772
  const matched = await qb.getMany();
305709
305773
  const profileKeys = /* @__PURE__ */ new Set();
305710
- for (const p of await this.companyProfileRepo.find()) {
305774
+ for (const p of await this.companyProfileRepo.find({ select: ["name"] })) {
305711
305775
  const k2 = normalizeCustomerName(p.name ?? "");
305712
305776
  if (k2)
305713
305777
  profileKeys.add(k2);
305714
305778
  }
305715
305779
  const resumeKeys = /* @__PURE__ */ new Set();
305716
- for (const t of await this.talentProfileRepo.find()) {
305780
+ for (const t of await this.talentProfileRepo.find({ select: ["extracted"] })) {
305717
305781
  const ex = t.extracted ?? {};
305718
305782
  for (const cand of this.parseResumeCompanies(String(ex.currentCompany ?? ex.company ?? ""))) {
305719
305783
  const k2 = normalizeCustomerName(cand);
@@ -305724,15 +305788,15 @@ var CustomerService = class CustomerService2 {
305724
305788
  const caseCount = /* @__PURE__ */ new Map();
305725
305789
  const activeCount = /* @__PURE__ */ new Map();
305726
305790
  const hmhLocal = /* @__PURE__ */ new Set();
305727
- for (const jc of await this.jobCaseRepo.find()) {
305728
- if (jc.customerId == null)
305729
- continue;
305730
- caseCount.set(jc.customerId, (caseCount.get(jc.customerId) ?? 0) + 1);
305731
- if (jc.status === "active") {
305732
- activeCount.set(jc.customerId, (activeCount.get(jc.customerId) ?? 0) + 1);
305733
- }
305734
- if ((jc.folderPath ?? "").includes("/local/clients/"))
305735
- hmhLocal.add(jc.customerId);
305791
+ const caseRows = await this.jobCaseRepo.createQueryBuilder("jc").select("jc.customerId", "customerId").addSelect("COUNT(*)", "cnt").addSelect("SUM(CASE WHEN jc.status = 'active' THEN 1 ELSE 0 END)", "activeCnt").addSelect("MAX(CASE WHEN jc.folderPath LIKE '%/local/clients/%' THEN 1 ELSE 0 END)", "hmhFlag").where("jc.customerId IS NOT NULL").groupBy("jc.customerId").getRawMany();
305792
+ for (const r of caseRows) {
305793
+ const id = Number(r.customerId);
305794
+ caseCount.set(id, Number(r.cnt));
305795
+ const active = Number(r.activeCnt ?? 0);
305796
+ if (active)
305797
+ activeCount.set(id, active);
305798
+ if (Number(r.hmhFlag ?? 0))
305799
+ hmhLocal.add(id);
305736
305800
  }
305737
305801
  const decorated = matched.map((c) => {
305738
305802
  const keys = [c.dedupKey, ...(c.aliases ?? []).map((a) => normalizeCustomerName(a))];
@@ -305878,7 +305942,7 @@ var CustomerController = class CustomerController2 {
305878
305942
  });
305879
305943
  }
305880
305944
  collect() {
305881
- return this.service.collectCompanies();
305945
+ return this.service.collectCompanies(true);
305882
305946
  }
305883
305947
  batchDelete(body) {
305884
305948
  const ids = this.parseBatchIds(body);
@@ -306701,8 +306765,9 @@ var ResourceUsageController = class ResourceUsageController2 {
306701
306765
  }
306702
306766
  async collectNow() {
306703
306767
  const snapshot = await this.service.collectNow();
306704
- const report = await this.service.reportUnreported();
306705
- return { ok: true, snapshot, report };
306768
+ this.service.reportUnreported().catch(() => {
306769
+ });
306770
+ return { ok: true, snapshot };
306706
306771
  }
306707
306772
  pending() {
306708
306773
  return this.service.pendingCount().then((count2) => ({ count: count2 }));