lurqrun 0.1.6 → 0.1.8
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.
- package/README.md +311 -139
- package/dist/auditHandler-VWCXSDVO.js +24 -0
- package/dist/autopilotInit-Q62MX5M6.js +178 -0
- package/dist/bin/lurq.js +3255 -23319
- package/dist/browserAuth-J7APSD4P.js +96 -0
- package/dist/cache-AEAKCV4I.js +12 -0
- package/dist/check-2JTQDQA6.js +2613 -0
- package/dist/check-PQSQ2MMA.js +192 -0
- package/dist/checkUpgrade-5YW77OBL.js +24 -0
- package/dist/chunk-2GAYNIHG.js +40 -0
- package/dist/chunk-2O6Z37IT.js +423 -0
- package/dist/chunk-2WD4QAH4.js +116 -0
- package/dist/chunk-3676XOBU.js +2235 -0
- package/dist/chunk-3D2MPGOQ.js +181 -0
- package/dist/chunk-3GHJR7XR.js +2049 -0
- package/dist/chunk-4ESO33J6.js +34 -0
- package/dist/chunk-4JHDSVIN.js +1229 -0
- package/dist/chunk-4KCPOMG6.js +68 -0
- package/dist/chunk-53SG6XWA.js +141 -0
- package/dist/chunk-5ABNDB3I.js +37 -0
- package/dist/chunk-5ALIJFDA.js +114 -0
- package/dist/chunk-63MUJNZL.js +318 -0
- package/dist/chunk-64ZF7KO4.js +1571 -0
- package/dist/chunk-6DM6UQFD.js +318 -0
- package/dist/chunk-6EQ3ARXA.js +304 -0
- package/dist/chunk-6L67QMCP.js +92 -0
- package/dist/chunk-72Y2FDVS.js +172 -0
- package/dist/chunk-A3TYI2TF.js +288 -0
- package/dist/chunk-B2UUYRBX.js +536 -0
- package/dist/chunk-BJT2LHAR.js +320 -0
- package/dist/chunk-BM3LF5T6.js +132 -0
- package/dist/chunk-BN3NM47Q.js +214 -0
- package/dist/chunk-BUALU27S.js +123 -0
- package/dist/chunk-C6GLE626.js +160 -0
- package/dist/chunk-D3K6IZVR.js +12845 -0
- package/dist/chunk-D3VTZS7V.js +222 -0
- package/dist/chunk-DM37MTOO.js +636 -0
- package/dist/chunk-DONTW3NE.js +171 -0
- package/dist/chunk-DSROTZ3Z.js +38 -0
- package/dist/chunk-ELGCAM7P.js +184 -0
- package/dist/chunk-EQCXENKZ.js +130 -0
- package/dist/chunk-EYAKM6YN.js +96 -0
- package/dist/chunk-FDFPMBCA.js +112 -0
- package/dist/chunk-FVYFV5HA.js +154 -0
- package/dist/chunk-GE37NVLN.js +15 -0
- package/dist/chunk-GM5Y555O.js +143 -0
- package/dist/chunk-GRJXQBQZ.js +793 -0
- package/dist/chunk-HWFX4BC4.js +177 -0
- package/dist/chunk-I3M2KJXB.js +56 -0
- package/dist/chunk-IFNONGRQ.js +603 -0
- package/dist/chunk-J3U2CPSK.js +136 -0
- package/dist/chunk-J6XQ7OPZ.js +74 -0
- package/dist/chunk-KMV4Y6R3.js +127 -0
- package/dist/chunk-KP5ZDDPE.js +340 -0
- package/dist/chunk-KYKSZ3XZ.js +202 -0
- package/dist/chunk-LEGPB7DO.js +81 -0
- package/dist/chunk-LUAKDHLZ.js +40 -0
- package/dist/chunk-MHUEVBVO.js +35 -0
- package/dist/chunk-MYGSLK44.js +37 -0
- package/dist/chunk-NEZNAPPN.js +41 -0
- package/dist/chunk-NPVN2THM.js +197 -0
- package/dist/chunk-NYZU5NCW.js +23 -0
- package/dist/chunk-O4KHCV6I.js +320 -0
- package/dist/chunk-ONDVTXUO.js +240 -0
- package/dist/chunk-OTJFHESY.js +176 -0
- package/dist/chunk-P6MIKSPY.js +243 -0
- package/dist/chunk-Q5VPF4WI.js +26 -0
- package/dist/chunk-QCRBX3LV.js +165 -0
- package/dist/chunk-QKGYDMWB.js +7409 -0
- package/dist/chunk-QSL6QN5X.js +115 -0
- package/dist/chunk-QUIMQ7YL.js +73 -0
- package/dist/chunk-RG3YLU6E.js +49 -0
- package/dist/chunk-SHCEBP3J.js +107 -0
- package/dist/chunk-SHZFOSXC.js +462 -0
- package/dist/chunk-SOXFMMXC.js +151 -0
- package/dist/chunk-TDTYV6QI.js +119 -0
- package/dist/chunk-TNTXWSYA.js +19 -0
- package/dist/chunk-TUXQ32WE.js +2251 -0
- package/dist/chunk-VGCDRK3S.js +37 -0
- package/dist/chunk-VLRHFMGJ.js +58 -0
- package/dist/chunk-WHX2ZFCG.js +4048 -0
- package/dist/chunk-X4W64MHU.js +2005 -0
- package/dist/chunk-XBQA4I36.js +92 -0
- package/dist/chunk-XGOV6KV4.js +413 -0
- package/dist/chunk-XIFQIFSZ.js +940 -0
- package/dist/chunk-XLXPVN3Y.js +15393 -0
- package/dist/chunk-ZJMLQ37G.js +90 -0
- package/dist/client-MU4EUDZV.js +15 -0
- package/dist/commands-UOOTMBKA.js +1023 -0
- package/dist/compat-Q5DVPITN.js +201 -0
- package/dist/constants-DJFOFZ44.js +24 -0
- package/dist/dashboardIssue-KBKLQMGC.js +274 -0
- package/dist/diff-I4SNUHU3.js +13 -0
- package/dist/dist-4XXIXHHZ.js +12945 -0
- package/dist/domains-VRT4BRVZ.js +14 -0
- package/dist/e2b-FVPHDULZ.js +172 -0
- package/dist/env-UN6KGZ7S.js +15 -0
- package/dist/envCheck-KUPTORFQ.js +71 -0
- package/dist/extract-6WG265BL.js +455 -0
- package/dist/fetch-PJ3SC32M.js +22 -0
- package/dist/firstTouch-COJCMOB3.js +55 -0
- package/dist/fix-3EDWNKW3.js +220 -0
- package/dist/handlers-4Q37WIFT.js +55 -0
- package/dist/hook-NA66XJLC.js +412 -0
- package/dist/http-25GJ6SKK.js +6928 -0
- package/dist/ingestQueue-FSVJC3AA.js +37 -0
- package/dist/install-G2HHXYJ2.js +20 -0
- package/dist/installSkill-5TIMYIJZ.js +70 -0
- package/dist/inventory-5AWSLJYU.js +31 -0
- package/dist/local-XPZMRH5R.js +13 -0
- package/dist/manifest-ENMIC54B.js +13 -0
- package/dist/mcp-PENLL2PK.js +500 -0
- package/dist/mcpConfig-3LYPRY5Q.js +80 -0
- package/dist/mcpHandlers-PO7GENA7.js +22 -0
- package/dist/mcpScan-ULP626TQ.js +1735 -0
- package/dist/mcpScanWorkflow-27O44FOE.js +98 -0
- package/dist/mcpStack-ZNYIFXZ5.js +20 -0
- package/dist/model-ASMZWLM7.js +214 -0
- package/dist/packages-RWF2LXST.js +40 -0
- package/dist/plan-SDILIDZT.js +465 -0
- package/dist/planView-ZAKRTGVS.js +82 -0
- package/dist/policy-JAGNMQJI.js +115 -0
- package/dist/probe-3IK646WN.js +610 -0
- package/dist/publicUpgrades-WTBGLDIK.js +42 -0
- package/dist/references-I6Y4BSRR.js +16 -0
- package/dist/release-7IU2R4YG.js +128 -0
- package/dist/remote-FN6225AH.js +42 -0
- package/dist/rename-OS6JYBZQ.js +204 -0
- package/dist/reportRuns-O4X7ZFTX.js +77 -0
- package/dist/safeFetch-COERXGFN.js +19 -0
- package/dist/sandbox-SAPSRKEI.js +39 -0
- package/dist/sarif-WLVJFJ7U.js +125 -0
- package/dist/server-OLTY3NYT.js +59 -0
- package/dist/surface-7MHE3RL7.js +143 -0
- package/dist/surface-JS2XU3U3.js +38 -0
- package/dist/surfaceHandlers-4B6TMZ34.js +20 -0
- package/dist/typecheck-NGOKNAJY.js +282 -0
- package/dist/types-M5JP2W3D.js +10 -0
- package/dist/uninstall-I2IJP5JZ.js +200 -0
- package/dist/upgrade-FS26DJGG.js +650 -0
- package/dist/upgradePlan-ZS5IOVMZ.js +181 -0
- package/dist/upkeepHandler-VFGYXJKB.js +13 -0
- package/dist/userConfig-ICASHI47.js +20 -0
- package/dist/watch-OCNEUXG6.js +204 -0
- package/package.json +26 -20
- package/templates/agent-rules.md +4 -4
- package/templates/skill-instructions.md +35 -17
- package/dist/bin/lurq.js.map +0 -1
- package/dist/index.d.ts +0 -805
- package/dist/index.js +0 -23570
- package/dist/index.js.map +0 -1
- package/drizzle/0000_confused_fabian_cortez.sql +0 -54
- package/drizzle/0001_aspiring_timeslip.sql +0 -15
- package/drizzle/0002_lyrical_lila_cheney.sql +0 -14
- package/drizzle/0003_violet_giant_girl.sql +0 -14
- package/drizzle/0004_slim_valeria_richards.sql +0 -15
- package/drizzle/0005_petite_luke_cage.sql +0 -12
- package/drizzle/0006_calm_nighthawk.sql +0 -3
- package/drizzle/0007_slimy_naoko.sql +0 -1
- package/drizzle/0008_peaceful_tigra.sql +0 -1
- package/drizzle/0009_smooth_harrier.sql +0 -10
- package/drizzle/0010_curved_amphibian.sql +0 -2
- package/drizzle/0011_compat_provenance_closures.sql +0 -11
- package/drizzle/0012_api_surfaces.sql +0 -9
- package/drizzle/0013_nice_thanos.sql +0 -1
- package/drizzle/0014_luxuriant_malcolm_colcord.sql +0 -10
- package/drizzle/0015_past_fat_cobra.sql +0 -11
- package/drizzle/0016_futuristic_junta.sql +0 -50
- package/drizzle/0017_absent_grandmaster.sql +0 -20
- package/drizzle/0018_rainy_proemial_gods.sql +0 -1
- package/drizzle/0019_dashing_korvac.sql +0 -11
- package/drizzle/0020_normal_vulture.sql +0 -3
- package/drizzle/0021_dazzling_blue_shield.sql +0 -17
- package/drizzle/0022_massive_ghost_rider.sql +0 -24
- package/drizzle/0023_next_shatterstar.sql +0 -1
- package/drizzle/0024_dusty_maelstrom.sql +0 -15
- package/drizzle/0025_gifted_harpoon.sql +0 -5
- package/drizzle/0026_awesome_mordo.sql +0 -1
- package/drizzle/0027_charming_ulik.sql +0 -2
- package/drizzle/0028_romantic_loners.sql +0 -2
- package/drizzle/0029_busy_korvac.sql +0 -16
- package/drizzle/0030_steady_mathemanic.sql +0 -6
- package/drizzle/0031_redundant_maginty.sql +0 -2
- package/drizzle/0032_stack_resolutions.sql +0 -14
- package/drizzle/0033_graceful_tyger_tiger.sql +0 -3
- package/drizzle/0034_uneven_thunderbird.sql +0 -1
- package/drizzle/0035_api_key_scopes.sql +0 -1
- package/drizzle/0036_policy_audit.sql +0 -21
- package/drizzle/0037_subscription_seats.sql +0 -1
- package/drizzle/0038_symbol_offsets.sql +0 -2
- package/drizzle/0039_mcp_runtime_scans.sql +0 -80
- package/drizzle/0040_subscription_overage_and_interval.sql +0 -4
- package/drizzle/0041_account_email.sql +0 -38
- package/drizzle/0042_alert_channels.sql +0 -21
- package/drizzle/meta/0000_snapshot.json +0 -370
- package/drizzle/meta/0001_snapshot.json +0 -482
- package/drizzle/meta/0002_snapshot.json +0 -575
- package/drizzle/meta/0003_snapshot.json +0 -667
- package/drizzle/meta/0004_snapshot.json +0 -769
- package/drizzle/meta/0005_snapshot.json +0 -864
- package/drizzle/meta/0006_snapshot.json +0 -882
- package/drizzle/meta/0007_snapshot.json +0 -876
- package/drizzle/meta/0008_snapshot.json +0 -882
- package/drizzle/meta/0009_snapshot.json +0 -948
- package/drizzle/meta/0010_snapshot.json +0 -969
- package/drizzle/meta/0011_snapshot.json +0 -1049
- package/drizzle/meta/0012_snapshot.json +0 -1115
- package/drizzle/meta/0013_snapshot.json +0 -1121
- package/drizzle/meta/0014_snapshot.json +0 -1190
- package/drizzle/meta/0015_snapshot.json +0 -1280
- package/drizzle/meta/0016_snapshot.json +0 -1683
- package/drizzle/meta/0017_snapshot.json +0 -1834
- package/drizzle/meta/0018_snapshot.json +0 -1834
- package/drizzle/meta/0019_snapshot.json +0 -1909
- package/drizzle/meta/0020_snapshot.json +0 -1921
- package/drizzle/meta/0021_snapshot.json +0 -2045
- package/drizzle/meta/0022_snapshot.json +0 -2246
- package/drizzle/meta/0023_snapshot.json +0 -2252
- package/drizzle/meta/0024_snapshot.json +0 -2375
- package/drizzle/meta/0025_snapshot.json +0 -2407
- package/drizzle/meta/0026_snapshot.json +0 -2413
- package/drizzle/meta/0027_snapshot.json +0 -2425
- package/drizzle/meta/0028_snapshot.json +0 -2438
- package/drizzle/meta/0029_snapshot.json +0 -2546
- package/drizzle/meta/0030_snapshot.json +0 -2586
- package/drizzle/meta/0031_snapshot.json +0 -2598
- package/drizzle/meta/0032_snapshot.json +0 -2699
- package/drizzle/meta/0033_snapshot.json +0 -2712
- package/drizzle/meta/0034_snapshot.json +0 -2719
- package/drizzle/meta/0035_snapshot.json +0 -2726
- package/drizzle/meta/0036_snapshot.json +0 -2876
- package/drizzle/meta/0037_snapshot.json +0 -2883
- package/drizzle/meta/0038_snapshot.json +0 -2895
- package/drizzle/meta/0039_snapshot.json +0 -3501
- package/drizzle/meta/0040_snapshot.json +0 -3527
- package/drizzle/meta/0041_snapshot.json +0 -3824
- package/drizzle/meta/0042_snapshot.json +0 -3960
- package/drizzle/meta/_journal.json +0 -307
- package/src/data/seed.json +0 -253
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
logger
|
|
4
|
+
} from "./chunk-MYGSLK44.js";
|
|
5
|
+
import {
|
|
6
|
+
init_esm_shims
|
|
7
|
+
} from "./chunk-I3M2KJXB.js";
|
|
8
|
+
|
|
9
|
+
// src/core/http.ts
|
|
10
|
+
init_esm_shims();
|
|
11
|
+
import { createHash } from "crypto";
|
|
12
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
13
|
+
import { existsSync } from "fs";
|
|
14
|
+
import { homedir } from "os";
|
|
15
|
+
import { dirname, join } from "path";
|
|
16
|
+
var HttpError = class extends Error {
|
|
17
|
+
constructor(message, status, url) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.status = status;
|
|
20
|
+
this.url = url;
|
|
21
|
+
this.name = "HttpError";
|
|
22
|
+
}
|
|
23
|
+
status;
|
|
24
|
+
url;
|
|
25
|
+
};
|
|
26
|
+
var DEFAULT_HOST_CONFIG = { maxConcurrent: 6, minIntervalMs: 0 };
|
|
27
|
+
var HOST_CONFIG = {
|
|
28
|
+
"api.github.com": { maxConcurrent: 4, minIntervalMs: 50 },
|
|
29
|
+
"registry.npmjs.org": { maxConcurrent: 4, minIntervalMs: 50 },
|
|
30
|
+
// The downloads API rate-limits aggressively — serialize with a steady gap.
|
|
31
|
+
// Weekly downloads go through the bulk endpoint; only growth hits this often.
|
|
32
|
+
"api.npmjs.org": { maxConcurrent: 1, minIntervalMs: 250 },
|
|
33
|
+
"api.deps.dev": { maxConcurrent: 4, minIntervalMs: 40 },
|
|
34
|
+
"raw.githubusercontent.com": { maxConcurrent: 4, minIntervalMs: 30 },
|
|
35
|
+
// Bundlephobia is slow/flaky — be gentle (§9.5).
|
|
36
|
+
"bundlephobia.com": { maxConcurrent: 2, minIntervalMs: 200 }
|
|
37
|
+
};
|
|
38
|
+
var HostLimiter = class {
|
|
39
|
+
constructor(config) {
|
|
40
|
+
this.config = config;
|
|
41
|
+
}
|
|
42
|
+
config;
|
|
43
|
+
active = 0;
|
|
44
|
+
nextAvailable = 0;
|
|
45
|
+
queue = [];
|
|
46
|
+
async acquire() {
|
|
47
|
+
if (this.active >= this.config.maxConcurrent) {
|
|
48
|
+
await new Promise((resolve) => this.queue.push(resolve));
|
|
49
|
+
}
|
|
50
|
+
this.active++;
|
|
51
|
+
const now = Date.now();
|
|
52
|
+
const wait = Math.max(0, this.nextAvailable - now);
|
|
53
|
+
this.nextAvailable = Math.max(now, this.nextAvailable) + this.config.minIntervalMs;
|
|
54
|
+
if (wait > 0) await delay(wait);
|
|
55
|
+
}
|
|
56
|
+
release() {
|
|
57
|
+
this.active--;
|
|
58
|
+
const next = this.queue.shift();
|
|
59
|
+
if (next) next();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var limiters = /* @__PURE__ */ new Map();
|
|
63
|
+
function limiterFor(host) {
|
|
64
|
+
let limiter = limiters.get(host);
|
|
65
|
+
if (!limiter) {
|
|
66
|
+
limiter = new HostLimiter(HOST_CONFIG[host] ?? DEFAULT_HOST_CONFIG);
|
|
67
|
+
limiters.set(host, limiter);
|
|
68
|
+
}
|
|
69
|
+
return limiter;
|
|
70
|
+
}
|
|
71
|
+
var MEMORY_CACHE_MAX = 500;
|
|
72
|
+
var memoryCache = /* @__PURE__ */ new Map();
|
|
73
|
+
function memoryCacheSet(key, entry) {
|
|
74
|
+
memoryCache.delete(key);
|
|
75
|
+
memoryCache.set(key, entry);
|
|
76
|
+
if (memoryCache.size > MEMORY_CACHE_MAX) {
|
|
77
|
+
const oldest = memoryCache.keys().next();
|
|
78
|
+
if (!oldest.done) memoryCache.delete(oldest.value);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
var bypassCacheRead = false;
|
|
82
|
+
function cacheDir() {
|
|
83
|
+
return process.env.LURQ_CACHE_DIR ?? join(homedir(), ".cache", "lurq", "http");
|
|
84
|
+
}
|
|
85
|
+
function cacheFile(key) {
|
|
86
|
+
const hash = createHash("sha256").update(key).digest("hex");
|
|
87
|
+
return join(cacheDir(), `${hash}.json`);
|
|
88
|
+
}
|
|
89
|
+
async function readCache(key, ttlMs) {
|
|
90
|
+
const now = Date.now();
|
|
91
|
+
const mem = memoryCache.get(key);
|
|
92
|
+
if (mem && now - mem.fetchedAt < ttlMs) {
|
|
93
|
+
memoryCacheSet(key, mem);
|
|
94
|
+
return mem;
|
|
95
|
+
}
|
|
96
|
+
const file = cacheFile(key);
|
|
97
|
+
if (!existsSync(file)) return void 0;
|
|
98
|
+
try {
|
|
99
|
+
const entry = JSON.parse(await readFile(file, "utf8"));
|
|
100
|
+
if (now - entry.fetchedAt < ttlMs) {
|
|
101
|
+
memoryCacheSet(key, entry);
|
|
102
|
+
return entry;
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
return void 0;
|
|
107
|
+
}
|
|
108
|
+
async function writeCache(key, entry) {
|
|
109
|
+
memoryCacheSet(key, entry);
|
|
110
|
+
const file = cacheFile(key);
|
|
111
|
+
try {
|
|
112
|
+
await mkdir(dirname(file), { recursive: true });
|
|
113
|
+
await writeFile(file, JSON.stringify(entry), "utf8");
|
|
114
|
+
} catch (err) {
|
|
115
|
+
logger.debug(`http cache write failed: ${err.message}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
var RETRYABLE = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
119
|
+
async function httpRequest(url, opts) {
|
|
120
|
+
const {
|
|
121
|
+
host,
|
|
122
|
+
ttlMs,
|
|
123
|
+
method = "GET",
|
|
124
|
+
headers = {},
|
|
125
|
+
body,
|
|
126
|
+
accept = "json",
|
|
127
|
+
timeoutMs = 15e3,
|
|
128
|
+
retries = 3,
|
|
129
|
+
fetchImpl = fetch
|
|
130
|
+
} = opts;
|
|
131
|
+
const key = opts.cacheKey ?? `${method} ${url} ${body ?? ""}`;
|
|
132
|
+
if (ttlMs > 0 && !bypassCacheRead && !opts.fresh) {
|
|
133
|
+
const cached = await readCache(key, ttlMs);
|
|
134
|
+
if (cached) {
|
|
135
|
+
return { status: cached.status, data: decode(cached.body, accept), fromCache: true };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const limiter = limiterFor(host);
|
|
139
|
+
let lastErr;
|
|
140
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
141
|
+
await limiter.acquire();
|
|
142
|
+
const controller = new AbortController();
|
|
143
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
144
|
+
try {
|
|
145
|
+
const res = await fetchImpl(url, { method, headers, body, signal: controller.signal });
|
|
146
|
+
const text = await res.text();
|
|
147
|
+
if (res.ok) {
|
|
148
|
+
if (ttlMs > 0)
|
|
149
|
+
await writeCache(key, { fetchedAt: Date.now(), status: res.status, body: text });
|
|
150
|
+
return { status: res.status, data: decode(text, accept), fromCache: false };
|
|
151
|
+
}
|
|
152
|
+
if (RETRYABLE.has(res.status) && attempt < retries) {
|
|
153
|
+
const retryAfter = parseRetryAfter(res.headers.get("retry-after"));
|
|
154
|
+
await delay(retryAfter ?? backoff(attempt));
|
|
155
|
+
lastErr = new HttpError(`HTTP ${res.status} for ${url}`, res.status, url);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
throw new HttpError(`HTTP ${res.status} for ${url}`, res.status, url);
|
|
159
|
+
} catch (err) {
|
|
160
|
+
lastErr = err;
|
|
161
|
+
const isAbort = err instanceof Error && err.name === "AbortError";
|
|
162
|
+
const isHttp = err instanceof HttpError;
|
|
163
|
+
if (isHttp && !RETRYABLE.has(err.status)) throw err;
|
|
164
|
+
if (attempt < retries) {
|
|
165
|
+
await delay(backoff(attempt));
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (isAbort) throw new HttpError(`Timeout after ${timeoutMs}ms for ${url}`, 0, url);
|
|
169
|
+
} finally {
|
|
170
|
+
clearTimeout(timer);
|
|
171
|
+
limiter.release();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
throw lastErr instanceof Error ? lastErr : new HttpError(`Request failed for ${url}`, 0, url);
|
|
175
|
+
}
|
|
176
|
+
async function httpGetJson(url, opts) {
|
|
177
|
+
return httpRequest(url, { ...opts, method: "GET", accept: "json" });
|
|
178
|
+
}
|
|
179
|
+
function decode(text, accept) {
|
|
180
|
+
if (accept === "text") return text;
|
|
181
|
+
return text ? JSON.parse(text) : null;
|
|
182
|
+
}
|
|
183
|
+
function backoff(attempt) {
|
|
184
|
+
const base = 500 * 2 ** attempt;
|
|
185
|
+
return base + Math.floor(attempt * 137 % 100 * 3);
|
|
186
|
+
}
|
|
187
|
+
function parseRetryAfter(value) {
|
|
188
|
+
if (!value) return void 0;
|
|
189
|
+
const seconds = Number(value);
|
|
190
|
+
if (!Number.isNaN(seconds)) return seconds * 1e3;
|
|
191
|
+
const date = Date.parse(value);
|
|
192
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
|
|
193
|
+
}
|
|
194
|
+
function delay(ms) {
|
|
195
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export {
|
|
199
|
+
HttpError,
|
|
200
|
+
httpRequest,
|
|
201
|
+
httpGetJson
|
|
202
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
logger
|
|
4
|
+
} from "./chunk-MYGSLK44.js";
|
|
5
|
+
import {
|
|
6
|
+
init_esm_shims
|
|
7
|
+
} from "./chunk-I3M2KJXB.js";
|
|
8
|
+
|
|
9
|
+
// src/surface/mcpRegistry.ts
|
|
10
|
+
init_esm_shims();
|
|
11
|
+
var REGISTRY = "https://registry.modelcontextprotocol.io/v0.1";
|
|
12
|
+
var TIMEOUT_MS = 8e3;
|
|
13
|
+
var memo = /* @__PURE__ */ new Map();
|
|
14
|
+
async function getJson(url) {
|
|
15
|
+
const ctl = new AbortController();
|
|
16
|
+
const timer = setTimeout(() => ctl.abort(), TIMEOUT_MS);
|
|
17
|
+
try {
|
|
18
|
+
const res = await fetch(url, { signal: ctl.signal, headers: { accept: "application/json" } });
|
|
19
|
+
if (!res.ok) return null;
|
|
20
|
+
return await res.json();
|
|
21
|
+
} catch (err) {
|
|
22
|
+
logger.debug?.({ url, err: String(err) }, "mcp registry unreachable");
|
|
23
|
+
return null;
|
|
24
|
+
} finally {
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function toManifest(server, npmPackage) {
|
|
29
|
+
const pkg = (server.packages ?? []).find(
|
|
30
|
+
(p) => p.registryType === "npm" && p.identifier === npmPackage
|
|
31
|
+
);
|
|
32
|
+
const remoteOnly = !pkg && (server.remotes ?? []).length > 0;
|
|
33
|
+
if (!pkg && !remoteOnly) return null;
|
|
34
|
+
const args = [...pkg?.runtimeArguments ?? [], ...pkg?.packageArguments ?? []].map((a) => a.value ?? a.name).filter((a) => typeof a === "string" && a.length > 0);
|
|
35
|
+
return {
|
|
36
|
+
registryName: server.name ?? npmPackage,
|
|
37
|
+
npmPackage,
|
|
38
|
+
version: pkg?.version ?? server.version ?? null,
|
|
39
|
+
transport: pkg?.transport?.type ?? (remoteOnly ? server.remotes?.[0]?.type ?? null : null),
|
|
40
|
+
env: (pkg?.environmentVariables ?? []).map((e) => ({
|
|
41
|
+
name: e.name ?? "",
|
|
42
|
+
description: e.description ?? null,
|
|
43
|
+
required: e.isRequired === true,
|
|
44
|
+
secret: e.isSecret === true,
|
|
45
|
+
format: e.format ?? null
|
|
46
|
+
})).filter((e) => e.name.length > 0),
|
|
47
|
+
args,
|
|
48
|
+
remoteOnly
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function fetchServerManifest(npmPackage) {
|
|
52
|
+
const hit = memo.get(npmPackage);
|
|
53
|
+
if (hit !== void 0) return hit;
|
|
54
|
+
const body = await getJson(
|
|
55
|
+
`${REGISTRY}/servers?search=${encodeURIComponent(npmPackage)}&limit=20`
|
|
56
|
+
);
|
|
57
|
+
let found = null;
|
|
58
|
+
for (const row of body?.servers ?? []) {
|
|
59
|
+
const m = row.server ? toManifest(row.server, npmPackage) : null;
|
|
60
|
+
if (m) {
|
|
61
|
+
found = m;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
memo.set(npmPackage, found);
|
|
66
|
+
return found;
|
|
67
|
+
}
|
|
68
|
+
function missingConfig(manifest, env = process.env) {
|
|
69
|
+
return (manifest?.env ?? []).filter((e) => e.required && !env[e.name]);
|
|
70
|
+
}
|
|
71
|
+
function configRequestLine(server, missing) {
|
|
72
|
+
if (missing.length === 0) return "";
|
|
73
|
+
const items = missing.map((m) => `${m.name}${m.description ? ` (${m.description})` : ""}`).join("; ");
|
|
74
|
+
return `${server} declares ${missing.length} required setting(s) before it will start: ${items}. Ask the user to supply ${missing.some((m) => m.secret) ? "these values (at least one is a credential \u2014 take it from the user, never from a log or a guess)" : "these values"}, then re-run the probe with them set.`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
fetchServerManifest,
|
|
79
|
+
missingConfig,
|
|
80
|
+
configRequestLine
|
|
81
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-I3M2KJXB.js";
|
|
5
|
+
|
|
6
|
+
// src/core/paths.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
import { existsSync } from "fs";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import { dirname, join } from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
var cachedRoot;
|
|
13
|
+
function packageRoot() {
|
|
14
|
+
if (cachedRoot) return cachedRoot;
|
|
15
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
for (; ; ) {
|
|
17
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
18
|
+
cachedRoot = dir;
|
|
19
|
+
return dir;
|
|
20
|
+
}
|
|
21
|
+
const parent = dirname(dir);
|
|
22
|
+
if (parent === dir) break;
|
|
23
|
+
dir = parent;
|
|
24
|
+
}
|
|
25
|
+
cachedRoot = process.cwd();
|
|
26
|
+
return cachedRoot;
|
|
27
|
+
}
|
|
28
|
+
function userWeightsPath() {
|
|
29
|
+
const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
30
|
+
return join(base, "lurq", "weights.json");
|
|
31
|
+
}
|
|
32
|
+
function projectWeightsPath() {
|
|
33
|
+
return join(process.cwd(), ".lurq", "weights.json");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
packageRoot,
|
|
38
|
+
userWeightsPath,
|
|
39
|
+
projectWeightsPath
|
|
40
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-I3M2KJXB.js";
|
|
5
|
+
|
|
6
|
+
// src/core/errors.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
var DEFAULT_MAX = 300;
|
|
9
|
+
function truncate(text, max) {
|
|
10
|
+
if (text.length <= max) return text;
|
|
11
|
+
return `${text.slice(0, max)}\u2026`;
|
|
12
|
+
}
|
|
13
|
+
function causeText(cause) {
|
|
14
|
+
if (cause == null) return null;
|
|
15
|
+
if (cause instanceof Error) {
|
|
16
|
+
const code = "code" in cause && (typeof cause.code === "string" || typeof cause.code === "number") ? String(cause.code) : null;
|
|
17
|
+
const msg = truncate(cause.message, DEFAULT_MAX);
|
|
18
|
+
return code ? `${code}: ${msg}` : msg;
|
|
19
|
+
}
|
|
20
|
+
if (typeof cause === "object" && cause !== null && "message" in cause) {
|
|
21
|
+
const msg = truncate(String(cause.message), DEFAULT_MAX);
|
|
22
|
+
const code = "code" in cause ? String(cause.code) : null;
|
|
23
|
+
return code ? `${code}: ${msg}` : msg;
|
|
24
|
+
}
|
|
25
|
+
return truncate(String(cause), DEFAULT_MAX);
|
|
26
|
+
}
|
|
27
|
+
function formatError(err, max = DEFAULT_MAX) {
|
|
28
|
+
const message = err instanceof Error ? truncate(err.message, max) : truncate(String(err), max);
|
|
29
|
+
const cause = err instanceof Error ? causeText(err.cause) : null;
|
|
30
|
+
return cause ? `${message} (cause: ${cause})` : message;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
formatError
|
|
35
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-I3M2KJXB.js";
|
|
5
|
+
|
|
6
|
+
// src/core/logger.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
var LEVELS = { error: 0, warn: 1, info: 2, debug: 3 };
|
|
9
|
+
function currentLevel() {
|
|
10
|
+
const raw = process.env.LOG_LEVEL;
|
|
11
|
+
return raw && raw in LEVELS ? LEVELS[raw] : LEVELS.info;
|
|
12
|
+
}
|
|
13
|
+
function emit(level, args) {
|
|
14
|
+
if (LEVELS[level] > currentLevel()) return;
|
|
15
|
+
const parts = args.map(
|
|
16
|
+
(a) => typeof a === "string" ? a : a instanceof Error ? a.stack ?? a.message : safeStringify(a)
|
|
17
|
+
);
|
|
18
|
+
process.stderr.write(`[lurq] ${level.toUpperCase()} ${parts.join(" ")}
|
|
19
|
+
`);
|
|
20
|
+
}
|
|
21
|
+
function safeStringify(value) {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.stringify(value);
|
|
24
|
+
} catch {
|
|
25
|
+
return String(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
var logger = {
|
|
29
|
+
error: (...args) => emit("error", args),
|
|
30
|
+
warn: (...args) => emit("warn", args),
|
|
31
|
+
info: (...args) => emit("info", args),
|
|
32
|
+
debug: (...args) => emit("debug", args)
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export {
|
|
36
|
+
logger
|
|
37
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
JSONRPCMessageSchema
|
|
4
|
+
} from "./chunk-D3K6IZVR.js";
|
|
5
|
+
import {
|
|
6
|
+
init_esm_shims
|
|
7
|
+
} from "./chunk-I3M2KJXB.js";
|
|
8
|
+
|
|
9
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
10
|
+
init_esm_shims();
|
|
11
|
+
var ReadBuffer = class {
|
|
12
|
+
append(chunk) {
|
|
13
|
+
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
14
|
+
}
|
|
15
|
+
readMessage() {
|
|
16
|
+
if (!this._buffer) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const index = this._buffer.indexOf("\n");
|
|
20
|
+
if (index === -1) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
24
|
+
this._buffer = this._buffer.subarray(index + 1);
|
|
25
|
+
return deserializeMessage(line);
|
|
26
|
+
}
|
|
27
|
+
clear() {
|
|
28
|
+
this._buffer = void 0;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
function deserializeMessage(line) {
|
|
32
|
+
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
33
|
+
}
|
|
34
|
+
function serializeMessage(message) {
|
|
35
|
+
return JSON.stringify(message) + "\n";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
ReadBuffer,
|
|
40
|
+
serializeMessage
|
|
41
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_ECOSYSTEM
|
|
4
|
+
} from "./chunk-VLRHFMGJ.js";
|
|
5
|
+
import {
|
|
6
|
+
packageVersions,
|
|
7
|
+
packages,
|
|
8
|
+
seedPackages,
|
|
9
|
+
syncRuns
|
|
10
|
+
} from "./chunk-4JHDSVIN.js";
|
|
11
|
+
import {
|
|
12
|
+
logger
|
|
13
|
+
} from "./chunk-MYGSLK44.js";
|
|
14
|
+
import {
|
|
15
|
+
init_esm_shims
|
|
16
|
+
} from "./chunk-I3M2KJXB.js";
|
|
17
|
+
|
|
18
|
+
// src/db/packages.ts
|
|
19
|
+
init_esm_shims();
|
|
20
|
+
import { and, desc, eq, gte, inArray, isNotNull, isNull, lt, notExists, sql } from "drizzle-orm";
|
|
21
|
+
var VERSION_CHUNK = 500;
|
|
22
|
+
var NAME_CHUNK = 500;
|
|
23
|
+
async function getSeedTargets(db) {
|
|
24
|
+
const rows = await db.select({ name: seedPackages.name, category: seedPackages.category }).from(seedPackages);
|
|
25
|
+
return rows.map((r) => ({ name: r.name, category: r.category ?? null }));
|
|
26
|
+
}
|
|
27
|
+
async function getStaleRefreshTargets(db, limit) {
|
|
28
|
+
if (limit <= 0) return [];
|
|
29
|
+
const rows = await db.select({
|
|
30
|
+
name: packages.name,
|
|
31
|
+
category: sql`case when ${packages.categorySource} = 'curated' then ${packages.category} end`
|
|
32
|
+
}).from(packages).where(
|
|
33
|
+
notExists(
|
|
34
|
+
db.select({ one: sql`1` }).from(seedPackages).where(eq(seedPackages.name, packages.name))
|
|
35
|
+
)
|
|
36
|
+
).orderBy(sql`${packages.dataAsOf} asc nulls first`).limit(limit);
|
|
37
|
+
return rows.map((r) => ({ name: r.name, category: r.category ?? null }));
|
|
38
|
+
}
|
|
39
|
+
async function getPackageByName(db, name, ecosystem = DEFAULT_ECOSYSTEM) {
|
|
40
|
+
const rows = await db.select().from(packages).where(and(eq(packages.name, name), eq(packages.ecosystem, ecosystem))).limit(1);
|
|
41
|
+
return rows[0] ?? null;
|
|
42
|
+
}
|
|
43
|
+
async function latestVersionsFor(db, names, ecosystem = DEFAULT_ECOSYSTEM) {
|
|
44
|
+
const out = /* @__PURE__ */ new Map();
|
|
45
|
+
for (let i = 0; i < names.length; i += NAME_CHUNK) {
|
|
46
|
+
const rows = await db.select({ name: packages.name, latestVersion: packages.latestVersion }).from(packages).where(
|
|
47
|
+
and(
|
|
48
|
+
inArray(packages.name, names.slice(i, i + NAME_CHUNK)),
|
|
49
|
+
eq(packages.ecosystem, ecosystem)
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
for (const row of rows) out.set(row.name, row.latestVersion);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
async function reusableFieldsFor(db, names, ecosystem = DEFAULT_ECOSYSTEM) {
|
|
57
|
+
const out = /* @__PURE__ */ new Map();
|
|
58
|
+
for (let i = 0; i < names.length; i += NAME_CHUNK) {
|
|
59
|
+
const rows = await db.select({
|
|
60
|
+
name: packages.name,
|
|
61
|
+
latestVersion: packages.latestVersion,
|
|
62
|
+
summary: packages.summary,
|
|
63
|
+
usageGuide: packages.usageGuide,
|
|
64
|
+
embedding: packages.embedding,
|
|
65
|
+
embeddingProvider: packages.embeddingProvider
|
|
66
|
+
}).from(packages).where(
|
|
67
|
+
and(
|
|
68
|
+
inArray(packages.name, names.slice(i, i + NAME_CHUNK)),
|
|
69
|
+
eq(packages.ecosystem, ecosystem)
|
|
70
|
+
)
|
|
71
|
+
);
|
|
72
|
+
for (const row of rows) {
|
|
73
|
+
const { name, ...fields } = row;
|
|
74
|
+
out.set(name, fields);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
async function getAllPackageNames(db, ecosystem = DEFAULT_ECOSYSTEM) {
|
|
80
|
+
const rows = await db.select({ name: packages.name }).from(packages).where(eq(packages.ecosystem, ecosystem));
|
|
81
|
+
return rows.map((r) => r.name);
|
|
82
|
+
}
|
|
83
|
+
async function getPackageNamesCreatedSince(db, since) {
|
|
84
|
+
const rows = await db.select({ name: packages.name }).from(packages).where(gte(packages.createdAt, since));
|
|
85
|
+
return rows.map((r) => r.name);
|
|
86
|
+
}
|
|
87
|
+
async function upsertPackageVersions(db, name, versions) {
|
|
88
|
+
if (versions.length === 0) {
|
|
89
|
+
logger.debug(`no version timeline to store for ${name}: registry returned none`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
for (let i = 0; i < versions.length; i += VERSION_CHUNK) {
|
|
93
|
+
const rows = versions.slice(i, i + VERSION_CHUNK).map((v) => ({
|
|
94
|
+
packageName: name,
|
|
95
|
+
version: v.version,
|
|
96
|
+
publishedAt: v.publishedAt,
|
|
97
|
+
peerDependencies: v.peerDependencies ?? null,
|
|
98
|
+
engines: v.engines ?? null
|
|
99
|
+
}));
|
|
100
|
+
await db.insert(packageVersions).values(rows).onConflictDoNothing();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async function getPackageVersions(db, name, limit = 50) {
|
|
104
|
+
const rows = await db.select({ version: packageVersions.version, publishedAt: packageVersions.publishedAt }).from(packageVersions).where(eq(packageVersions.packageName, name)).orderBy(desc(packageVersions.publishedAt)).limit(limit);
|
|
105
|
+
return rows.map((r) => ({ version: r.version, publishedAt: r.publishedAt }));
|
|
106
|
+
}
|
|
107
|
+
async function getTopPackageNames(db, limit = 1e3) {
|
|
108
|
+
const rows = await db.select({ name: packages.name }).from(packages).where(isNotNull(packages.weeklyDownloads)).orderBy(desc(packages.weeklyDownloads)).limit(limit);
|
|
109
|
+
return rows.map((r) => r.name);
|
|
110
|
+
}
|
|
111
|
+
async function upsertPackage(db, row) {
|
|
112
|
+
const { name: _name, ecosystem: _ecosystem, createdAt: _createdAt, ...mutable } = row;
|
|
113
|
+
await db.insert(packages).values(row).onConflictDoUpdate({
|
|
114
|
+
target: [packages.ecosystem, packages.name],
|
|
115
|
+
set: { ...mutable, updatedAt: /* @__PURE__ */ new Date() }
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async function stampFirstRequester(db, name, ownerId, ecosystem = DEFAULT_ECOSYSTEM) {
|
|
119
|
+
await db.update(packages).set({ firstRequestedByOwnerId: ownerId }).where(
|
|
120
|
+
and(
|
|
121
|
+
eq(packages.name, name),
|
|
122
|
+
eq(packages.ecosystem, ecosystem),
|
|
123
|
+
isNull(packages.firstRequestedByOwnerId)
|
|
124
|
+
)
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
async function getContributionsByOwner(db, ownerId, opts = {}) {
|
|
128
|
+
const limit = opts.limit ?? 50;
|
|
129
|
+
const offset = opts.offset ?? 0;
|
|
130
|
+
const [rows, [countRow]] = await Promise.all([
|
|
131
|
+
db.select({
|
|
132
|
+
name: packages.name,
|
|
133
|
+
category: packages.category,
|
|
134
|
+
healthScore: packages.healthScore,
|
|
135
|
+
firstRequestedAt: packages.createdAt
|
|
136
|
+
}).from(packages).where(eq(packages.firstRequestedByOwnerId, ownerId)).orderBy(desc(packages.createdAt)).limit(limit).offset(offset),
|
|
137
|
+
db.select({ count: sql`count(*)::int` }).from(packages).where(eq(packages.firstRequestedByOwnerId, ownerId))
|
|
138
|
+
]);
|
|
139
|
+
return { total: countRow?.count ?? 0, packages: rows };
|
|
140
|
+
}
|
|
141
|
+
function syncOrigin() {
|
|
142
|
+
const env = process.env.RAILWAY_ENVIRONMENT_NAME;
|
|
143
|
+
const service = process.env.RAILWAY_SERVICE_NAME;
|
|
144
|
+
if (!env && !service) return null;
|
|
145
|
+
return `${env ?? "?"}/${service ?? "?"}`;
|
|
146
|
+
}
|
|
147
|
+
var SYNC_STALE_MS = 6 * 60 * 60 * 1e3;
|
|
148
|
+
async function reapAbandonedSyncRuns(db) {
|
|
149
|
+
await db.update(syncRuns).set({
|
|
150
|
+
status: "failed",
|
|
151
|
+
finishedAt: /* @__PURE__ */ new Date(),
|
|
152
|
+
errors: [
|
|
153
|
+
{
|
|
154
|
+
package: "*",
|
|
155
|
+
source: "pipeline",
|
|
156
|
+
message: "abandoned: the process died before writing a terminal status"
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}).where(
|
|
160
|
+
and(
|
|
161
|
+
eq(syncRuns.status, "running"),
|
|
162
|
+
lt(syncRuns.startedAt, new Date(Date.now() - SYNC_STALE_MS))
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
async function startSyncRun(db) {
|
|
167
|
+
await reapAbandonedSyncRuns(db);
|
|
168
|
+
const [row] = await db.insert(syncRuns).values({ status: "running", origin: syncOrigin() }).returning({ id: syncRuns.id });
|
|
169
|
+
return row.id;
|
|
170
|
+
}
|
|
171
|
+
async function finishSyncRun(db, id, data) {
|
|
172
|
+
await db.update(syncRuns).set({
|
|
173
|
+
finishedAt: /* @__PURE__ */ new Date(),
|
|
174
|
+
packagesSeen: data.packagesSeen,
|
|
175
|
+
packagesUpdated: data.packagesUpdated,
|
|
176
|
+
errors: data.errors,
|
|
177
|
+
status: data.status
|
|
178
|
+
}).where(eq(syncRuns.id, id));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export {
|
|
182
|
+
getSeedTargets,
|
|
183
|
+
getStaleRefreshTargets,
|
|
184
|
+
getPackageByName,
|
|
185
|
+
latestVersionsFor,
|
|
186
|
+
reusableFieldsFor,
|
|
187
|
+
getAllPackageNames,
|
|
188
|
+
getPackageNamesCreatedSince,
|
|
189
|
+
upsertPackageVersions,
|
|
190
|
+
getPackageVersions,
|
|
191
|
+
getTopPackageNames,
|
|
192
|
+
upsertPackage,
|
|
193
|
+
stampFirstRequester,
|
|
194
|
+
getContributionsByOwner,
|
|
195
|
+
startSyncRun,
|
|
196
|
+
finishSyncRun
|
|
197
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
verificationRuns
|
|
4
|
+
} from "./chunk-4JHDSVIN.js";
|
|
5
|
+
import {
|
|
6
|
+
init_esm_shims
|
|
7
|
+
} from "./chunk-I3M2KJXB.js";
|
|
8
|
+
|
|
9
|
+
// src/db/verification.ts
|
|
10
|
+
init_esm_shims();
|
|
11
|
+
import { desc, eq } from "drizzle-orm";
|
|
12
|
+
async function storeVerificationRun(db, run) {
|
|
13
|
+
await db.insert(verificationRuns).values(run);
|
|
14
|
+
}
|
|
15
|
+
async function getLatestVerificationByName(db, packageName) {
|
|
16
|
+
const rows = await db.select().from(verificationRuns).where(eq(verificationRuns.packageName, packageName)).orderBy(desc(verificationRuns.ranAt)).limit(1);
|
|
17
|
+
return rows[0] ?? null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
storeVerificationRun,
|
|
22
|
+
getLatestVerificationByName
|
|
23
|
+
};
|