hunter-mate 0.1.23 → 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 (56) 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 +220 -105
  6. package/dist/index.js +221 -38
  7. package/dist/web/dist/404.html +1 -1
  8. package/dist/web/dist/_next/static/chunks/253-a05d05b94bfbd7a4.js +1 -0
  9. package/dist/web/dist/_next/static/chunks/{852-248884963a986600.js → 852-ad19b97821a4cf9e.js} +1 -1
  10. package/dist/web/dist/_next/static/chunks/app/companies/{page-ec27ce9ab3610221.js → page-e8d02fe997579315.js} +1 -1
  11. package/dist/web/dist/_next/static/chunks/app/jobs/page-4827a9ef286b6483.js +1 -0
  12. package/dist/web/dist/_next/static/chunks/app/talents/{page-c0a0c250eb5f5459.js → page-0edef6d07b3cf69d.js} +1 -1
  13. package/dist/web/dist/_next/static/css/10ba1fa1d6ce23a7.css +3 -0
  14. package/dist/web/dist/admin/data.html +1 -1
  15. package/dist/web/dist/admin/data.txt +1 -1
  16. package/dist/web/dist/auth/verify.html +1 -1
  17. package/dist/web/dist/auth/verify.txt +1 -1
  18. package/dist/web/dist/companies.html +1 -1
  19. package/dist/web/dist/companies.txt +2 -2
  20. package/dist/web/dist/company/admin.html +1 -1
  21. package/dist/web/dist/company/admin.txt +1 -1
  22. package/dist/web/dist/entity.html +1 -1
  23. package/dist/web/dist/entity.txt +1 -1
  24. package/dist/web/dist/index.html +1 -1
  25. package/dist/web/dist/index.txt +1 -1
  26. package/dist/web/dist/jobs.html +1 -1
  27. package/dist/web/dist/jobs.txt +2 -2
  28. package/dist/web/dist/logs.html +1 -1
  29. package/dist/web/dist/logs.txt +1 -1
  30. package/dist/web/dist/matching/jobs/placeholder/talents.html +1 -1
  31. package/dist/web/dist/matching/jobs/placeholder/talents.txt +1 -1
  32. package/dist/web/dist/matching/portraits/placeholder/jobs.html +1 -1
  33. package/dist/web/dist/matching/portraits/placeholder/jobs.txt +1 -1
  34. package/dist/web/dist/parselog.html +1 -1
  35. package/dist/web/dist/parselog.txt +1 -1
  36. package/dist/web/dist/recordings.html +1 -1
  37. package/dist/web/dist/recordings.txt +1 -1
  38. package/dist/web/dist/resource-usage.html +1 -1
  39. package/dist/web/dist/resource-usage.txt +1 -1
  40. package/dist/web/dist/shared/placeholder.html +1 -1
  41. package/dist/web/dist/shared/placeholder.txt +1 -1
  42. package/dist/web/dist/snapshots/placeholder/agent-prompt.html +1 -1
  43. package/dist/web/dist/snapshots/placeholder/agent-prompt.txt +1 -1
  44. package/dist/web/dist/talents.html +1 -1
  45. package/dist/web/dist/talents.txt +2 -2
  46. package/dist/web/dist/team/insights.html +1 -1
  47. package/dist/web/dist/team/insights.txt +1 -1
  48. package/package.json +1 -1
  49. package/dist/assets/server/chunks/chunk-BLXHCSZD.mjs +0 -565
  50. package/dist/assets/server/chunks/esm-4U746B76.mjs +0 -29
  51. package/dist/web/dist/_next/static/chunks/954-fb0212fe71f60a52.js +0 -1
  52. package/dist/web/dist/_next/static/chunks/app/jobs/page-4175a90f1b42f87d.js +0 -1
  53. package/dist/web/dist/_next/static/css/bd072fee69ae8474.css +0 -3
  54. /package/dist/assets/extension/background/{service-worker.20261016165050.js → service-worker.20261017183328.js} +0 -0
  55. /package/dist/web/dist/_next/static/{a_JzW5lROd6a66UMqSE9Z → 5MA8faUttk6FzlxGWnOlM}/_buildManifest.js +0 -0
  56. /package/dist/web/dist/_next/static/{a_JzW5lROd6a66UMqSE9Z → 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
@@ -221713,6 +221711,17 @@ var JobcaseService = class JobcaseService2 {
221713
221711
  for (const it of items)
221714
221712
  it.rsUserIds = rsMap.get(it.id) ?? [];
221715
221713
  }
221714
+ const custIds = Array.from(new Set(items.map((i) => i.customerId).filter((n) => n != null)));
221715
+ if (custIds.length) {
221716
+ const custs = await this.customerRepo.find({
221717
+ where: { id: In(custIds) },
221718
+ select: ["id", "canonicalName"]
221719
+ });
221720
+ const nameMap = new Map(custs.map((c) => [c.id, c.canonicalName]));
221721
+ for (const it of items) {
221722
+ it.customerName = it.customerId != null ? nameMap.get(it.customerId) ?? null : null;
221723
+ }
221724
+ }
221716
221725
  return { items, total, statusCounts };
221717
221726
  }
