@neat.is/core 0.10.5 → 0.10.6-dev.20261008

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/{chunk-DVCGDMTZ.js → chunk-6QMWJAWR.js} +1454 -1019
  2. package/dist/chunk-6QMWJAWR.js.map +1 -0
  3. package/dist/{chunk-Q2SL2SVH.js → chunk-EMFX3V77.js} +43 -224
  4. package/dist/chunk-EMFX3V77.js.map +1 -0
  5. package/dist/chunk-MR64ICXX.js +19 -0
  6. package/dist/chunk-MR64ICXX.js.map +1 -0
  7. package/dist/{chunk-EFBWQIKG.js → chunk-QPG2QXCW.js} +11 -27
  8. package/dist/chunk-QPG2QXCW.js.map +1 -0
  9. package/dist/chunk-RGYC5U2Q.js +511 -0
  10. package/dist/chunk-RGYC5U2Q.js.map +1 -0
  11. package/dist/{chunk-LXQCL4MP.js → chunk-TZXSWSHX.js} +2 -2
  12. package/dist/{chunk-BC53SCT7.js → chunk-VFZ6CXLI.js} +20 -6
  13. package/dist/chunk-VFZ6CXLI.js.map +1 -0
  14. package/dist/cli.cjs +2065 -1178
  15. package/dist/cli.cjs.map +1 -1
  16. package/dist/cli.d.cts +2 -0
  17. package/dist/cli.d.ts +2 -0
  18. package/dist/cli.js +249 -76
  19. package/dist/cli.js.map +1 -1
  20. package/dist/index.cjs +1653 -952
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +45 -99
  23. package/dist/index.d.ts +45 -99
  24. package/dist/index.js +18 -15
  25. package/dist/neatd.cjs +1666 -965
  26. package/dist/neatd.cjs.map +1 -1
  27. package/dist/neatd.js +7 -4
  28. package/dist/neatd.js.map +1 -1
  29. package/dist/otel-grpc-CCCI772O.js +11 -0
  30. package/dist/registry.cjs +570 -0
  31. package/dist/registry.cjs.map +1 -0
  32. package/dist/registry.d.cts +220 -0
  33. package/dist/registry.d.ts +220 -0
  34. package/dist/registry.js +62 -0
  35. package/dist/registry.js.map +1 -0
  36. package/dist/server.cjs +1384 -657
  37. package/dist/server.cjs.map +1 -1
  38. package/dist/server.js +10 -6
  39. package/dist/server.js.map +1 -1
  40. package/package.json +9 -3
  41. package/dist/chunk-BC53SCT7.js.map +0 -1
  42. package/dist/chunk-DVCGDMTZ.js.map +0 -1
  43. package/dist/chunk-EFBWQIKG.js.map +0 -1
  44. package/dist/chunk-Q2SL2SVH.js.map +0 -1
  45. package/dist/otel-grpc-B7ABHLV7.js +0 -10
  46. /package/dist/{chunk-LXQCL4MP.js.map → chunk-TZXSWSHX.js.map} +0 -0
  47. /package/dist/{otel-grpc-B7ABHLV7.js.map → otel-grpc-CCCI772O.js.map} +0 -0
@@ -11,35 +11,38 @@ import {
11
11
  handleSpan,
12
12
  isBoundaryTimeoutSymptom,
13
13
  junctionFetch,
14
- listProjects,
15
14
  loadGraphFromDisk,
16
15
  makeErrorSpanWriter,
16
+ maybeStartRepoSync,
17
17
  nodeContext,
18
18
  pathsForProject,
19
19
  promoteFrontierEdges,
20
- pruneRegistry,
21
20
  readErrorEvents,
22
- registryPath,
23
21
  resetGraph,
24
22
  resolveCredential,
25
23
  resolveFusedServiceId,
26
24
  resolveHangHop,
27
25
  saveGraphToDisk,
28
- setStatus,
29
26
  stageFrontierEdge,
30
27
  startConnectorPollLoop,
31
28
  startConnectorPolling,
32
29
  startPersistLoop,
33
- startStalenessLoop,
30
+ startStalenessLoop
31
+ } from "./chunk-6QMWJAWR.js";
32
+ import {
33
+ listProjects,
34
+ pruneRegistry,
35
+ registryPath,
36
+ setStatus,
34
37
  touchLastSeen,
35
38
  writeAtomically
36
- } from "./chunk-DVCGDMTZ.js";
39
+ } from "./chunk-RGYC5U2Q.js";
37
40
  import {
38
41
  assertBindAuthority,
39
42
  buildOtelReceiver,
40
43
  listenSteppingOtlp,
41
44
  readAuthEnv
42
- } from "./chunk-EFBWQIKG.js";
45
+ } from "./chunk-QPG2QXCW.js";
43
46
 
