@lunora/advisor 1.0.0-alpha.55 → 1.0.0-alpha.56
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 +53 -0
- package/dist/index.d.mts +397 -61
- package/dist/index.d.ts +397 -61
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/MAP_VERSION-BS08jBkS.mjs +1 -0
- package/dist/packem_shared/actionWithoutErrorHandling-D1DqSPpg.mjs +1 -0
- package/dist/packem_shared/aiRunWithoutLogging-CMvQPNBr.mjs +1 -0
- package/dist/packem_shared/classifySensitivity-DjswRYWd.mjs +1 -0
- package/dist/packem_shared/compareToBaseline-T1_kl8VY.mjs +1 -0
- package/dist/packem_shared/errorWithoutCatalog-DTDVKU4b.mjs +1 -0
- package/dist/packem_shared/{filterWithoutIndex-ht2GZQWV.mjs → filterWithoutIndex-yd1N-GQ0.mjs} +1 -1
- package/dist/packem_shared/gradeFromScore-DW82YDVY.mjs +1 -0
- package/dist/packem_shared/procedureWithoutStructuredEvent-D4Qi2vH7.mjs +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{byCodepoint as p}from"./MAP_VERSION-BS08jBkS.mjs";const l=new Set(["clean","exempt","failing","warned"]),d=(e,r)=>{const t=new Map(e.map(s=>[s.name,s.occurrences]));return r.some(s=>s.occurrences>(t.get(s.name)??0))},i=e=>typeof e=="number"&&Number.isFinite(e),g=e=>{if(typeof e!="object"||e===null)return!1;const r=e;return typeof r.id=="string"&&i(r.score)&&typeof r.coverage=="string"&&l.has(r.coverage)},m=e=>{if(typeof e!="object"||e===null)return!1;const r=e;return Array.isArray(r.checks)&&i(r.score)},v=(e,r)=>{if(r.version!==e.version)return{comparable:!1,reason:"version-mismatch"};const t=new Map(r.procedures.map(o=>[o.id,o])),s=[],n=[],a=[];for(const o of e.procedures){if(o.coverage==="exempt")continue;const c=t.get(o.id);c!==void 0&&c.coverage!=="exempt"&&o.score<c.score&&s.push({after:o.score,before:c.score,id:o.id}),o.coverage==="failing"&&c?.coverage!=="failing"&&n.push(o.id),d(c?.checks??[],o.checks)&&a.push(o.id)}s.sort((o,c)=>p(o.id,c.id)),n.sort(p),a.sort(p);const u=e.score-r.score,f=d(r.project.checks,e.project.checks);return{comparable:!0,dropped:s,newFailing:n,projectRegressed:f,regressed:u<0||s.length>0||n.length>0||a.length>0||f,scoreDelta:u,worsened:a}},y=e=>{if(typeof e!="object"||e===null)return;const r=e;if(!(!i(r.version)||!i(r.score))&&!(!Array.isArray(r.procedures)||!r.procedures.every(t=>g(t)))&&m(r.project))return e};export{v as compareToBaseline,y as parseAdvisorMap};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{i as t}from"./finding-BAVgqnCF.mjs";const a={categories:["SCHEMA"],description:"A procedure throws a bare `new Error(...)`. It reaches the client as an opaque message the caller cannot branch on, and error grouping cannot fingerprint it into a stable issue.",facing:"EXTERNAL",level:"WARN",name:"error_without_catalog",remediation:'Throw a coded error instead: `throw new LunoraError("<CODE>", { … })` from `@lunora/errors`, adding the code to `ERROR_CATALOG` if it is new.',run:e=>{if(e.procedureProtections===void 0)return[];const o=[];for(const r of e.procedureProtections)r.throwsBareError===!0&&o.push(t(a,{cacheKey:`error_without_catalog:${r.file}:${r.exportName}`,detail:`${r.kind} \`${r.exportName}\` (${r.file}) throws a bare \`new Error(...)\`. Use \`LunoraError\` with a catalog code so the client can branch on it and Studio can group it.`,metadata:{exportName:r.exportName,file:r.file,kind:r.kind}}));return o},source:"static",title:"Bare Error thrown instead of a coded LunoraError"};export{a as default};
|
package/dist/packem_shared/{filterWithoutIndex-ht2GZQWV.mjs → filterWithoutIndex-yd1N-GQ0.mjs}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{i as
|
|
1
|
+
import{i as l}from"./finding-BAVgqnCF.mjs";const r={categories:["PERFORMANCE"],description:"A query calls `.filter()` without a `.withIndex()` / `.withSearchIndex()`, so it loads every row in the table and filters in memory — a full table scan that gets linearly slower as the table grows.",facing:"EXTERNAL",level:"WARN",name:"filter_without_index",remediation:'Narrow the read with `.withIndex("name", (q) => q.eq(...))` first, then `.filter()` only for what the index cannot express.',run:i=>{const t=[];for(const e of i.queries??[]){if(!e.hasFilter||e.hasIndex||e.table==="")continue;const a=e.line>0?`${e.file}:${e.line.toString()}`:e.file;t.push(l(r,{cacheKey:`filter_without_index:${e.file}:${e.line.toString()}:${e.table}`,detail:`Query on "${e.table}" at ${a} calls .filter() without an index — it loads every row of "${e.table}" and filters in memory.`,metadata:{exportName:e.exportName,file:e.file,line:e.line,table:e.table}}))}return t},source:"static",title:"Filter without index"};export{r as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const s={ERROR:20,INFO:5,WARN:10},i={ERROR:3,INFO:1,WARN:2},n=e=>Number.isFinite(e)&&e>=0?e:0,c=e=>s[e],u=(e,r)=>i[e]>=i[r]?e:r,h=(e,r="none")=>{const o=e.visibility==="public"?2:.5,t=e.kind==="query"?.5:o;return r==="high"?t*2:t},g=e=>Math.max(1,e*.2),d=e=>{const r=e.reduce((o,t)=>o+n(t.weight),0);return Math.min(100,Math.max(0,100-r))},l=e=>{const r=e.reduce((t,a)=>t+a.weight,0);if(r===0)return 100;const o=e.reduce((t,a)=>t+a.score*a.weight,0);return Math.round(o/r)},R=e=>e>=90?"excellent":e>=70?"good":e>=50?"needs-work":"at-risk",m=e=>e===100?"clean":e>=50?"warned":"failing";export{s as DEFAULT_WEIGHT_BY_LEVEL,m as coverageFromScore,R as gradeFromScore,n as normalizeWeight,h as procedureWeight,g as projectWeight,l as scoreGlobal,d as scoreProcedure,c as weightFor,u as worstLevel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{i as r}from"./finding-BAVgqnCF.mjs";const o={categories:["SCHEMA"],description:"A public `mutation`/`action` emits no structured event. When it fails you get a stack trace with no request context — no ids, no tenant, no outcome — so the failure is visible but not searchable.",facing:"INTERNAL",level:"INFO",name:"procedure_without_structured_event",remediation:'Emit one event on the primary path: `ctx.log.info("<verb>", { … })`, or wrap the handler in `ctx.span("<name>", …)` to attach timing too.',run:t=>{if(t.procedureProtections===void 0)return[];const i=[];for(const e of t.procedureProtections)e.visibility!=="public"||e.kind==="query"||e.emitsEvent!==!1||i.push(r(o,{cacheKey:`procedure_without_structured_event:${e.file}:${e.exportName}`,detail:`Public ${e.kind} \`${e.exportName}\` (${e.file}) emits no structured event. Add a \`ctx.log\` line or a \`ctx.span\` so a failure carries its request context.`,metadata:{exportName:e.exportName,file:e.file,kind:e.kind}}));return i},source:"static",title:"Public write emits no structured event"};export{o as default};
|