221718
221727
  async create(dto) {
@@ -222273,6 +222282,11 @@ var AuthService = AuthService_1 = class AuthService2 {
222273
222282
  expires_in: 60 * 60 * 24 * 7
222274
222283
  };
222275
222284
  }
222285
+ issueStableLocalToken(userId) {
222286
+ const DAY = 86400;
222287
+ const exp = (Math.floor(Date.now() / 1e3 / DAY) + 2) * DAY;
222288
+ return jwt.sign({ data: { _id: userId }, exp }, this.secret, { noTimestamp: true });
222289
+ }
222276
222290
  async sendEmailCode(body) {
222277
222291
  try {
222278
222292
  const res = await (0, import_rxjs2.firstValueFrom)(this.http.post(`${this.saasBaseUrl}/hunter-mate/auth/email/send-code`, body));
@@ -222305,7 +222319,7 @@ var AuthService = AuthService_1 = class AuthService2 {
222305
222319
  const decodedEmail = decoded?.data?.email ?? email ?? "";
222306
222320
  const existing = await this.saasTokenRepo.findOne({ where: { hmUserId } });
222307
222321
  if (existing) {
222308
- 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() });
222309
222323
  } else {
222310
222324
  await this.saasTokenRepo.save({ hmUserId, email: decodedEmail, token });
222311
222325
  }
@@ -222359,7 +222373,7 @@ var AuthService = AuthService_1 = class AuthService2 {
222359
222373
  loggedIn: true,
222360
222374
  email,
222361
222375
  hmUserId,
222362
- token: this.issueLocalToken(hmUserId).access_token
222376
+ token: this.issueStableLocalToken(hmUserId)
222363
222377
  };
222364
222378
  }
222365
222379
  extractUserId(saasToken, data) {
@@ -222799,9 +222813,13 @@ var DatasyncService = class DatasyncService2 {
222799
222813
  changeLog;
222800
222814
  tenant;
222801
222815
  logger = new import_common18.Logger(DatasyncService_1.name);
222802
- static SYNC_VIEW_TTL_MS = 2e4;
222816
+ static SYNC_VIEW_TTL_MS = 6e4;
222817
+ static SYNC_VIEW_STALE_GRACE_MS = 6e5;
222818
+ static SYNC_VIEW_ERROR_CACHE_MS = 6e4;
222803
222819
  timer;
222804
222820
  syncViewCache = null;
222821
+ syncViewRefresh = null;
222822
+ syncViewError = null;
222805
222823
  pushing = false;
222806
222824
  pulling = false;
222807
222825
  authFailed = false;
@@ -222988,23 +223006,32 @@ var DatasyncService = class DatasyncService2 {
222988
223006
  return { ...base, loggedIn: false };
222989
223007
  const uid = this.hmUserIdOf(token.token);
222990
223008
  const cached2 = this.syncViewCache;
222991
- if (cached2 && cached2.uid === uid && Date.now() - cached2.at < DatasyncService_1.SYNC_VIEW_TTL_MS) {
222992
- return { ...base, loggedIn: true, ...cached2.view, activeTenantId: await this.getActiveTenantId() };
223009
+ if (cached2 && cached2.uid === uid) {
223010
+ const age = Date.now() - cached2.at;
223011
+ if (age < DatasyncService_1.SYNC_VIEW_TTL_MS) {
223012
+ return { ...base, loggedIn: true, ...cached2.view, activeTenantId: await this.getActiveTenantId() };
223013
+ }
223014
+ if (age < DatasyncService_1.SYNC_VIEW_STALE_GRACE_MS) {
223015
+ this.kickSyncViewBackgroundRefresh(uid, token.token);
223016
+ return { ...base, loggedIn: true, ...cached2.view, activeTenantId: await this.getActiveTenantId() };
223017
+ }
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 };
222993
223022
  }
222994
223023
  try {
222995
- const res = await fetch(`${this.saasBaseUrl}/hunter-mate/sync/state?heads=0`, {
222996
- headers: { Authorization: `HMJWT ${token.token}` }
222997
- });
222998
- if (!res.ok)
222999
- return { ...base, loggedIn: true, remoteError: `HTTP ${res.status}` };
223000
- const body = await res.json();
223001
- const view = {
223002
- hmUserId: body.hmUserId,
223003
- memberships: body.memberships ?? [],
223004
- serverSuggestedTenantId: body.activeTenantId ?? null,
223005
- heads: []
223006
- };
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
+ }
223032
+ const view = await this.fetchSyncView(uid, token.token);
223007
223033
  this.syncViewCache = { uid, at: Date.now(), view };
223034
+ this.syncViewError = null;
223008
223035
  return {
223009
223036
  ...base,
223010
223037
  loggedIn: true,
@@ -223012,9 +223039,42 @@ var DatasyncService = class DatasyncService2 {
223012
223039
  activeTenantId: await this.getActiveTenantId()
223013
223040
  };
223014
223041
  } catch (err) {
223042
+ this.syncViewError = { uid, message: err.message ?? String(err), at: Date.now() };
223015
223043
  return { ...base, loggedIn: true, remoteError: err.message ?? String(err) };
223016
223044
  }
223017
223045
  }
223046
+ async fetchSyncView(uid, jwt5) {
223047
+ const res = await fetch(`${this.saasBaseUrl}/hunter-mate/sync/state?heads=0`, {
223048
+ headers: { Authorization: `HMJWT ${jwt5}` },
223049
+ signal: AbortSignal.timeout(1e4)
223050
+ });
223051
+ if (!res.ok)
223052
+ throw new Error(`HTTP ${res.status}`);
223053
+ const body = await res.json();
223054
+ return {
223055
+ hmUserId: body.hmUserId,
223056
+ memberships: body.memberships ?? [],
223057
+ serverSuggestedTenantId: body.activeTenantId ?? null,
223058
+ heads: []
223059
+ };
223060
+ }
223061
+ kickSyncViewBackgroundRefresh(uid, jwt5) {
223062
+ if (this.syncViewRefresh)
223063
+ return;
223064
+ this.syncViewRefresh = (async () => {
223065
+ try {
223066
+ const view = await this.fetchSyncView(uid, jwt5);
223067
+ if (this.syncViewCache?.uid === uid)
223068
+ this.syncViewCache = { uid, at: Date.now(), view };
223069
+ } catch (err) {
223070
+ this.logger.warn(`sync view \u540E\u53F0\u5237\u65B0\u5931\u8D25,\u7F13\u5B58\u5DF2\u6E05(\u4E0B\u56DE\u963B\u585E\u5F0F\u91CD\u8BD5): ${err?.message ?? err}`);
223071
+ if (this.syncViewCache?.uid === uid)
223072
+ this.syncViewCache = null;
223073
+ } finally {
223074
+ this.syncViewRefresh = null;
223075
+ }
223076
+ })();
223077
+ }
223018
223078
  async listVersions(entity) {
223019
223079
  const where = entity ? { entity } : {};
223020
223080
  const rows = await this.versionRepo.find({ where, order: { entity: "ASC", localId: "ASC" } });
@@ -223032,6 +223092,7 @@ var DatasyncService = class DatasyncService2 {
223032
223092
  "Content-Type": "application/json",
223033
223093
  Authorization: `HMJWT ${token.token}`
223034
223094
  },
223095
+ signal: AbortSignal.timeout(3e4),
223035
223096
  ...body !== void 0 ? { body: JSON.stringify(body) } : {}
223036
223097
  });
223037
223098
  const text = await res.text();
@@ -223298,19 +223359,23 @@ var DatasyncService = class DatasyncService2 {
223298
223359
  await this.reconcileMembership(token.token);
223299
223360
  await this.syncTenantMembers(token.token);
223300
223361
  const myId = this.hmUserIdOf(token.token);
223301
- for (const cfg of SYNC_REGISTRY) {
223302
- if (cfg.direction !== "both")
223303
- continue;
223304
- const table = this.tableOf(cfg);
223305
- try {
223306
- const r = await this.pullEntity(cfg, token.token, myId);
223307
- result[table] = `${r.applied}u/${r.conflicts}c/${r.deleted}d/${r.pooled}p`;
223308
- } catch (err) {
223309
- const msg = err.message ?? String(err);
223310
- this.logger.warn(`pull entity ${table} failed: ${msg}`);
223311
- 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
+ }
223312
223377
  }
223313
- }
223378
+ }));
223314
223379
  return result;