44
47
  // src/daemon.ts
45
48
  import {
@@ -49,7 +52,7 @@ import {
49
52
  unlinkSync,
50
53
  writeFileSync
51
54
  } from "fs";
52
- import path4 from "path";
55
+ import path3 from "path";
53
56
  import { createRequire } from "module";
54
57
 
55
58
  // src/hang-sensor.ts
@@ -117,13 +120,13 @@ function decodeRailwayTargetRef(ref) {
117
120
  var CREDENTIAL_REFRESH_SKEW_MS = 6e4;
118
121
  var CP_REQUEST_TIMEOUT_MS = 1e4;
119
122
  var DEFAULT_RELIST_INTERVAL_MS = 6e4;
120
- async function cpGet(path5, deps) {
123
+ async function cpGet(path4, deps) {
121
124
  const f = deps.fetchImpl ?? fetch;
122
- const res = await f(`${deps.cpUrl.replace(/\/+$/, "")}${path5}`, {
125
+ const res = await f(`${deps.cpUrl.replace(/\/+$/, "")}${path4}`, {
123
126
  headers: { authorization: `Bearer ${deps.daemonToken}`, accept: "application/json" },
124
127
  signal: AbortSignal.timeout(CP_REQUEST_TIMEOUT_MS)
125
128
  });
126
- if (!res.ok) throw new Error(`control plane ${path5} \u2192 HTTP ${res.status}`);
129
+ if (!res.ok) throw new Error(`control plane ${path4} \u2192 HTTP ${res.status}`);
127
130
  return await res.json();
128
131
  }
129
132
  function credentialRecord(provider, cred) {
@@ -195,14 +198,14 @@ async function readPushHandles(projectDir) {
195
198
  }
196
199
  }
197
200
  async function writePushHandle(projectDir, provider, handle) {
198
- const path5 = pushHandlesPath(projectDir);
201
+ const path4 = pushHandlesPath(projectDir);
199
202
  const handles = await readPushHandles(projectDir);
200
203
  handles[provider] = handle;
201
- await mkdir(dirname(path5), { recursive: true });
202
- const tmp = `${path5}.${process.pid}.tmp`;
204
+ await mkdir(dirname(path4), { recursive: true });
205
+ const tmp = `${path4}.${process.pid}.tmp`;
203
206
  await writeFile(tmp, `${JSON.stringify(handles, null, 2)}
204
207
  `, "utf8");
205
- await rename(tmp, path5);
208
+ await rename(tmp, path4);
206
209
  }
207
210
  function pushCredentialRecord(provider, cred, deps) {
208
211
  switch (provider) {
@@ -420,190 +423,6 @@ async function maybeStartHostedConnectors(input) {
420
423
  });
421
424
  }
422
425
 
423
- // src/connectors/hosted-repos.ts
424
- import os from "os";
425
- import path from "path";
426
- import { mkdtemp, rm } from "fs/promises";
427
- var CP_REQUEST_TIMEOUT_MS2 = 1e4;
428
- var DEFAULT_SYNC_INTERVAL_MS = 5 * 6e4;
429
- var CLONE_TIMEOUT_MS = 5 * 6e4;
430
- function scrubToken(s) {
431
- return s.replace(/x-access-token:[^@\s]+@/g, "x-access-token:***@");
432
- }
433
- async function cpGet2(pathname, deps) {
434
- const f = deps.fetchImpl ?? fetch;
435
- const res = await f(`${deps.cpUrl.replace(/\/+$/, "")}${pathname}`, {
436
- headers: { authorization: `Bearer ${deps.daemonToken}`, accept: "application/json" },
437
- signal: AbortSignal.timeout(CP_REQUEST_TIMEOUT_MS2)
438
- });
439
- if (!res.ok) throw new Error(`control plane ${pathname} \u2192 HTTP ${res.status}`);
440
- return await res.json();
441
- }
442
- async function cpPostStatus(deps, owner, name, body) {
443
- const f = deps.fetchImpl ?? fetch;
444
- const url = `${deps.cpUrl.replace(/\/+$/, "")}/internal/projects/${deps.projectId}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/status`;
445
- const res = await f(url, {
446
- method: "POST",
447
- headers: { authorization: `Bearer ${deps.daemonToken}`, "content-type": "application/json" },
448
- body: JSON.stringify(body),
449
- signal: AbortSignal.timeout(CP_REQUEST_TIMEOUT_MS2)
450
- });
451
- if (!res.ok && res.status !== 404) throw new Error(`control plane status POST \u2192 HTTP ${res.status}`);
452
- }
453
- var defaultCloneRepo = async (cloneUrl, ref, destDir) => {
454
- const [{ default: git }, httpMod, fs3] = await Promise.all([
455
- import("isomorphic-git"),
456
- import("isomorphic-git/http/node"),
457
- import("fs")
458
- ]);
459
- const http = httpMod.default ?? httpMod;
460
- const parsed = new URL(cloneUrl);
461
- const password = parsed.password || parsed.username;
462
- const username = parsed.password ? parsed.username : "x-access-token";
463
- const cleanUrl = `${parsed.protocol}//${parsed.host}${parsed.pathname}`;
464
- const clone = git.clone({
465
- fs: fs3,
466
- http,
467
- dir: destDir,
468
- url: cleanUrl,
469
- // Absent ref → isomorphic-git clones the remote's default branch.
470
- ...ref ? { ref } : {},
471
- singleBranch: true,
472
- depth: 1,
473
- onAuth: () => ({ username, password })
474
- });
475
- let timer;
476
- const timeout = new Promise((_, reject) => {
477
- timer = setTimeout(() => reject(new Error(`clone timed out after ${CLONE_TIMEOUT_MS}ms`)), CLONE_TIMEOUT_MS);
478
- });
479
- try {
480
- await Promise.race([clone, timeout]);
481
- } finally {
482
- if (timer) clearTimeout(timer);
483
- }
484
- };
485
- function needsSync(r) {
486
- return r.syncStatus === void 0 || r.syncStatus === "syncing";
487
- }
488
- async function syncOneRepo(r, input) {
489
- const { deps, graph } = input;
490
- const cloneRepo = input.cloneRepo ?? defaultCloneRepo;
491
- const extract = input.extract ?? extractFromDirectory;
492
- const label = `${r.owner}/${r.name}`;
493
- const tmpRoot = input.tmpRoot ?? os.tmpdir();
494
- let dir;
495
- try {
496
- dir = await mkdtemp(path.join(tmpRoot, "neat-repo-"));
497
- await cpPostStatus(deps, r.owner, r.name, { syncStatus: "syncing", detail: "cloning" }).catch(() => {
498
- });
499
- await cloneRepo(r.cloneUrl, r.defaultBranch, dir);
500
- const extracted = await extract(graph, dir, { source: label });
501
- const nodes = extracted?.nodesAdded ?? 0;
502
- const edges = extracted?.edgesAdded ?? 0;
503
- await cpPostStatus(deps, r.owner, r.name, {
504
- syncStatus: "synced",
505
- detail: `extracted ${nodes} node${nodes === 1 ? "" : "s"}, ${edges} edge${edges === 1 ? "" : "s"}`,
506
- lastSyncAt: new Date(input.now?.() ?? Date.now()).toISOString()
507
- });
508
- return true;
509
- } catch (err) {
510
- input.onError?.(label, err);
511
- await cpPostStatus(deps, r.owner, r.name, {
512
- syncStatus: "failed",
513
- detail: scrubToken(err.message).slice(0, 300)
514
- }).catch(() => {
515
- });
516
- return false;
517
- } finally {
518
- if (dir) await rm(dir, { recursive: true, force: true }).catch(() => {
519
- });
520
- }
521
- }
522
- async function runRepoSyncPassCounted(input) {
523
- const counts = { listed: false, synced: 0, failed: 0 };
524
- let repos;
525
- try {
526
- repos = await cpGet2(`/internal/projects/${input.deps.projectId}/repos`, input.deps);
527
- } catch (err) {
528
- input.onSkip?.("(all)", `control plane repo list unreadable \u2014 ${err.message}`);
529
- return counts;
530
- }
531
- if (!Array.isArray(repos)) return counts;
532
- counts.listed = true;
533
- for (const r of repos) {
534
- if (!input.forceResync && !needsSync(r)) continue;
535
- if (await syncOneRepo(r, input)) counts.synced++;
536
- else counts.failed++;
537
- }
538
- return counts;
539
- }
540
- async function startRepoSync(input) {
541
- const intervalMs = input.intervalMs ?? DEFAULT_SYNC_INTERVAL_MS;
542
- const now = () => input.now?.() ?? Date.now();
543
- let stopped = false;
544
- let inFlight = null;
545
- let again = false;
546
- let lastPass;
547
- let bootResyncDone = false;
548
- const run = async () => {
549
- try {
550
- do {
551
- again = false;
552
- const startedAt = new Date(now()).toISOString();
553
- const counts = await runRepoSyncPassCounted({ ...input, forceResync: !bootResyncDone });
554
- if (counts.listed) bootResyncDone = true;
555
- lastPass = { ...counts, startedAt, finishedAt: new Date(now()).toISOString() };
556
- } while (again && !stopped);
557
- } finally {
558
- inFlight = null;
559
- }
560
- };
561
- const tick = () => {
562
- if (stopped || inFlight) return;
563
- inFlight = run();
564
- };
565
- tick();
566
- const timer = setInterval(tick, intervalMs);
567
- if (typeof timer.unref === "function") timer.unref();
568
- const stop = () => {
569
- stopped = true;
570
- clearInterval(timer);
571
- };
572
- return Object.assign(stop, {
573
- syncNow: () => {
574
- const summary = lastPass ? { lastPass } : {};
575
- if (inFlight) {
576
- again = true;
577
- return { status: "queued", ...summary };
578
- }
579
- inFlight = run();
580
- return { status: "started", ...summary };
581
- },
582
- settled: async () => {
583
- while (inFlight) await inFlight;
584
- }
585
- });
586
- }
587
- async function maybeStartRepoSync(input) {
588
- const env = input.env ?? process.env;
589
- const cpUrl = env.NEAT_CP_URL;
590
- const projectId = env.NEAT_CP_PROJECT_ID;
591
- const daemonToken = env.NEAT_AUTH_TOKEN;
592
- if (!cpUrl || !projectId || !daemonToken) return () => {
593
- };
594
- return startRepoSync({
595
- deps: { cpUrl, projectId, daemonToken, ...input.fetchImpl ? { fetchImpl: input.fetchImpl } : {} },
596
- graph: input.graph,
597
- project: input.project,
598
- ...input.cloneRepo ? { cloneRepo: input.cloneRepo } : {},
599
- ...input.extract ? { extract: input.extract } : {},
600
- ...input.intervalMs !== void 0 ? { intervalMs: input.intervalMs } : {},
601
- ...input.tmpRoot ? { tmpRoot: input.tmpRoot } : {},
602
- ...input.onSkip ? { onSkip: input.onSkip } : {},
603
- ...input.onError ? { onError: input.onError } : {}
604
- });
605
- }
606
-
607
426
  // src/connectors/kubernetes/client.ts
608
427
  import { Agent, request as httpsRequest } from "https";
609
428
  function deploymentsPath(namespace) {
@@ -653,9 +472,9 @@ function makeK8sFetchImpl(transport) {
653
472
  req.end();
654
473
  }));
655
474
  }
656
- async function listResource(transport, namespace, path5, opts = {}) {
475
+ async function listResource(transport, namespace, path4, opts = {}) {
657
476
  const base = opts.apiUrl ?? transport.server;
658
- const url = `${base.replace(/\/$/, "")}${path5}`;
477
+ const url = `${base.replace(/\/$/, "")}${path4}`;
659
478
  const fetchImpl = opts.fetchImpl ?? makeK8sFetchImpl(transport);
660
479
  const res = await junctionFetch(
661
480
  url,
@@ -665,7 +484,7 @@ async function listResource(transport, namespace, path5, opts = {}) {
665
484
  { provider: "kubernetes", accountKey: `${safeHost(transport.server)}/${namespace}`, fetchImpl }
666
485
  );
667
486
  if (!res.ok) {
668
- throw new Error(`kubernetes ${path5} failed: ${res.status} ${res.statusText}`);
487
+ throw new Error(`kubernetes ${path4} failed: ${res.status} ${res.statusText}`);
669
488
  }
670
489
  const json = await res.json();
671
490
  return Array.isArray(json.items) ? json.items : [];
@@ -961,15 +780,15 @@ function createK8sResolveTarget(graph) {
961
780
 
962
781
  // src/connectors/kubernetes/substrate.ts
963
782
  import { readFile as readFile2 } from "fs/promises";
964
- import os2 from "os";
965
- import path2 from "path";
783
+ import os from "os";
784
+ import path from "path";
966
785
  function defaultHome() {
967
786
  const override = process.env.NEAT_HOME;
968
- if (override && override.length > 0) return path2.resolve(override);
969
- return path2.join(os2.homedir(), ".neat");
787
+ if (override && override.length > 0) return path.resolve(override);
788
+ return path.join(os.homedir(), ".neat");
970
789
  }
971
790
  function k8sSubstrateConfigPath(home = defaultHome()) {
972
- return path2.join(home, "k8s.json");
791
+ return path.join(home, "k8s.json");
973
792
  }
974
793
  async function readK8sSubstrateConfig(home = defaultHome()) {
975
794
  let raw;
@@ -1065,7 +884,7 @@ function createKubernetesConnector(graph, config, fetchImpl) {
1065
884
 
1066
885
  // src/unrouted.ts
1067
886
  import { promises as fs } from "fs";
1068
- import path3 from "path";
887
+ import path2 from "path";
1069
888
  function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
1070
889
  return {
1071
890
  timestamp: now.toISOString(),
@@ -1075,34 +894,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
1075
894
  };
1076
895
  }
1077
896
  async function appendUnroutedSpan(neatHome, record) {
1078
- const target = path3.join(neatHome, "errors.ndjson");
897
+ const target = path2.join(neatHome, "errors.ndjson");
1079
898
  await fs.mkdir(neatHome, { recursive: true });
1080
899
  await fs.appendFile(target, JSON.stringify(record) + "\n", "utf8");
1081
900
  }
1082
901
  function unroutedErrorsPath(neatHome) {
1083
- return path3.join(neatHome, "errors.ndjson");
902
+ return path2.join(neatHome, "errors.ndjson");
1084
903
  }
1085
904
 
1086
905
  // src/daemon.ts
1087
906
  import { NodeType } from "@neat.is/types";
1088
907
  function daemonJsonPath(scanPath) {
1089
- return path4.join(scanPath, "neat-out", "daemon.json");
908
+ return path3.join(scanPath, "neat-out", "daemon.json");
1090
909
  }
1091
910
  function daemonsDiscoveryDir(home) {
1092
911
  const base = home && home.length > 0 ? home : neatHomeFromEnv();
1093
- return path4.join(base, "daemons");
912
+ return path3.join(base, "daemons");
1094
913
  }
1095
914
  function daemonDiscoveryPath(project, home) {
1096
- return path4.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
915
+ return path3.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
1097
916
  }
1098
917
  function sanitizeDiscoveryName(project) {
1099
918
  return project.replace(/[^A-Za-z0-9._-]/g, "_");
1100
919
  }
1101
920
  function neatHomeFromEnv() {
1102
921
  const env = process.env.NEAT_HOME;
1103
- if (env && env.length > 0) return path4.resolve(env);
922
+ if (env && env.length > 0) return path3.resolve(env);
1104
923
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
1105
- return path4.join(home, ".neat");
924
+ return path3.join(home, ".neat");
1106
925
  }
1107
926
  async function readDaemonRecord(scanPath) {
1108
927
  try {
@@ -1195,11 +1014,11 @@ function teardownSlot(slot) {
1195
1014
  }
1196
1015
  }
1197
1016
  function neatHomeFor(opts) {
1198
- if (opts.neatHome && opts.neatHome.length > 0) return path4.resolve(opts.neatHome);
1017
+ if (opts.neatHome && opts.neatHome.length > 0) return path3.resolve(opts.neatHome);
1199
1018
  const env = process.env.NEAT_HOME;
1200
- if (env && env.length > 0) return path4.resolve(env);
1019
+ if (env && env.length > 0) return path3.resolve(env);
1201
1020
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
1202
- return path4.join(home, ".neat");
1021
+ return path3.join(home, ".neat");
1203
1022
  }
1204
1023
  function routeSpanToProject(serviceName, projects) {
1205
1024
  if (!serviceName) return DEFAULT_PROJECT;
@@ -1251,7 +1070,7 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
1251
1070
  );
1252
1071
  }
1253
1072
  async function bootstrapProject(entry, connectors = [], neatHome) {
1254
- const paths = pathsForProject(entry.name, path4.join(entry.path, "neat-out"));
1073
+ const paths = pathsForProject(entry.name, path3.join(entry.path, "neat-out"));
1255
1074
  try {
1256
1075
  const stat = await fs2.stat(entry.path);
1257
1076
  if (!stat.isDirectory()) {
@@ -1406,7 +1225,7 @@ async function startDaemon(opts = {}) {
1406
1225
  const projectArg = typeof opts.project === "string" && opts.project.length > 0 ? opts.project : process.env.NEAT_PROJECT && process.env.NEAT_PROJECT.length > 0 ? process.env.NEAT_PROJECT : null;
1407
1226
  const projectPathArg = opts.projectPath && opts.projectPath.length > 0 ? opts.projectPath : process.env.NEAT_PROJECT_PATH && process.env.NEAT_PROJECT_PATH.length > 0 ? process.env.NEAT_PROJECT_PATH : null;
1408
1227
  const singleProject = projectArg;
1409
- const singleProjectPath = singleProject && projectPathArg ? path4.resolve(projectPathArg) : null;
1228
+ const singleProjectPath = singleProject && projectPathArg ? path3.resolve(projectPathArg) : null;
1410
1229
  if (singleProject && !singleProjectPath) {
1411
1230
  throw new Error(
1412
1231
  `neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
@@ -1421,7 +1240,7 @@ async function startDaemon(opts = {}) {
1421
1240
  );
1422
1241
  }
1423
1242
  }
1424
- const pidPath = path4.join(home, "neatd.pid");
1243
+ const pidPath = path3.join(home, "neatd.pid");
1425
1244
  await writeAtomically(pidPath, `${process.pid}
1426
1245
  `);
1427
1246
  const slots = /* @__PURE__ */ new Map();
@@ -1902,8 +1721,8 @@ async function startDaemon(opts = {}) {
1902
1721
  let registryWatcher = null;
1903
1722
  let reloadTimer = null;
1904
1723
  if (!singleProject) try {
1905
- const regDir = path4.dirname(regPath);
1906
- const regBase = path4.basename(regPath);
1724
+ const regDir = path3.dirname(regPath);
1725
+ const regBase = path3.basename(regPath);
1907
1726
  registryWatcher = watch(regDir, (_eventType, filename) => {
1908
1727
  if (filename !== null && filename !== regBase) return;
1909
1728
  if (reloadTimer) clearTimeout(reloadTimer);
@@ -1983,4 +1802,4 @@ export {
1983
1802
  resolveHost,
1984
1803
  startDaemon
1985
1804
  };
1986
- //# sourceMappingURL=chunk-Q2SL2SVH.js.map
1805
+ //# sourceMappingURL=chunk-EMFX3V77.js.map