lurqrun 0.1.0 → 0.1.3
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/LICENSE +21 -201
- package/README.md +91 -68
- package/dist/bin/lurq.js +9562 -3444
- package/dist/bin/lurq.js.map +1 -1
- package/dist/index.d.ts +300 -15
- package/dist/index.js +10958 -4838
- package/dist/index.js.map +1 -1
- package/drizzle/0028_romantic_loners.sql +2 -0
- package/drizzle/0029_busy_korvac.sql +16 -0
- package/drizzle/0030_steady_mathemanic.sql +6 -0
- package/drizzle/0031_redundant_maginty.sql +2 -0
- package/drizzle/0032_stack_resolutions.sql +14 -0
- package/drizzle/0033_graceful_tyger_tiger.sql +3 -0
- package/drizzle/0034_api_key_scopes.sql +1 -0
- package/drizzle/0035_policy_audit.sql +21 -0
- package/drizzle/meta/0028_snapshot.json +2438 -0
- package/drizzle/meta/0029_snapshot.json +2546 -0
- package/drizzle/meta/0030_snapshot.json +2586 -0
- package/drizzle/meta/0031_snapshot.json +2598 -0
- package/drizzle/meta/0032_snapshot.json +2699 -0
- package/drizzle/meta/0033_snapshot.json +2712 -0
- package/drizzle/meta/0034_snapshot.json +2719 -0
- package/drizzle/meta/0035_snapshot.json +2869 -0
- package/drizzle/meta/_journal.json +56 -0
- package/package.json +7 -3
- package/templates/agent-rules.md +5 -0
- package/templates/skill-instructions.md +47 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,137 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The single answer to "is it safe to install this?".
|
|
6
|
+
*
|
|
7
|
+
* This exists because lurq had several. `verify` rolled risk flags into a
|
|
8
|
+
* level, `evaluate` reported a health score and a confidence tier, and `audit`
|
|
9
|
+
* emitted findings — three code paths deriving safety from overlapping inputs
|
|
10
|
+
* and disagreeing about the same package. A tool that answers one question
|
|
11
|
+
* three ways has not answered it, and the disagreement always surfaced at the
|
|
12
|
+
* worst moment, because the paths diverge exactly where the evidence is thin.
|
|
13
|
+
*
|
|
14
|
+
* Every surface now calls this and renders what it returns. Adding a signal
|
|
15
|
+
* means editing one file, and no caller can accidentally be more reassuring
|
|
16
|
+
* than the evidence supports.
|
|
17
|
+
*
|
|
18
|
+
* Three rules, each of which was a real defect:
|
|
19
|
+
*
|
|
20
|
+
* 1. A SECURITY FINDING OVERRIDES QUALITY. A package with a known advisory is
|
|
21
|
+
* not "safe" because it is popular and well maintained. The health score
|
|
22
|
+
* stays a quality measure — it is not fudged — but it never sets the
|
|
23
|
+
* verdict, and the verdict is what every surface leads with.
|
|
24
|
+
*
|
|
25
|
+
* 2. UNKNOWN IS NOT CLEAN. `advisories` is NULL until the package has been
|
|
26
|
+
* analysed and `[]` once it has, and collapsing those with `?? []` reported
|
|
27
|
+
* "0 advisories" for a package nobody had looked at yet. Missing evidence
|
|
28
|
+
* is carried in `unknowns` and suppresses reassurance outright.
|
|
29
|
+
*
|
|
30
|
+
* 3. A NAME THAT DOES NOT EXIST IS NOT A RISK RATING. It is bad input, and
|
|
31
|
+
* saying "high risk" invites the reader to weigh it against a benefit. There
|
|
32
|
+
* is no package to weigh.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* `invalid` is deliberately outside `RiskLevel`: it is a statement about the
|
|
37
|
+
* INPUT, not about a package, and flattening it into `high` loses the only
|
|
38
|
+
* thing the caller can act on — that there is nothing here to install.
|
|
39
|
+
*/
|
|
40
|
+
type VerdictLevel = RiskLevel | 'invalid';
|
|
41
|
+
interface SecurityVerdict {
|
|
42
|
+
level: VerdictLevel;
|
|
43
|
+
/** Why this is not clean, worst first. Empty only when nothing was found. */
|
|
44
|
+
reasons: string[];
|
|
45
|
+
/**
|
|
46
|
+
* What was NOT established. Non-empty means `level` is provisional: it is the
|
|
47
|
+
* worst we can currently justify, not the worst that is true.
|
|
48
|
+
*/
|
|
49
|
+
unknowns: string[];
|
|
50
|
+
/** Every input needed to justify a clean bill was present. */
|
|
51
|
+
complete: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Safe to render as reassurance ("looks safe", a green tick).
|
|
54
|
+
*
|
|
55
|
+
* The one flag every renderer must consult. It requires a low level AND no
|
|
56
|
+
* findings AND nothing unchecked, so a caller cannot produce a green tick
|
|
57
|
+
* over a gap in the evidence by reading `level` alone.
|
|
58
|
+
*/
|
|
59
|
+
reassuring: boolean;
|
|
60
|
+
/** Advisories actually recorded. Null when none have been fetched yet. */
|
|
61
|
+
advisoryCount: number | null;
|
|
62
|
+
/**
|
|
63
|
+
* WHICH version this verdict is about, in words a reader can act on.
|
|
64
|
+
*
|
|
65
|
+
* Without it the surfaces agree and still mislead. `verify vitest` answers
|
|
66
|
+
* about the latest release and says "no problems found"; the audit answers
|
|
67
|
+
* about the 2.1.9 you have installed and says "vulnerable". Both are correct
|
|
68
|
+
* and they read as a contradiction, because neither said what it was talking
|
|
69
|
+
* about. A clean bill for the newest version is not a clean bill for the one
|
|
70
|
+
* running in your node_modules.
|
|
71
|
+
*/
|
|
72
|
+
scope: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
4
75
|
/**
|
|
5
76
|
* Shared domain types and the v1 category taxonomy (§8.3).
|
|
6
77
|
* These are the stable contracts the rest of the system builds on.
|
|
7
78
|
*/
|
|
79
|
+
/**
|
|
80
|
+
* Which registry a package lives in.
|
|
81
|
+
*
|
|
82
|
+
* `npm` is the default everywhere — every read path defaults to it, so adding
|
|
83
|
+
* this type changed no existing behaviour. What it buys is that a package name
|
|
84
|
+
* is only unique WITHIN a registry: `requests`, `redis`, `click` and `attrs` all
|
|
85
|
+
* exist on both npm and PyPI as entirely unrelated software, and keying on the
|
|
86
|
+
* bare name would let one overwrite the other's evidence.
|
|
87
|
+
*
|
|
88
|
+
* PyPI names normalise before they are stored (PEP 503: `Flask`, `flask` and
|
|
89
|
+
* `Flask_SQLAlchemy` are the same project); that belongs in the PyPI client at
|
|
90
|
+
* the ingestion boundary, not here, so `name` always holds the canonical form.
|
|
91
|
+
*/
|
|
92
|
+
declare const ECOSYSTEMS: readonly ["npm", "pypi"];
|
|
93
|
+
type Ecosystem = (typeof ECOSYSTEMS)[number];
|
|
94
|
+
/**
|
|
95
|
+
* The registry every existing caller means when it doesn't say.
|
|
96
|
+
*
|
|
97
|
+
* Every read helper takes `ecosystem` as a DEFAULTED parameter rather than a
|
|
98
|
+
* required one. That is what let the composite key land as a pure no-op: not a
|
|
99
|
+
* single call site changed, and npm behaviour is bit-identical. A PyPI caller
|
|
100
|
+
* passes the argument; nobody else has to care.
|
|
101
|
+
*
|
|
102
|
+
* ponytail: only `packages` is keyed by registry so far. These are still keyed
|
|
103
|
+
* by bare package name and WILL collide once PyPI rows exist — each one is safe
|
|
104
|
+
* today only because nothing writes a PyPI row yet, so scope it in the phase
|
|
105
|
+
* that first makes it multi-ecosystem, not speculatively now:
|
|
106
|
+
*
|
|
107
|
+
* package_versions → needed by PyPI compat (per-version requires-dist)
|
|
108
|
+
* seed_packages → needed when a PyPI package can join the sync roster
|
|
109
|
+
* discovery_queue → needed by PyPI discovery (classifiers + BigQuery seed)
|
|
110
|
+
* api_surfaces,
|
|
111
|
+
* surface_queue,
|
|
112
|
+
* symbols, entities → needed by the Python surface worker
|
|
113
|
+
* compat_edges,
|
|
114
|
+
* resolved_closures → needed by the `uv` resolve-check
|
|
115
|
+
*
|
|
116
|
+
* The unscoped reads that go with them live in db/discovery.ts, db/apiSurfaces.ts
|
|
117
|
+
* and pipeline/discovery.ts. Adding a PyPI write path without scoping the tables
|
|
118
|
+
* it touches is how one registry starts answering for the other.
|
|
119
|
+
*
|
|
120
|
+
* RETRIEVAL IS THE ONE THIS DEFAULT CANNOT COVER, and it is the one that fails
|
|
121
|
+
* quietly. A keyed lookup has a name to disambiguate, so a defaulted argument
|
|
122
|
+
* resolves it. `search/recommend.ts` has no name — finding names IS the query —
|
|
123
|
+
* so nothing here helps it, and the first PyPI row with an embedding puts
|
|
124
|
+
* SQLAlchemy in the results for a TypeScript project. No error, just a wrong
|
|
125
|
+
* answer. Retrieval has to take its ecosystem from the REQUEST (the repo whose
|
|
126
|
+
* manifest was parsed, an explicit tool argument, or the stack the agent is
|
|
127
|
+
* editing), never from a default.
|
|
128
|
+
*
|
|
129
|
+
* Two notes for whoever wires that up: filtering the HNSW index after the fact
|
|
130
|
+
* loses recall — pre-filtered partial indexes per ecosystem keep it — and the
|
|
131
|
+
* lexical `search_vector` needs the same treatment, or the hybrid's two halves
|
|
132
|
+
* will disagree about which registry they are searching.
|
|
133
|
+
*/
|
|
134
|
+
declare const DEFAULT_ECOSYSTEM: Ecosystem;
|
|
8
135
|
/** Category taxonomy for the JS/TS web stack (§8.3). `other` is the fallback. */
|
|
9
136
|
declare const CATEGORIES: readonly ["framework", "meta-framework", "state-management", "routing", "orm", "database-client", "ui-component-library", "styling", "forms", "validation", "data-fetching", "http-client", "auth", "testing", "build-tool", "bundler", "linting", "date-time", "animation", "charts", "i18n", "utility", "other"];
|
|
10
137
|
type Category = (typeof CATEGORIES)[number];
|
|
@@ -16,7 +143,9 @@ type CategorySource = 'curated' | 'inferred';
|
|
|
16
143
|
/** How a candidate entered the discovery queue (§2B). `dependency-graph` and
|
|
17
144
|
* `recent` are the long-tail channels; `category-search` is keyword-seeded;
|
|
18
145
|
* `reactive` is an on-demand query that wasn't tracked yet. */
|
|
19
|
-
type DiscoverySource = 'dependency-graph' | 'category-search' | 'recent' | 'reactive'
|
|
146
|
+
type DiscoverySource = 'dependency-graph' | 'category-search' | 'recent' | 'reactive'
|
|
147
|
+
/** Seen on npm's `_changes` replication feed — a name we had never heard of. */
|
|
148
|
+
| 'npm-changes';
|
|
20
149
|
/** Lifecycle of a discovery-queue candidate (§2B). */
|
|
21
150
|
type DiscoveryStatus = 'pending' | 'ingested' | 'rejected';
|
|
22
151
|
/**
|
|
@@ -66,8 +195,13 @@ type PeerMeta = Record<string, {
|
|
|
66
195
|
/** One incompatibility found across a set of packages. */
|
|
67
196
|
interface CompatConflict {
|
|
68
197
|
/** Where the conflict came from. `peer-deps`/`engines` are Tier-1 (metadata,
|
|
69
|
-
* instant, deterministic); `
|
|
70
|
-
|
|
198
|
+
* instant, deterministic); `resolve` is npm's own ERESOLVE on the whole set;
|
|
199
|
+
* `sandbox` is the empirical co-install under VM isolation.
|
|
200
|
+
*
|
|
201
|
+
* A `resolve` conflict is about the SET, not a pair — npm reports that these
|
|
202
|
+
* packages cannot coexist, not which two are at fault — so `packages` carries
|
|
203
|
+
* every member and `enumeratePairs` deliberately does not attribute it. */
|
|
204
|
+
source: 'peer-deps' | 'engines' | 'sandbox' | 'resolve';
|
|
71
205
|
/** The packages involved in the conflict. */
|
|
72
206
|
packages: string[];
|
|
73
207
|
detail: string;
|
|
@@ -114,19 +248,43 @@ interface CompatEvidence {
|
|
|
114
248
|
* only corrected by a backfill, which has not been run. */
|
|
115
249
|
witnessCount: number;
|
|
116
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* How the set-level verdict was established.
|
|
253
|
+
*
|
|
254
|
+
* `source` distinguishes a cache hit from a resolve we just ran, which matters
|
|
255
|
+
* for a caller deciding whether the answer is worth re-checking: a cached entry
|
|
256
|
+
* is exact for those versions and immutable, but it was minted at `at` and the
|
|
257
|
+
* publish that would have invalidated it may not have been seen yet.
|
|
258
|
+
*/
|
|
259
|
+
interface CompatResolution {
|
|
260
|
+
source: 'cache' | 'resolved';
|
|
261
|
+
/** True when npm produced a lockfile for the exact set. */
|
|
262
|
+
resolved: boolean;
|
|
263
|
+
/** 'ERESOLVE' for a proven conflict; null when it resolved. */
|
|
264
|
+
reason: 'ERESOLVE' | null;
|
|
265
|
+
/** npm's own message on a conflict — names the packages and ranges. */
|
|
266
|
+
detail?: string;
|
|
267
|
+
/** ISO timestamp the resolution was established. */
|
|
268
|
+
at: string;
|
|
269
|
+
}
|
|
117
270
|
/**
|
|
118
271
|
* `compat` output: whole-architecture compatibility for a set of packages.
|
|
119
272
|
* Tier-1 peer-dependency/engine analysis + any Tier-2 sandbox conflicts.
|
|
120
273
|
*/
|
|
121
274
|
interface CompatOutput {
|
|
122
275
|
packages: string[];
|
|
123
|
-
/**
|
|
124
|
-
* - `conflict` —
|
|
125
|
-
*
|
|
126
|
-
* - `
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
|
|
276
|
+
/** Verdict about the *set*, not its pairs:
|
|
277
|
+
* - `conflict` — proven broken: a peer-range violation, a sandbox conflict,
|
|
278
|
+
* or npm's own ERESOLVE on this exact set.
|
|
279
|
+
* - `compatible` — npm resolved these exact versions together.
|
|
280
|
+
* - `unknown` — genuinely undetermined: a member we have no version for, or
|
|
281
|
+
* a resolve that could not complete. Never a hedge on a set
|
|
282
|
+
* we did resolve.
|
|
283
|
+
*
|
|
284
|
+
* There is deliberately no `likely`. It meant "no pair is known to be broken",
|
|
285
|
+
* which is a statement about our coverage rather than about the packages, and
|
|
286
|
+
* it was the answer real stacks got almost every time. */
|
|
287
|
+
overall: 'compatible' | 'conflict' | 'unknown';
|
|
130
288
|
conflicts: CompatConflict[];
|
|
131
289
|
/** Packages lurq has no compatibility metadata for (counted toward `unknown`). */
|
|
132
290
|
unverified: string[];
|
|
@@ -136,9 +294,12 @@ interface CompatOutput {
|
|
|
136
294
|
name: string;
|
|
137
295
|
version: string | null;
|
|
138
296
|
}[];
|
|
139
|
-
/**
|
|
140
|
-
*
|
|
297
|
+
/** Sandbox-established edges among these packages (verified/conflict) — the
|
|
298
|
+
* one pairwise signal that is not derivable from a set resolution. */
|
|
141
299
|
evidence: CompatEvidence[];
|
|
300
|
+
/** How the set-level verdict was reached. Absent when a declared conflict made
|
|
301
|
+
* a resolve unnecessary, or when a member had no version to key on. */
|
|
302
|
+
resolution?: CompatResolution;
|
|
142
303
|
/** Every unordered pair among `checked`, each with its own verdict — exactly
|
|
143
304
|
* n(n−1)/2 entries. `conflicts` lists only what went wrong; this lists what
|
|
144
305
|
* was compared, which is what lets a caller show coverage rather than just
|
|
@@ -189,6 +350,15 @@ interface UsageOutput {
|
|
|
189
350
|
delta?: SurfaceDelta & {
|
|
190
351
|
fromVersion: string;
|
|
191
352
|
};
|
|
353
|
+
/** Echo of a requested version the registry has never published. A structured
|
|
354
|
+
* flag as well as prose, so an agent can branch on "this release does not
|
|
355
|
+
* exist" without parsing `note` — it is a different answer from "we have no
|
|
356
|
+
* surface for it yet", and only one of the two means stop. */
|
|
357
|
+
unpublishedVersion?: string;
|
|
358
|
+
/** Why a requested `knownVersion` delta is absent. Only set when one was asked
|
|
359
|
+
* for and could not be produced — silence about a requested comparison reads
|
|
360
|
+
* as "no changes", which is the one thing it never means. */
|
|
361
|
+
deltaNote?: string;
|
|
192
362
|
note?: string;
|
|
193
363
|
}
|
|
194
364
|
type AdvisorySeverity = 'critical' | 'high' | 'moderate' | 'low' | 'info';
|
|
@@ -246,6 +416,23 @@ interface Candidate {
|
|
|
246
416
|
weeklyDownloads: number | null;
|
|
247
417
|
lastReleaseAt: string | null;
|
|
248
418
|
repoUrl: string | null;
|
|
419
|
+
/**
|
|
420
|
+
* The three facts that can reverse an install decision on their own.
|
|
421
|
+
*
|
|
422
|
+
* `recommend` is the call an agent makes *before* choosing a dependency, and
|
|
423
|
+
* it carried none of them: a deprecated package could be returned with nothing
|
|
424
|
+
* in the payload saying so, leaving `confidence` and a numeric score as the
|
|
425
|
+
* only hints. Deprecation caps the maintenance component and bars `proven`,
|
|
426
|
+
* but a low score reads as "less good", not "do not install this". `evaluate`
|
|
427
|
+
* and `verify` have always carried these; the tool most likely to precede an
|
|
428
|
+
* install should not be the one that hides them.
|
|
429
|
+
*
|
|
430
|
+
* Emitted even when false/zero — see mcp/compact, which keeps both on purpose,
|
|
431
|
+
* so an agent never has to read meaning into an absent field.
|
|
432
|
+
*/
|
|
433
|
+
deprecated: boolean;
|
|
434
|
+
archived: boolean;
|
|
435
|
+
advisories: number;
|
|
249
436
|
}
|
|
250
437
|
/** Full evidence read for one package (§12.3.2). */
|
|
251
438
|
interface EvaluateOutput {
|
|
@@ -265,6 +452,8 @@ interface EvaluateOutput {
|
|
|
265
452
|
bundleMinGzipKb: number | null;
|
|
266
453
|
deprecated: boolean;
|
|
267
454
|
archived: boolean;
|
|
455
|
+
/** The shared safety call — identical to what `verify` and `audit` return. */
|
|
456
|
+
verdict: SecurityVerdict;
|
|
268
457
|
advisories: Advisory[];
|
|
269
458
|
summary: string | null;
|
|
270
459
|
usageGuide: UsageGuide | null;
|
|
@@ -280,6 +469,7 @@ interface EvaluateOutput {
|
|
|
280
469
|
/** `verify` output (§12.3.4). */
|
|
281
470
|
/** Supply-chain risk gate: high = review before installing (see security/risk). */
|
|
282
471
|
type RiskLevel = 'low' | 'medium' | 'high';
|
|
472
|
+
|
|
283
473
|
interface VerifyOutput {
|
|
284
474
|
exists: boolean;
|
|
285
475
|
tracked: boolean;
|
|
@@ -293,7 +483,10 @@ interface VerifyOutput {
|
|
|
293
483
|
/** Suspected typosquat target — a popular package this name closely mimics. */
|
|
294
484
|
typosquatOf: string | null;
|
|
295
485
|
confidence: Confidence | null;
|
|
296
|
-
|
|
486
|
+
/** Null when this package has never been analysed — NOT the same as zero. */
|
|
487
|
+
advisoryCount: number | null;
|
|
488
|
+
/** The shared safety call. Read `verdict.reassuring` before showing a tick. */
|
|
489
|
+
verdict: SecurityVerdict;
|
|
297
490
|
}
|
|
298
491
|
|
|
299
492
|
declare const SERVER_NAME = "lurq";
|
|
@@ -362,12 +555,39 @@ declare const EnvSchema: z.ZodObject<{
|
|
|
362
555
|
SUMMARY_API_KEY: z.ZodOptional<z.ZodString>;
|
|
363
556
|
SUMMARY_MODEL: z.ZodDefault<z.ZodString>;
|
|
364
557
|
SUMMARY_BASE_URL: z.ZodDefault<z.ZodString>;
|
|
558
|
+
/**
|
|
559
|
+
* How many `npm install --package-lock-only` processes may run at once.
|
|
560
|
+
*
|
|
561
|
+
* Each one holds npm's arborist tree in memory — 200-500MB for a real stack —
|
|
562
|
+
* so this is a memory cap wearing a concurrency hat. Eight concurrent resolves
|
|
563
|
+
* is ~3GB and will OOM a small container; the work is network-bound anyway, so
|
|
564
|
+
* raising it buys throughput only until the box runs out of RAM.
|
|
565
|
+
*/
|
|
566
|
+
LURQ_RESOLVE_CONCURRENCY: z.ZodDefault<z.ZodNumber>;
|
|
567
|
+
/**
|
|
568
|
+
* Where npm keeps its metadata cache for stack resolution.
|
|
569
|
+
*
|
|
570
|
+
* Point this at a persistent volume in production. A warm cache is the
|
|
571
|
+
* difference between 8.6s and 19.2s on a 15-package stack (measured), and an
|
|
572
|
+
* ephemeral container filesystem means every redeploy pays cold cost again for
|
|
573
|
+
* the first few hundred resolves. Unset = npm's default location.
|
|
574
|
+
*/
|
|
575
|
+
LURQ_NPM_CACHE_DIR: z.ZodOptional<z.ZodString>;
|
|
576
|
+
/** Budget for one stack resolve. Past this the answer is `unknown`, never a
|
|
577
|
+
* guess — and nothing is cached, so the next ask gets a real attempt. */
|
|
578
|
+
LURQ_RESOLVE_TIMEOUT_MS: z.ZodDefault<z.ZodNumber>;
|
|
365
579
|
LURQ_SYNC_CONCURRENCY: z.ZodDefault<z.ZodNumber>;
|
|
366
580
|
/** Stalest non-seed packages the daily sync refreshes on top of the seed list.
|
|
367
581
|
* This is the rotation rate for everything discovery ingested: index size /
|
|
368
582
|
* this = days to come all the way around. Raise it if the sync finishes well
|
|
369
583
|
* inside the cron window; lower it if npm starts rate-limiting. 0 disables
|
|
370
|
-
* the rotation (seeds only, the pre-rotation behaviour).
|
|
584
|
+
* the rotation (seeds only, the pre-rotation behaviour).
|
|
585
|
+
*
|
|
586
|
+
* It is also the discovery frontier's clock, which is why it is not a small
|
|
587
|
+
* number. `graphChannel` re-expands a package only when its `latest_version`
|
|
588
|
+
* moves, and nothing observes a version move except this rotation — so at 400
|
|
589
|
+
* against a 20.8k index the graph channel could only re-arm on a 52-day lag
|
|
590
|
+
* and had gone effectively silent. */
|
|
371
591
|
LURQ_SYNC_REFRESH_CAP: z.ZodDefault<z.ZodNumber>;
|
|
372
592
|
LOG_LEVEL: z.ZodDefault<z.ZodEnum<["error", "warn", "info", "debug"]>>;
|
|
373
593
|
PORT: z.ZodDefault<z.ZodNumber>;
|
|
@@ -375,6 +595,11 @@ declare const EnvSchema: z.ZodObject<{
|
|
|
375
595
|
LURQ_RATE_LIMIT_MAX: z.ZodDefault<z.ZodNumber>;
|
|
376
596
|
/** Coarser per-IP rate limit (blunts unauthenticated floods before auth). */
|
|
377
597
|
LURQ_IP_RATE_LIMIT_MAX: z.ZodDefault<z.ZodNumber>;
|
|
598
|
+
/** Per-IP limit for `POST /scan/public`, the one unauthenticated route that
|
|
599
|
+
* reads GitHub, queries the database, and queues ingestion work. The coarse
|
|
600
|
+
* IP limit is the wrong ceiling for it: 240 scans a minute is nothing for a
|
|
601
|
+
* JSON-RPC caller and a great deal of somebody else's GitHub budget. */
|
|
602
|
+
LURQ_SCAN_RATE_LIMIT_MAX: z.ZodDefault<z.ZodNumber>;
|
|
378
603
|
/** Rate-limit window, milliseconds (applies to both limiters). */
|
|
379
604
|
LURQ_RATE_LIMIT_WINDOW_MS: z.ZodDefault<z.ZodNumber>;
|
|
380
605
|
/** Bearer token guarding `/metrics`. Unset → the endpoint is disabled (404). */
|
|
@@ -383,10 +608,46 @@ declare const EnvSchema: z.ZodObject<{
|
|
|
383
608
|
* authenticated web app presents it to mint a key for a signed-in user. Unset
|
|
384
609
|
* → the endpoint is disabled (404). Keep it server-side, never in the client. */
|
|
385
610
|
LURQ_ISSUER_SECRET: z.ZodOptional<z.ZodString>;
|
|
611
|
+
/** PostHog project token (the public `phc_…` one, same as the web app's).
|
|
612
|
+
* Set → the hosted service sends account-keyed product events (key issued,
|
|
613
|
+
* tool called) that join the web app's identified visitors. Unset → nothing
|
|
614
|
+
* is sent, which is every local and stdio install. */
|
|
615
|
+
LURQ_POSTHOG_KEY: z.ZodOptional<z.ZodString>;
|
|
616
|
+
STRIPE_SECRET_KEY: z.ZodOptional<z.ZodString>;
|
|
617
|
+
/** Signing secret for `POST /billing/webhook`. Unset → the endpoint is 404. */
|
|
618
|
+
STRIPE_WEBHOOK_SECRET: z.ZodOptional<z.ZodString>;
|
|
619
|
+
/** Price id backing the Pro plan. Unset → Pro cannot be checked out. */
|
|
620
|
+
/**
|
|
621
|
+
* Whether Stripe Managed Payments applies to our Checkout Sessions: Stripe as
|
|
622
|
+
* merchant of record, taking over indirect tax registration and remittance,
|
|
623
|
+
* disputes and fraud — the half `automatic_tax` alone does not buy.
|
|
624
|
+
*
|
|
625
|
+
* ALWAYS SENT, in both directions, and that is the point. Managed Payments has
|
|
626
|
+
* an account-level default (on, for accounts created since it shipped), so
|
|
627
|
+
* omitting the parameter hands the decision to a dashboard toggle instead of
|
|
628
|
+
* to config. That is action at a distance: the same deploy behaves differently
|
|
629
|
+
* per account, and the failure it produces is a 400 at the moment someone
|
|
630
|
+
* tries to pay. Sending it explicitly makes the deployment the authority.
|
|
631
|
+
*
|
|
632
|
+
* Defaults true to match the account default. Every product must carry an
|
|
633
|
+
* eligible `tax_code` (see billing/provision.ts) or Stripe rejects the session,
|
|
634
|
+
* so `false` is the one-variable escape hatch if eligibility is ever in doubt.
|
|
635
|
+
*/
|
|
636
|
+
STRIPE_MANAGED_PAYMENTS: z.ZodEffects<z.ZodDefault<z.ZodEnum<["true", "false"]>>, boolean, "true" | "false" | undefined>;
|
|
637
|
+
STRIPE_PRICE_PRO: z.ZodOptional<z.ZodString>;
|
|
638
|
+
/** Price id backing Enterprise. Normally unset: Enterprise is sold by
|
|
639
|
+
* conversation, and `contactOnly` in core/plans.ts is what the page reads. */
|
|
640
|
+
STRIPE_PRICE_ENTERPRISE: z.ZodOptional<z.ZodString>;
|
|
641
|
+
/** Absolute base URL the checkout returns to, e.g. https://lurq.run. */
|
|
642
|
+
LURQ_WEB_URL: z.ZodDefault<z.ZodString>;
|
|
386
643
|
/** Numeric App ID from the GitHub App settings page. */
|
|
387
644
|
LURQ_GITHUB_APP_ID: z.ZodOptional<z.ZodString>;
|
|
388
645
|
/** PEM private key. Accepts literal newlines or `\n` escapes (Railway/Vercel). */
|
|
389
646
|
LURQ_GITHUB_APP_PRIVATE_KEY: z.ZodOptional<z.ZodString>;
|
|
647
|
+
/** Webhook secret from the same App settings page, so repo changes made on
|
|
648
|
+
* GitHub reach us. Unset → `POST /github/webhook` is disabled (404): an
|
|
649
|
+
* unverified webhook is an open write endpoint, so no secret means no route. */
|
|
650
|
+
LURQ_GITHUB_WEBHOOK_SECRET: z.ZodOptional<z.ZodString>;
|
|
390
651
|
LURQ_ENDPOINT: z.ZodOptional<z.ZodString>;
|
|
391
652
|
LURQ_API_KEY: z.ZodOptional<z.ZodString>;
|
|
392
653
|
E2B_API_KEY: z.ZodOptional<z.ZodString>;
|
|
@@ -399,21 +660,33 @@ declare const EnvSchema: z.ZodObject<{
|
|
|
399
660
|
SUMMARY_PROVIDER: "openai" | "none";
|
|
400
661
|
SUMMARY_MODEL: string;
|
|
401
662
|
SUMMARY_BASE_URL: string;
|
|
663
|
+
LURQ_RESOLVE_CONCURRENCY: number;
|
|
664
|
+
LURQ_RESOLVE_TIMEOUT_MS: number;
|
|
402
665
|
LURQ_SYNC_CONCURRENCY: number;
|
|
403
666
|
LURQ_SYNC_REFRESH_CAP: number;
|
|
404
667
|
LOG_LEVEL: "info" | "error" | "warn" | "debug";
|
|
405
668
|
PORT: number;
|
|
406
669
|
LURQ_RATE_LIMIT_MAX: number;
|
|
407
670
|
LURQ_IP_RATE_LIMIT_MAX: number;
|
|
671
|
+
LURQ_SCAN_RATE_LIMIT_MAX: number;
|
|
408
672
|
LURQ_RATE_LIMIT_WINDOW_MS: number;
|
|
673
|
+
STRIPE_MANAGED_PAYMENTS: boolean;
|
|
674
|
+
LURQ_WEB_URL: string;
|
|
409
675
|
DATABASE_URL?: string | undefined;
|
|
410
676
|
GITHUB_TOKEN?: string | undefined;
|
|
411
677
|
EMBEDDING_API_KEY?: string | undefined;
|
|
412
678
|
SUMMARY_API_KEY?: string | undefined;
|
|
679
|
+
LURQ_NPM_CACHE_DIR?: string | undefined;
|
|
413
680
|
LURQ_METRICS_TOKEN?: string | undefined;
|
|
414
681
|
LURQ_ISSUER_SECRET?: string | undefined;
|
|
682
|
+
LURQ_POSTHOG_KEY?: string | undefined;
|
|
683
|
+
STRIPE_SECRET_KEY?: string | undefined;
|
|
684
|
+
STRIPE_WEBHOOK_SECRET?: string | undefined;
|
|
685
|
+
STRIPE_PRICE_PRO?: string | undefined;
|
|
686
|
+
STRIPE_PRICE_ENTERPRISE?: string | undefined;
|
|
415
687
|
LURQ_GITHUB_APP_ID?: string | undefined;
|
|
416
688
|
LURQ_GITHUB_APP_PRIVATE_KEY?: string | undefined;
|
|
689
|
+
LURQ_GITHUB_WEBHOOK_SECRET?: string | undefined;
|
|
417
690
|
LURQ_ENDPOINT?: string | undefined;
|
|
418
691
|
LURQ_API_KEY?: string | undefined;
|
|
419
692
|
E2B_API_KEY?: string | undefined;
|
|
@@ -430,17 +703,29 @@ declare const EnvSchema: z.ZodObject<{
|
|
|
430
703
|
SUMMARY_API_KEY?: string | undefined;
|
|
431
704
|
SUMMARY_MODEL?: string | undefined;
|
|
432
705
|
SUMMARY_BASE_URL?: string | undefined;
|
|
706
|
+
LURQ_RESOLVE_CONCURRENCY?: number | undefined;
|
|
707
|
+
LURQ_NPM_CACHE_DIR?: string | undefined;
|
|
708
|
+
LURQ_RESOLVE_TIMEOUT_MS?: number | undefined;
|
|
433
709
|
LURQ_SYNC_CONCURRENCY?: number | undefined;
|
|
434
710
|
LURQ_SYNC_REFRESH_CAP?: number | undefined;
|
|
435
711
|
LOG_LEVEL?: "info" | "error" | "warn" | "debug" | undefined;
|
|
436
712
|
PORT?: number | undefined;
|
|
437
713
|
LURQ_RATE_LIMIT_MAX?: number | undefined;
|
|
438
714
|
LURQ_IP_RATE_LIMIT_MAX?: number | undefined;
|
|
715
|
+
LURQ_SCAN_RATE_LIMIT_MAX?: number | undefined;
|
|
439
716
|
LURQ_RATE_LIMIT_WINDOW_MS?: number | undefined;
|
|
440
717
|
LURQ_METRICS_TOKEN?: string | undefined;
|
|
441
718
|
LURQ_ISSUER_SECRET?: string | undefined;
|
|
719
|
+
LURQ_POSTHOG_KEY?: string | undefined;
|
|
720
|
+
STRIPE_SECRET_KEY?: string | undefined;
|
|
721
|
+
STRIPE_WEBHOOK_SECRET?: string | undefined;
|
|
722
|
+
STRIPE_MANAGED_PAYMENTS?: "true" | "false" | undefined;
|
|
723
|
+
STRIPE_PRICE_PRO?: string | undefined;
|
|
724
|
+
STRIPE_PRICE_ENTERPRISE?: string | undefined;
|
|
725
|
+
LURQ_WEB_URL?: string | undefined;
|
|
442
726
|
LURQ_GITHUB_APP_ID?: string | undefined;
|
|
443
727
|
LURQ_GITHUB_APP_PRIVATE_KEY?: string | undefined;
|
|
728
|
+
LURQ_GITHUB_WEBHOOK_SECRET?: string | undefined;
|
|
444
729
|
LURQ_ENDPOINT?: string | undefined;
|
|
445
730
|
LURQ_API_KEY?: string | undefined;
|
|
446
731
|
E2B_API_KEY?: string | undefined;
|
|
@@ -476,4 +761,4 @@ declare const logger: {
|
|
|
476
761
|
|
|
477
762
|
declare function buildProgram(): Command;
|
|
478
763
|
|
|
479
|
-
export { API_KEY_PREFIX, type Advisory, type AdvisorySeverity, type BuildSignal, type BuildVerified, CACHE_TTL, CATEGORIES, type Candidate, type Category, type CategorySource, type CompatConflict, type CompatEvidence, type CompatOutput, type CompatPair, type CompatProvenance, type CompatStatus, type Confidence, type Config, ConfigError, DEFAULT_ENDPOINT, type DependencyRanges, type DiscoverySource, type DiscoveryStatus, EMBEDDING_DIM, type EvaluateOutput, type ExportKind, type ExportSymbol, FRONTEND_CATEGORIES, PACKAGE_NAME, PROVENANCE_RANK, type PeerMeta, type RiskLevel, type Runtime, SERVER_NAME, STALENESS_DAYS, type ScoreBreakdown, type SurfaceDelta, type UsageGuide, type UsageOutput, VERSION, type VerifyOutput, buildProgram, getConfig, isCategory, isFrontendCategory, loadEnv, logger, requireConfig };
|
|
764
|
+
export { API_KEY_PREFIX, type Advisory, type AdvisorySeverity, type BuildSignal, type BuildVerified, CACHE_TTL, CATEGORIES, type Candidate, type Category, type CategorySource, type CompatConflict, type CompatEvidence, type CompatOutput, type CompatPair, type CompatProvenance, type CompatResolution, type CompatStatus, type Confidence, type Config, ConfigError, DEFAULT_ECOSYSTEM, DEFAULT_ENDPOINT, type DependencyRanges, type DiscoverySource, type DiscoveryStatus, ECOSYSTEMS, EMBEDDING_DIM, type Ecosystem, type EvaluateOutput, type ExportKind, type ExportSymbol, FRONTEND_CATEGORIES, PACKAGE_NAME, PROVENANCE_RANK, type PeerMeta, type RiskLevel, type Runtime, SERVER_NAME, STALENESS_DAYS, type ScoreBreakdown, type SurfaceDelta, type UsageGuide, type UsageOutput, VERSION, type VerifyOutput, buildProgram, getConfig, isCategory, isFrontendCategory, loadEnv, logger, requireConfig };
|