223315
223380
  } finally {
223316
223381
  this.pulling = false;
@@ -223318,8 +223383,9 @@ var DatasyncService = class DatasyncService2 {
223318
223383
  }
223319
223384
  async reconcileMembership(jwt5) {
223320
223385
  try {
223321
- const res = await fetch(`${this.saasBaseUrl}/hunter-mate/sync/state`, {
223322
- 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)
223323
223389
  });
223324
223390
  if (res.status === 401) {
223325
223391
  this.authFailed = true;
@@ -223400,7 +223466,7 @@ var DatasyncService = class DatasyncService2 {
223400
223466
  let deleted = 0;
223401
223467
  let pooled = 0;
223402
223468
  let since = cursor.pulledWatermark ?? void 0;
223403
- const LIMIT = 500;
223469
+ const LIMIT = 100;
223404
223470
  for (let page = 0; page < 20; page++) {
223405
223471
  const url2 = new URL(`${this.saasBaseUrl}/hunter-mate/sync/pull`);
223406
223472
  url2.searchParams.set("entity", table);
@@ -224483,6 +224549,7 @@ SearchlogController = __decorate73([
224483
224549
  var import_common31 = __toESM(require_common(), 1);
224484
224550
  var import_axios4 = __toESM(require_axios2(), 1);
224485
224551
  var import_typeorm69 = __toESM(require_typeorm2(), 1);
224552
+ import { Agent } from "https";
224486
224553
 
224487
224554
  // dist/.server-tsc/auth/auth.controller.js
224488
224555
  var import_common26 = __toESM(require_common(), 1);
@@ -224836,7 +224903,15 @@ var AuthModule = class AuthModule2 {
224836
224903
  };
224837
224904
  AuthModule = __decorate79([
224838
224905
  (0, import_common31.Module)({
224839
- 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
+ ],
224840
224915
  providers: [AuthService, OptionalAuthMiddleware],
224841
224916
  controllers: [AuthController],
224842
224917
  exports: [AuthService]
@@ -245940,7 +246015,7 @@ import * as tls from "node:tls";
245940
246015
  import * as http3 from "node:http";
245941
246016
  var _a;
245942
246017
  var INTERNAL = /* @__PURE__ */ Symbol("AgentBaseInternalState");
245943
- var Agent2 = class extends (_a = http3.Agent, _a) {
246018
+ var Agent3 = class extends (_a = http3.Agent, _a) {
245944
246019
  constructor(opts) {
245945
246020
  super(opts);
245946
246021
  this[INTERNAL] = {};
@@ -246087,7 +246162,7 @@ function parseProxyResponse(socket) {
246087
246162
  function debugLog2(...args) {
246088
246163
  debug.log("[https-proxy-agent]", ...args);
246089
246164
  }
246090
- var HttpsProxyAgent = class extends Agent2 {
246165
+ var HttpsProxyAgent = class extends Agent3 {
246091
246166
  constructor(proxy, opts) {
246092
246167
  super(opts);
246093
246168
  this.options = {};
@@ -265044,7 +265119,11 @@ var __param25 = function(paramIndex, decorator) {
265044
265119
  decorator(target, key, paramIndex);
265045
265120
  };
265046
265121
  };
265122
+ var RecordingService_1;
265047
265123
  var RecordingService = class RecordingService2 {
265124
+ static {
265125
+ RecordingService_1 = this;
265126
+ }
265048
265127
  eventRepo;
265049
265128
  snapshotService;
265050
265129
  eventBus;
@@ -265126,8 +265205,10 @@ var RecordingService = class RecordingService2 {
265126
265205
  }
265127
265206
  return { sessionId, eventsDeleted, snapshotsDeleted };
265128
265207
  }
265208
+ static DEFAULT_WINDOW_MS = 90 * 24 * 60 * 60 * 1e3;
265129
265209
  async listRecordings(limit = 100, options = {}) {
265130
- 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);
265131
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");
265132
265213
  if (from)
265133
265214
  qb.andWhere("e.createdAt >= :from", { from });
@@ -265152,7 +265233,7 @@ var RecordingService = class RecordingService2 {
265152
265233
  };
265153
265234
  }
265154
265235
  };
265155
- RecordingService = __decorate94([
265236
+ RecordingService = RecordingService_1 = __decorate94([
265156
265237
  (0, import_common51.Injectable)(),
265157
265238
  __param25(0, (0, import_typeorm79.InjectRepository)(RecordingEvent)),
265158
265239
  __metadata80("design:paramtypes", [
@@ -265810,7 +265891,7 @@ async function pool(items, limit, fn) {
265810
265891
  });
265811
265892
  await Promise.all(workers);
265812
265893
  }
265813
- async function folderSize(dir) {
265894
+ async function sizeOfDir(dir) {
265814
265895
  let total = 0;
265815
265896
  let entries;
265816
265897
  try {
@@ -265822,7 +265903,7 @@ async function folderSize(dir) {
265822
265903
  const full = path6.join(dir, ent.name);
265823
265904
  try {
265824
265905
  if (ent.isDirectory()) {
265825
- const sub = await folderSize(full);
265906
+ const sub = await sizeOfDir(full);
265826
265907
  total += sub;
265827
265908
  } else if (ent.isFile()) {
265828
265909
  const st = await fsp.stat(full);
@@ -265833,19 +265914,19 @@ async function folderSize(dir) {
265833
265914
  });
265834
265915
  return total;
265835
265916
  }
265836
- async function topLevelBreakdown(dir, limit = TOP_ENTRIES_LIMIT) {
265917
+ async function sizeWithBreakdown(dir, limit = TOP_ENTRIES_LIMIT) {
265837
265918
  let entries;
265838
265919
  try {
265839
265920
  entries = await fsp.readdir(dir, { withFileTypes: true });
265840
265921
  } catch {
265841
- return [];
265922
+ return { totalBytes: 0, topEntries: [] };
265842
265923
  }
265843
265924
  const sized = [];
265844
265925
  await pool(entries, WALK_CONCURRENCY, async (ent) => {
265845
265926
  const full = path6.join(dir, ent.name);
265846
265927
  try {
265847
265928
  if (ent.isDirectory()) {
265848
- const sub = await folderSize(full);
265929
+ const sub = await sizeOfDir(full);
265849
265930
  sized.push({ name: ent.name + "/", bytes: sub });
265850
265931
  } else if (ent.isFile()) {
265851
265932
  const st = await fsp.stat(full);
@@ -265854,13 +265935,14 @@ async function topLevelBreakdown(dir, limit = TOP_ENTRIES_LIMIT) {
265854
265935
  } catch {
265855
265936
  }
265856
265937
  });
265938
+ const totalBytes = sized.reduce((acc, e) => acc + e.bytes, 0);
265857
265939
  sized.sort((a, b2) => b2.bytes - a.bytes);
265858
265940
  if (sized.length <= limit)
265859
- return sized;
265941
+ return { totalBytes, topEntries: sized };
265860
265942
  const head = sized.slice(0, limit);
265861
265943
  const restBytes = sized.slice(limit).reduce((acc, e) => acc + e.bytes, 0);
265862
265944
  head.push({ name: `others(${sized.length - limit})`, bytes: restBytes });
265863
- return head;
265945
+ return { totalBytes, topEntries: head };
265864
265946
  }
265865
265947
  function findInstallRoot(startDir, maxUp = 6) {
265866
265948
  let dir = startDir;
@@ -265927,27 +266009,26 @@ var ResourceCollector = ResourceCollector_1 = class ResourceCollector2 {
265927
266009
  }
265928
266010
  async collectPaths(specs = this.resolvePathSpecs()) {
265929
266011
  const out = [];
265930
- for (const spec of specs) {
266012
+ let slot = 0;
266013
+ await pool(specs, WALK_CONCURRENCY, async (spec) => {
266014
+ const idx = slot++;
265931
266015
  try {
265932
266016
  if (!fs7.existsSync(spec.path)) {
265933
- out.push({ key: spec.key, path: spec.path, exists: false, totalBytes: 0, topEntries: [], group: spec.group });
265934
- continue;
266017
+ out[idx] = { key: spec.key, path: spec.path, exists: false, totalBytes: 0, topEntries: [], group: spec.group };
266018
+ return;
265935
266019
  }
265936
266020
  const st = await fsp.stat(spec.path);
265937
266021
  if (st.isFile()) {
265938
- out.push({ key: spec.key, path: spec.path, exists: true, totalBytes: st.size, topEntries: [], group: spec.group });
265939
- continue;
266022
+ out[idx] = { key: spec.key, path: spec.path, exists: true, totalBytes: st.size, topEntries: [], group: spec.group };
266023
+ return;
265940
266024
  }
265941
- const [totalBytes, topEntries] = await Promise.all([
265942
- folderSize(spec.path),
265943
- topLevelBreakdown(spec.path)
265944
- ]);
265945
- 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 };
265946
266027
  } catch (err) {
265947
266028
  this.logger.warn(`\u91C7\u96C6\u8DEF\u5F84\u5360\u7528\u5931\u8D25 ${spec.path}: ${err.message}`);
265948
- 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 };
265949
266030
  }
265950
- }
266031
+ });
265951
266032
  return out;
265952
266033
  }
265953
266034
  async collectProcesses() {
@@ -291331,6 +291412,9 @@ ExtractionRuleService = __decorate101([
291331
291412
  ], ExtractionRuleService);
291332
291413
 
291333
291414
  // dist/.server-tsc/extraction/structured-data.js
291415
+ function toCheerio(html) {
291416
+ return typeof html === "string" ? load(html) : html;
291417
+ }
291334
291418
  function pageClassFromJsonLdTypes(types2) {
291335
291419
  const t = new Set(types2.map((x) => x.toLowerCase()));
291336
291420
  if (t.has("person"))
@@ -291366,7 +291450,7 @@ function flattenEntity(entity, prefix = "", out = {}) {
291366
291450
  return out;
291367
291451
  }
291368
291452
  function extractJsonLd(html) {
291369
- const $ = load(html);
291453
+ const $ = toCheerio(html);
291370
291454
  const entities = [];
291371
291455
  $('script[type="application/ld+json"]').each((_i, el) => {
291372
291456
  try {
@@ -291396,7 +291480,7 @@ function extractJsonLd(html) {
291396
291480
  return { types: types2, data };
291397
291481
  }
291398
291482
  function extractOpenGraph(html) {
291399
- const $ = load(html);
291483
+ const $ = toCheerio(html);
291400
291484
  const out = {};
291401
291485
  $('meta[property^="og:"], meta[name^="og:"]').each((_i, el) => {
291402
291486
  const key = $(el).attr("property") || $(el).attr("name") || "";
@@ -291501,7 +291585,7 @@ function applySelectorRule(payload, html) {
291501
291585
  if (payload?.fields || payload?.lists || payload?.entityList) {
291502
291586
  return applyScriptRule(html, payload);
291503
291587
  }
291504
- const $ = load(html);
291588
+ const $ = typeof html === "string" ? load(html) : html;
291505
291589
  const result = {};
291506
291590
  const mapping = payload.mapping || {};
291507
291591
  for (const [field, selector] of Object.entries(mapping)) {
@@ -291583,13 +291667,14 @@ var ExtractionService = class ExtractionService2 {
291583
291667
  applyRulesToHtml(sourceUrl, html, rules) {
291584
291668
  const matched = rules.filter((r) => r.enabled && matchRule(r, sourceUrl)).sort((a, b2) => b2.priority - a.priority);
291585
291669
  const extracted = {};
291670
+ const $ = load(html);
291586
291671
  for (const rule of matched) {
291587
291672
  if (rule.ruleType === "selector")
291588
- Object.assign(extracted, applySelectorRule(rule.rulePayload, html));
291673
+ Object.assign(extracted, applySelectorRule(rule.rulePayload, $));
291589
291674
  else if (rule.ruleType === "regex")
291590
291675
  Object.assign(extracted, applyRegexRule(rule.rulePayload, html));
291591
291676
  else if (rule.ruleType === "script")
291592
- Object.assign(extracted, applyScriptRule(html, rule.rulePayload));
291677
+ Object.assign(extracted, applyScriptRule($, rule.rulePayload));
291593
291678
  }
291594
291679
  this.applyProfileUrlFallback(extracted, sourceUrl, matched);
291595
291680
  return {
@@ -291667,8 +291752,9 @@ var ExtractionService = class ExtractionService2 {
291667
291752
  });
291668
291753
  return { ...result, status: "no-snapshot", message: "Missing sourceUrl or rrweb full snapshot." };
291669
291754
  }
291670
- const jsonld = extractJsonLd(html);
291671
- const og = extractOpenGraph(html);
291755
+ const $ = load(html);
291756
+ const jsonld = extractJsonLd($);
291757
+ const og = extractOpenGraph($);
291672
291758
  const rules = await this.ruleService.findEnabled();
291673
291759
  const adapterRules = (await this.adapterRuleRepo.find({ where: { enabled: true } })).map((r) => ({
291674
291760
  ruleId: r.externalId || `${r.platform}/${r.hostPattern}`,
@@ -291685,11 +291771,11 @@ var ExtractionService = class ExtractionService2 {
291685
291771
  const ruleExtracted = {};
291686
291772
  for (const rule of matched) {
291687
291773
  if (rule.ruleType === "selector")
291688
- Object.assign(ruleExtracted, applySelectorRule(rule.rulePayload, html));
291774
+ Object.assign(ruleExtracted, applySelectorRule(rule.rulePayload, $));
291689
291775
  else if (rule.ruleType === "regex")
291690
291776
  Object.assign(ruleExtracted, applyRegexRule(rule.rulePayload, html));
291691
291777
  else if (rule.ruleType === "script")
291692
- Object.assign(ruleExtracted, applyScriptRule(html, rule.rulePayload));
291778
+ Object.assign(ruleExtracted, applyScriptRule($, rule.rulePayload));
291693
291779
  }
291694
291780
  const merged = { ...og, ...jsonld?.data || {}, ...ruleExtracted };
291695
291781
  for (const [k2, v] of Object.entries({ ...jsonld?.data || {}, ...og || {} })) {
@@ -292041,8 +292127,9 @@ var ExtractionService = class ExtractionService2 {
292041
292127
  return { sessionId, error: "missing snapshot or sourceUrl" };
292042
292128
  }
292043
292129
  const parsed = new URL(sourceUrl);
292044
- const jsonld = extractJsonLd(html);
292045
- const og = extractOpenGraph(html);
292130
+ const $ = load(html);
292131
+ const jsonld = extractJsonLd($);
292132
+ const og = extractOpenGraph($);
292046
292133
  const pageClass = jsonld ? pageClassFromJsonLdTypes(jsonld.types) : null;
292047
292134
  const draft = {
292048
292135
  ruleId: `${etldPlus1(parsed.hostname).replace(/\./g, "-")}-${pageClass || "page"}-auto`,
@@ -294444,6 +294531,8 @@ var AdapterService = class AdapterService2 {
294444
294531
  const sourceUrl = snapshot.sourceUrl || "";
294445
294532
  const html = snapshot.html;
294446
294533
  const matched = sourceUrl ? await this.findRulesForUrl(sourceUrl) : [];
294534
+ let cached$ = null;
294535
+ const $ = () => cached$ ??= load(html);
294447
294536
  const ruleExtracted = {};
294448
294537
  const isEmptyVal = (v) => v == null || v === "" || Array.isArray(v) && v.length === 0;
294449
294538
  const mergeRuleOutput = (out) => {
@@ -294457,15 +294546,13 @@ var AdapterService = class AdapterService2 {
294457
294546
  if (rule.ruleType === "selector") {
294458
294547
  const payload = rule.rulePayload;
294459
294548
  if (payload?.fields || payload?.lists) {
294460
- const { applyScriptRule: applyScriptRule2 } = await import("./chunks/script-rule-ZJN6CEYX.mjs");
294461
- mergeRuleOutput(applyScriptRule2(html, payload));
294549
+ const { applyScriptRule: applyScriptRule2 } = await import("./chunks/script-rule-4RZQ2PQE.mjs");
294550
+ mergeRuleOutput(applyScriptRule2($(), payload));
294462
294551
  } else {
294463
- const { load: load2 } = await import("./chunks/esm-4U746B76.mjs");
294464
- const $ = load2(html);
294465
294552
  const mapping = payload.mapping || {};
294466
294553
  const out = {};
294467
294554
  for (const [field, selector] of Object.entries(mapping)) {
294468
- const el = $(selector).first();
294555
+ const el = $()(selector).first();
294469
294556
  out[field] = el.text().trim() || el.attr("content") || el.attr("value") || null;
294470
294557
  }
294471
294558
  mergeRuleOutput(out);
@@ -294479,13 +294566,13 @@ var AdapterService = class AdapterService2 {
294479
294566
  }
294480
294567
  mergeRuleOutput(out);
294481
294568
  } else if (rule.ruleType === "script") {
294482
- const { applyScriptRule: applyScriptRule2 } = await import("./chunks/script-rule-ZJN6CEYX.mjs");
294483
- mergeRuleOutput(applyScriptRule2(html, rule.rulePayload));
294569
+ const { applyScriptRule: applyScriptRule2 } = await import("./chunks/script-rule-4RZQ2PQE.mjs");
294570
+ mergeRuleOutput(applyScriptRule2($(), rule.rulePayload));
294484
294571
  } else if (rule.ruleType === "jsonld") {
294485
294572
  }
294486
294573
  }
294487
- const jsonld = extractJsonLd(html);
294488
- const og = extractOpenGraph(html);
294574
+ const jsonld = extractJsonLd($());
294575
+ const og = extractOpenGraph($());
294489
294576
  const merged = { ...og, ...jsonld?.data || {}, ...ruleExtracted };
294490
294577
  for (const [k2, v] of Object.entries({ ...jsonld?.data || {}, ...og || {} })) {
294491
294578
  if (ruleExtracted[k2] == null && v != null)
@@ -305301,6 +305388,11 @@ var CustomerService = class CustomerService2 {
305301
305388
  datasync;
305302
305389
  tenant;
305303
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
+ }
305304
305396
  constructor(repo, jobCaseRepo, remarkRepo, companyProfileRepo, talentProfileRepo, jobPostingRepo, parseLogRepo, datasync, tenant) {
305305
305397
  this.repo = repo;
305306
305398
  this.jobCaseRepo = jobCaseRepo;
@@ -305313,7 +305405,9 @@ var CustomerService = class CustomerService2 {
305313
305405
  this.tenant = tenant;
305314
305406
  }
305315
305407
  async batchDelete(ids) {
305316
- 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;
305317
305411
  }
305318
305412
  async onModuleInit() {
305319
305413
  await this.repo.query("UPDATE customers SET isCustomer = 1 WHERE isCustomer IS NULL");
@@ -305394,6 +305488,7 @@ var CustomerService = class CustomerService2 {
305394
305488
  if (changed) {
305395
305489
  customer.aliases = [...aliases];
305396
305490
  await this.repo.save(customer);
305491
+ this.invalidateCollectCache();
305397
305492
  }
305398
305493
  return { customer, created: false, merged: true };
305399
305494
  };
@@ -305427,6 +305522,7 @@ var CustomerService = class CustomerService2 {
305427
305522
  });
305428
305523
  try {
305429
305524
  const saved = await this.repo.save(entity);
305525
+ this.invalidateCollectCache();
305430
305526
  return { customer: saved, created: true, merged: false };
305431
305527
  } catch (err) {
305432
305528
  if (String(err?.code).startsWith("SQLITE_CONSTRAINT")) {
@@ -305476,7 +305572,9 @@ var CustomerService = class CustomerService2 {
305476
305572
  }
305477
305573
  customer.profile = next;
305478
305574
  }
305479
- return this.repo.save(customer);
305575
+ const saved = await this.repo.save(customer);
305576
+ this.invalidateCollectCache();
305577
+ return saved;
305480
305578
  }
305481
305579
  async duplicates(id) {
305482
305580
  const customer = await this.findOne(id);
@@ -305550,6 +305648,7 @@ var CustomerService = class CustomerService2 {
305550
305648
  if ((keep.isCustomer ?? 0) !== 1 && (remove.isCustomer ?? 0) === 1)
305551
305649
  keep.isCustomer = 1;
305552
305650
  await this.repo.save(keep);
305651
+ this.invalidateCollectCache();
305553
305652
  await this.jobCaseRepo.update({ customerId: removeId }, { customerId: keepId });
305554
305653
  await this.remarkRepo.update({ targetType: "customer", targetId: String(removeId) }, { targetId: String(keepId) });
305555
305654
  await this.datasync.deleteWithTombstones(this.repo, "customers", [removeId]);
@@ -305573,7 +305672,15 @@ var CustomerService = class CustomerService2 {
305573
305672
  });
305574
305673
  return [...new Set(parts)];
305575
305674
  }
305576
- 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() {
305577
305684
  const talents = await this.talentProfileRepo.find();
305578
305685
  const talentNames = new Set(talents.map((t) => (t.name ?? "").trim().toLowerCase()).filter(Boolean));
305579
305686
  const existing = await this.repo.find();
@@ -305611,7 +305718,7 @@ var CustomerService = class CustomerService2 {
305611
305718
  }
305612
305719
  }
305613
305720
  const profileKeys = /* @__PURE__ */ new Set();
305614
- for (const p of await this.companyProfileRepo.find()) {
305721
+ for (const p of profiles) {
305615
305722
  const k2 = normalizeCustomerName(p.name ?? "");
305616
305723
  if (k2)
305617
305724
  profileKeys.add(k2);
@@ -305626,7 +305733,9 @@ var CustomerService = class CustomerService2 {
305626
305733
  }
305627
305734
  }
305628
305735
  const caseCustomerIds = new Set((await this.jobCaseRepo.find({ select: ["customerId"] })).map((jc) => jc.customerId).filter((id) => id != null));
305629
- 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
+ })) {
305630
305739
  if (!(c.canonicalName ?? "").trim()) {
305631
305740
  if (caseCustomerIds.has(c.id))
305632
305741
  continue;
@@ -305662,13 +305771,13 @@ var CustomerService = class CustomerService2 {
305662
305771
  qb.select([...CustomerService_1.LIST_COLS]);
305663
305772
  const matched = await qb.getMany();
305664
305773
  const profileKeys = /* @__PURE__ */ new Set();
305665
- for (const p of await this.companyProfileRepo.find()) {
305774
+ for (const p of await this.companyProfileRepo.find({ select: ["name"] })) {
305666
305775
  const k2 = normalizeCustomerName(p.name ?? "");
305667
305776
  if (k2)
305668
305777
  profileKeys.add(k2);
305669
305778
  }
305670
305779
  const resumeKeys = /* @__PURE__ */ new Set();
305671
- for (const t of await this.talentProfileRepo.find()) {
305780
+ for (const t of await this.talentProfileRepo.find({ select: ["extracted"] })) {
305672
305781
  const ex = t.extracted ?? {};
305673
305782
  for (const cand of this.parseResumeCompanies(String(ex.currentCompany ?? ex.company ?? ""))) {
305674
305783
  const k2 = normalizeCustomerName(cand);
@@ -305679,15 +305788,15 @@ var CustomerService = class CustomerService2 {
305679
305788
  const caseCount = /* @__PURE__ */ new Map();
305680
305789
  const activeCount = /* @__PURE__ */ new Map();
305681
305790
  const hmhLocal = /* @__PURE__ */ new Set();
305682
- for (const jc of await this.jobCaseRepo.find()) {
305683
- if (jc.customerId == null)
305684
- continue;
305685
- caseCount.set(jc.customerId, (caseCount.get(jc.customerId) ?? 0) + 1);
305686
- if (jc.status === "active") {
305687
- activeCount.set(jc.customerId, (activeCount.get(jc.customerId) ?? 0) + 1);
305688
- }
305689
- if ((jc.folderPath ?? "").includes("/local/clients/"))
305690
- 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);
305691
305800
  }
305692
305801
  const decorated = matched.map((c) => {
305693
305802
  const keys = [c.dedupKey, ...(c.aliases ?? []).map((a) => normalizeCustomerName(a))];
@@ -305833,7 +305942,7 @@ var CustomerController = class CustomerController2 {
305833
305942
  });
305834
305943
  }
305835
305944
  collect() {
305836
- return this.service.collectCompanies();
305945
+ return this.service.collectCompanies(true);
305837
305946
  }
305838
305947
  batchDelete(body) {
305839
305948
  const ids = this.parseBatchIds(body);
@@ -306656,8 +306765,9 @@ var ResourceUsageController = class ResourceUsageController2 {
306656
306765
  }
306657
306766
  async collectNow() {
306658
306767
  const snapshot = await this.service.collectNow();
306659
- const report = await this.service.reportUnreported();
306660
- return { ok: true, snapshot, report };
306768
+ this.service.reportUnreported().catch(() => {
306769
+ });
306770
+ return { ok: true, snapshot };
306661
306771
  }
306662
306772
  pending() {
306663
306773
  return this.service.pendingCount().then((count2) => ({ count: count2 }));
@@ -307067,12 +307177,17 @@ var RecommendationService = RecommendationService_1 = class RecommendationServic
307067
307177
  if (!ids.length)
307068
307178
  return {};
307069
307179
  const now = /* @__PURE__ */ new Date();
307180
+ const dayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
307070
307181
  const weekStart = new Date(now.getFullYear(), now.getMonth(), now.getDate() - (now.getDay() + 6) % 7);
307071
- const rows = await this.recRepo.createQueryBuilder("r").select("r.jobCaseId", "jobCaseId").addSelect("r.stage", "stage").addSelect("COUNT(*)", "c").addSelect("SUM(CASE WHEN r.updatedAt >= :weekStart THEN 1 ELSE 0 END)", "weekC").where("r.jobCaseId IN (:...ids)", { ids }).setParameter("weekStart", weekStart.toISOString()).groupBy("r.jobCaseId").addGroupBy("r.stage").getRawMany();
307182
+ const rows = await this.recRepo.createQueryBuilder("r").select("r.jobCaseId", "jobCaseId").addSelect("r.stage", "stage").addSelect("COUNT(*)", "c").addSelect("SUM(CASE WHEN r.updatedAt >= :weekStart THEN 1 ELSE 0 END)", "weekC").addSelect("SUM(CASE WHEN r.updatedAt >= :dayStart THEN 1 ELSE 0 END)", "todayC").where("r.jobCaseId IN (:...ids)", { ids }).setParameter("weekStart", weekStart.toISOString()).setParameter("dayStart", dayStart.toISOString()).groupBy("r.jobCaseId").addGroupBy("r.stage").getRawMany();
307072
307183
  const out = {};
307073
307184
  for (const r of rows) {
307074
307185
  const jc = Number(r.jobCaseId);
307075
- (out[jc] ??= {})[r.stage] = { total: Number(r.c), week: Number(r.weekC ?? 0) };
307186
+ (out[jc] ??= {})[r.stage] = {
307187
+ total: Number(r.c),
307188
+ week: Number(r.weekC ?? 0),
307189
+ today: Number(r.todayC ?? 0)
307190
+ };
307076
307191
  }
307077
307192
  return out;
307078
307193
  }