@ttt-productions/repo-guards 0.1.1 → 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.
@@ -27,6 +27,16 @@ export interface MonitoringFacts {
27
27
  sdkInitFiles: readonly Reviewed[];
28
28
  /** The Functions test seam that records captures; tests use it instead of mocking the package. */
29
29
  functionsTestRecorder: string;
30
+ /**
31
+ * Entry points whose failures their core reports: the entry file, the core module it hands every
32
+ * event to, and the why (`[]` when there is none). An entry is stale when the core no longer
33
+ * captures, the entry file no longer imports it, or the entry file reports on its own.
34
+ */
35
+ reportedByCore: ReadonlyArray<{
36
+ path: string;
37
+ core: string;
38
+ why: string;
39
+ }>;
30
40
  }
31
41
  /** The entry-point shapes a file defines, or none when its failures reach monitoring. */
32
42
  export declare function unmonitoredEntryPoint(file: FileView, facts: Pick<MonitoringFacts, 'monitoringPackage' | 'captureCalls' | 'callableExits'>): string[];
@@ -1 +1 @@
1
- {"version":3,"file":"monitoring.d.ts","sourceRoot":"","sources":["../../../src/modules/backend/monitoring.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AA0BvD,MAAM,WAAW,eAAe;IAC9B,6DAA6D;IAC7D,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,4EAA4E;IAC5E,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,4DAA4D;IAC5D,aAAa,EAAE,MAAM,CAAC;IACtB,gHAAgH;IAChH,YAAY,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClF,+FAA+F;IAC/F,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,wDAAwD;IACxD,gBAAgB,EAAE,MAAM,CAAC;IACzB,uGAAuG;IACvG,YAAY,EAAE,SAAS,QAAQ,EAAE,CAAC;IAClC,kGAAkG;IAClG,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAeD,yFAAyF;AACzF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,mBAAmB,GAAG,cAAc,GAAG,eAAe,CAAC,GAAG,MAAM,EAAE,CAOpJ;AAED,8CAA8C;AAC9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAIlH;AAED,kDAAkD;AAClD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,IAAI,EAAE,CAInE;AAKD,eAAO,MAAM,eAAe,EAAE,sBAAsB,CAAC,eAAe,CAyHnE,CAAC;AAKF,MAAM,WAAW,iBAAiB;IAChC,mGAAmG;IACnG,MAAM,EAAE,MAAM,OAAO,CAAC;QAAE,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,GAAG;QAAE,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC7G,qGAAqG;IACrG,QAAQ,EAAE,aAAa,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,6EAA6E;IAC7E,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,iHAAiH;AACjH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAA;CAAE,CAAC,CAyBnG;AAED,eAAO,MAAM,iBAAiB,EAAE,sBAAsB,CAAC,iBAAiB,CAuCvE,CAAC;AAKF,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,QAAQ,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvD,4GAA4G;IAC5G,UAAU,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,8GAA8G;IAC9G,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AASD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAS1D;AAWD,4GAA4G;AAC5G,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,YAAY,CAAC,EAC1D,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA+BzC;AAED,eAAO,MAAM,kBAAkB,EAAE,sBAAsB,CAAC,kBAAkB,CAyCzE,CAAC"}
1
+ {"version":3,"file":"monitoring.d.ts","sourceRoot":"","sources":["../../../src/modules/backend/monitoring.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import ts from 'typescript';
6
6
  import { calleeName, forEachNode, lineOfNode } from '../../support/ast.js';
7
7
  import { loaderProblem, namesProblem, reviewedProblems, textProblem } from '../../support/facts.js';
8
8
  import { MODULE_LOADS, moduleImports, namesModule } from '../../support/imports.js';
9
+ import { resolveRelative } from '../../support/paths.js';
9
10
  import { escapeRegExp } from '../../support/text.js';
10
11
  const FUNCTIONS_CODE = { roots: ['functions'], kinds: ['code'], tests: false };
11
12
  const APP_CODE = { roots: ['app'], kinds: ['code'], tests: false };
@@ -22,6 +23,23 @@ function matchIndexes(file, pattern) {
22
23
  out.push(m.index);
23
24
  return out;
24
25
  }
26
+ /** A module path without its source or emitted extension, for comparing an import to a file. */
27
+ const withoutExtension = (path) => path.replace(/\.(?:[cm]?[jt]sx?)$/, '');
28
+ /** True when a file imports the module at `corePath` for its values. */
29
+ function importsModule(file, corePath) {
30
+ const target = withoutExtension(corePath);
31
+ return file.imports.some(({ spec, typeOnly }) => {
32
+ if (typeOnly)
33
+ return false;
34
+ const resolved = resolveRelative(file.path, spec);
35
+ return resolved !== null && !resolved.escapes && withoutExtension(resolved.path) === target;
36
+ });
37
+ }
38
+ /** True when a file imports the monitoring package and calls one of its capture calls. */
39
+ function reportsToMonitoring(file, facts) {
40
+ const importsMonitoring = moduleImports(file.sourceFile, MODULE_LOADS).some(({ spec, typeOnly }) => !typeOnly && namesModule(spec, facts.monitoringPackage));
41
+ return importsMonitoring && facts.captureCalls.some((capture) => new RegExp(`\\b${escapeRegExp(capture)}\\s*\\(`).test(file.code));
42
+ }
25
43
  /** Every Cloud Functions entry-point shape, with the label a finding reports. */
26
44
  const ENTRY_POINT_SHAPES = [
27
45
  { shape: 'onCall', re: /\bonCall\s*(?:<[^>]*>)?\s*\(/ },
@@ -41,9 +59,7 @@ export function unmonitoredEntryPoint(file, facts) {
41
59
  return [];
42
60
  if (facts.callableExits.some((exit) => callPattern(exit).test(file.code)))
43
61
  return [];
44
- const importsMonitoring = moduleImports(file.sourceFile, MODULE_LOADS).some(({ spec, typeOnly }) => !typeOnly && namesModule(spec, facts.monitoringPackage));
45
- const captures = facts.captureCalls.some((capture) => new RegExp(`\\b${escapeRegExp(capture)}\\s*\\(`).test(file.code));
46
- return importsMonitoring && captures ? [] : shapes;
62
+ return reportsToMonitoring(file, facts) ? [] : shapes;
47
63
  }
48
64
  /** Every import of a provider SDK package. */
49
65
  export function providerSdkImports(file, sdks) {
@@ -79,6 +95,12 @@ export const monitoringGuard = {
79
95
  textProblem(facts?.providerInitCall, 'providerInitCall', problems);
80
96
  reviewedProblems(facts?.sdkInitFiles, 'sdkInitFiles', problems);
81
97
  textProblem(facts?.functionsTestRecorder, 'functionsTestRecorder', problems);
98
+ if (!Array.isArray(facts?.reportedByCore))
99
+ problems.push('reportedByCore is missing (declare [] when every entry point reports its own failures)');
100
+ for (const entry of facts?.reportedByCore ?? []) {
101
+ if (!entry?.path || !entry.core || !entry.why?.trim())
102
+ problems.push('a reportedByCore entry needs its entry file, its core module, and its why');
103
+ }
82
104
  return problems;
83
105
  },
84
106
  build(facts) {
@@ -90,13 +112,38 @@ export const monitoringGuard = {
90
112
  `or database trigger — either exits its callable through ${facts.callableExits.join(' / ') || 'the app\'s callable exit'} ` +
91
113
  `or imports ${facts.monitoringPackage} and calls ${facts.captureCalls.join(' / ')} on its failure path. A failure ` +
92
114
  'path that only writes a log line is not monitored: nothing watches the log, so a background trigger fails ' +
93
- 'invisibly. An import that is never called is not monitoring either.',
115
+ 'invisibly. An import that is never called is not monitoring either. An entry point whose core reports every ' +
116
+ 'failure is a reviewed entry naming that core, with its why; it is stale when the core no longer captures, ' +
117
+ 'the entry point no longer imports it, or the entry point reports on its own.',
94
118
  run(context) {
95
119
  const findings = [];
120
+ const reviewed = new Map(facts.reportedByCore.map((entry) => [entry.path, entry]));
121
+ const seen = new Set();
96
122
  for (const file of context.files(FUNCTIONS_CODE)) {
97
123
  const shapes = unmonitoredEntryPoint(file, facts);
98
- if (shapes.length)
99
- findings.push({ file: file.path, detail: `defines ${shapes.join(', ')} and reports no failure to monitoring` });
124
+ const entry = reviewed.get(file.path);
125
+ if (!entry) {
126
+ if (shapes.length)
127
+ findings.push({ file: file.path, detail: `defines ${shapes.join(', ')} and reports no failure to monitoring` });
128
+ continue;
129
+ }
130
+ seen.add(file.path);
131
+ if (!ENTRY_POINT_SHAPES.some(({ re }) => re.test(file.code))) {
132
+ findings.push({ file: file.path, detail: 'a reportedByCore entry for a file that defines no entry point' });
133
+ }
134
+ else if (!shapes.length) {
135
+ findings.push({ file: file.path, detail: 'a reportedByCore entry for an entry point that reports on its own' });
136
+ }
137
+ else if (!importsModule(file, entry.core)) {
138
+ findings.push({ file: file.path, detail: `a reportedByCore entry names ${entry.core}, which the entry point does not import` });
139
+ }
140
+ else if (!context.reader.exists(entry.core) || !reportsToMonitoring(context.file(entry.core), facts)) {
141
+ findings.push({ file: file.path, detail: `a reportedByCore entry names ${entry.core}, which reports no failure to monitoring` });
142
+ }
143
+ }
144
+ for (const entry of facts.reportedByCore) {
145
+ if (!seen.has(entry.path))
146
+ findings.push({ file: entry.path, detail: 'a reportedByCore entry for a file the Functions code does not hold' });
100
147
  }
101
148
  return findings;
102
149
  },
@@ -1 +1 @@
1
- {"version":3,"file":"monitoring.js","sourceRoot":"","sources":["../../../src/modules/backend/monitoring.ts"],"names":[],"mappings":"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","sourcesContent":["// The monitoring guards: every Cloud Function entry point reports its failures, monitoring is bound\n// once per runtime in its adapters, the provider's SDK is named only where it starts, tests capture\n// through the recording seam, telemetry tags survive the content policy, and a service the app does\n// not use is named nowhere.\n\nimport ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../config.js';\nimport type { Finding, Guard } from '../../guard.js';\nimport type { Scope } from '../../reader/reader.js';\nimport type { FileView } from '../../reader/view.js';\nimport type { Reviewed } from '../../reader/layout.js';\nimport { calleeName, forEachNode, lineOfNode } from '../../support/ast.js';\nimport { loaderProblem, namesProblem, reviewedProblems, textProblem } from '../../support/facts.js';\nimport { MODULE_LOADS, moduleImports, namesModule } from '../../support/imports.js';\nimport { escapeRegExp } from '../../support/text.js';\n\nconst FUNCTIONS_CODE: Scope = { roots: ['functions'], kinds: ['code'], tests: false };\nconst APP_CODE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\nconst APP_AND_FUNCTIONS_CODE: Scope = { roots: ['app', 'functions'], kinds: ['code'], tests: false };\n\n/** A pattern for a call to `name` (`a.b` matches `a . b (`), never a longer name ending in it. */\nfunction callPattern(name: string): RegExp {\n return new RegExp(`(?<![\\\\w$])${name.split('.').map(escapeRegExp).join('\\\\s*\\\\.\\\\s*')}\\\\s*\\\\(`, 'g');\n}\n\n/** The index of every match of a pattern in a file's comment-stripped code. */\nfunction matchIndexes(file: FileView, pattern: RegExp): number[] {\n const re = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : `${pattern.flags}g`);\n const out: number[] = [];\n for (let m = re.exec(file.code); m; m = re.exec(file.code)) out.push(m.index);\n return out;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Monitoring: entry points, one init per runtime, the provider SDK, the recording seam.\n\nexport interface MonitoringFacts {\n /** The one monitoring package every capture goes through. */\n monitoringPackage: string;\n /** The package's init call, which binds the provider. */\n initCall: string;\n /** The package's capture calls. */\n captureCalls: readonly string[];\n /** App calls through which a callable exits, each capturing every fault. */\n callableExits: readonly string[];\n /** The one Functions module that initializes monitoring. */\n functionsInit: string;\n /** The app root's reporter bindings: the file that initializes, and the layout that mounts it as an element. */\n appReporters: ReadonlyArray<{ file: string; mountedIn: string; element: string }>;\n /** The provider SDK's package names (or scope, `@vendor`), named only where the SDK starts. */\n providerSdks: readonly string[];\n /** The provider SDK's own init call (`Vendor.init`). */\n providerInitCall: string;\n /** The files that start the provider SDK, each with its why; one that no longer starts it is stale. */\n sdkInitFiles: readonly Reviewed[];\n /** The Functions test seam that records captures; tests use it instead of mocking the package. */\n functionsTestRecorder: string;\n}\n\n/** Every Cloud Functions entry-point shape, with the label a finding reports. */\nconst ENTRY_POINT_SHAPES: ReadonlyArray<{ shape: string; re: RegExp }> = [\n { shape: 'onCall', re: /\\bonCall\\s*(?:<[^>]*>)?\\s*\\(/ },\n { shape: 'onRequest', re: /\\bonRequest\\s*\\(/ },\n { shape: 'onSchedule', re: /\\bonSchedule\\s*\\(/ },\n { shape: 'onDocument*', re: /\\bonDocument\\w*\\s*\\(/ },\n { shape: 'onObjectFinalized', re: /\\bonObjectFinalized\\s*\\(/ },\n { shape: 'onObjectDeleted', re: /\\bonObjectDeleted\\s*\\(/ },\n { shape: 'onMessagePublished', re: /\\bonMessagePublished\\s*\\(/ },\n { shape: 'onTaskDispatched', re: /\\bonTaskDispatched\\s*\\(/ },\n { shape: 'onValue*', re: /\\bonValue\\w*\\s*\\(/ },\n];\n\n/** The entry-point shapes a file defines, or none when its failures reach monitoring. */\nexport function unmonitoredEntryPoint(file: FileView, facts: Pick<MonitoringFacts, 'monitoringPackage' | 'captureCalls' | 'callableExits'>): string[] {\n const shapes = ENTRY_POINT_SHAPES.filter(({ re }) => re.test(file.code)).map(({ shape }) => shape);\n if (!shapes.length) return [];\n if (facts.callableExits.some((exit) => callPattern(exit).test(file.code))) return [];\n const importsMonitoring = moduleImports(file.sourceFile, MODULE_LOADS).some(({ spec, typeOnly }) => !typeOnly && namesModule(spec, facts.monitoringPackage));\n const captures = facts.captureCalls.some((capture) => new RegExp(`\\\\b${escapeRegExp(capture)}\\\\s*\\\\(`).test(file.code));\n return importsMonitoring && captures ? [] : shapes;\n}\n\n/** Every import of a provider SDK package. */\nexport function providerSdkImports(file: FileView, sdks: readonly string[]): Array<{ node: ts.Node; spec: string }> {\n return moduleImports(file.sourceFile, MODULE_LOADS)\n .filter(({ spec }) => sdks.some((sdk) => namesModule(spec, sdk)))\n .map(({ node, spec }) => ({ node, spec }));\n}\n\n/** Every `vi.mock` / `vi.doMock` of a package. */\nexport function packageMocks(file: FileView, pkg: string): ts.Node[] {\n return moduleImports(file.sourceFile, ['mock'])\n .filter(({ callee, spec }) => (callee === 'vi.mock' || callee === 'vi.doMock') && namesModule(spec, pkg))\n .map(({ node }) => node);\n}\n\n/** True when a file renders `<Element />` (or `<Element>…`). */\nconst mountsElement = (file: FileView, element: string) => new RegExp(`<${escapeRegExp(element)}(?=[\\\\s/>])`).test(file.code);\n\nexport const monitoringGuard: GenericGuardDefinition<MonitoringFacts> = {\n id: 'monitoring',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.monitoringPackage, 'monitoringPackage', problems);\n textProblem(facts?.initCall, 'initCall', problems);\n namesProblem(facts?.captureCalls, 'captureCalls', problems);\n namesProblem(facts?.callableExits, 'callableExits', problems, { nonEmpty: false });\n textProblem(facts?.functionsInit, 'functionsInit', problems);\n if (!Array.isArray(facts?.appReporters)) problems.push('appReporters is missing (declare [] when the app root binds no reporter)');\n for (const r of facts?.appReporters ?? []) {\n if (!r?.file || !r.mountedIn || !r.element) problems.push('an app reporter needs its file, the layout that mounts it, and the element');\n }\n namesProblem(facts?.providerSdks, 'providerSdks', problems);\n textProblem(facts?.providerInitCall, 'providerInitCall', problems);\n reviewedProblems(facts?.sdkInitFiles, 'sdkInitFiles', problems);\n textProblem(facts?.functionsTestRecorder, 'functionsTestRecorder', problems);\n return problems;\n },\n build(facts) {\n const initPattern = callPattern(facts.initCall);\n const providerInit = callPattern(facts.providerInitCall);\n const entryPoints: Guard = {\n title: 'every Cloud Function entry point reports its failures to monitoring',\n description:\n 'Every file that defines a deployed Cloud Function — callable, HTTP, schedule, Firestore, Storage, pub/sub, task, ' +\n `or database trigger — either exits its callable through ${facts.callableExits.join(' / ') || 'the app\\'s callable exit'} ` +\n `or imports ${facts.monitoringPackage} and calls ${facts.captureCalls.join(' / ')} on its failure path. A failure ` +\n 'path that only writes a log line is not monitored: nothing watches the log, so a background trigger fails ' +\n 'invisibly. An import that is never called is not monitoring either.',\n run(context) {\n const findings: Finding[] = [];\n for (const file of context.files(FUNCTIONS_CODE)) {\n const shapes = unmonitoredEntryPoint(file, facts);\n if (shapes.length) findings.push({ file: file.path, detail: `defines ${shapes.join(', ')} and reports no failure to monitoring` });\n }\n return findings;\n },\n };\n const initOnce: Guard = {\n title: 'monitoring is initialized once per runtime, only in its adapters',\n description:\n `The Functions runtime initializes monitoring in ${facts.functionsInit} and nowhere else; the app root binds its ` +\n `reporter only in its declared adapters, each initializing once and mounted by its layout. A second ` +\n `${facts.initCall} is a second configuration nothing keeps aligned with the first and double-reports the moment ` +\n 'both run; a missing one leaves every capture writing into an unbound client. Pass the values at the existing ' +\n 'adapter instead of opening a new init.',\n run(context) {\n const findings: Finding[] = [];\n let functionsInits = 0;\n for (const file of context.files(FUNCTIONS_CODE)) {\n const sites = matchIndexes(file, initPattern);\n if (file.path === facts.functionsInit) functionsInits += sites.length;\n else for (const i of sites) findings.push({ file: file.path, line: file.lineOf(i), detail: `${facts.initCall} outside the Functions adapter` });\n }\n if (functionsInits !== 1) findings.push({ file: facts.functionsInit, detail: `the Functions adapter calls ${facts.initCall} ${functionsInits} times, not once` });\n const reporters = new Map(facts.appReporters.map((r) => [r.file, r]));\n const reporterInits = new Map<string, number>();\n for (const file of context.files(APP_CODE)) {\n const sites = matchIndexes(file, initPattern);\n if (reporters.has(file.path)) reporterInits.set(file.path, sites.length);\n else for (const i of sites) findings.push({ file: file.path, line: file.lineOf(i), detail: `${facts.initCall} outside the app's reporter adapters` });\n }\n for (const reporter of facts.appReporters) {\n const count = reporterInits.get(reporter.file) ?? 0;\n if (count !== 1) findings.push({ file: reporter.file, detail: `the reporter adapter calls ${facts.initCall} ${count} times, not once` });\n if (!context.reader.exists(reporter.mountedIn)) findings.push({ file: reporter.mountedIn, detail: 'the layout that mounts the reporter no longer exists' });\n else if (!mountsElement(context.file(reporter.mountedIn), reporter.element)) {\n findings.push({ file: reporter.mountedIn, detail: `does not mount <${reporter.element} />, so the reporter is never bound` });\n }\n }\n return findings;\n },\n };\n const providerNamed: Guard = {\n title: 'the monitoring provider SDK is named only where it starts',\n description:\n `No file in the app or Functions roots imports a provider SDK package (${facts.providerSdks.join(', ')}) or calls ` +\n `${facts.providerInitCall}: the provider binds inside ${facts.monitoringPackage}, and a direct import is a third ` +\n 'binding site whose DSN, environment, and sample rate the app boundary can no longer supply. Capture through the ' +\n 'monitoring package instead. Each declared SDK init file still starts the SDK; one that no longer does is stale.',\n run(context) {\n const findings: Finding[] = [];\n for (const file of context.files(APP_AND_FUNCTIONS_CODE)) {\n for (const { node, spec } of providerSdkImports(file, facts.providerSdks)) {\n findings.push({ file: file.path, line: lineOfNode(file, node), detail: `imports ${spec}` });\n }\n for (const i of matchIndexes(file, providerInit)) findings.push({ file: file.path, line: file.lineOf(i), detail: `calls ${facts.providerInitCall}` });\n }\n for (const entry of facts.sdkInitFiles) {\n if (!context.reader.exists(entry.path)) findings.push({ file: entry.path, detail: 'stale SDK init file: it no longer exists' });\n else if (!matchIndexes(context.file(entry.path), providerInit).length) {\n findings.push({ file: entry.path, detail: `stale SDK init file: it no longer calls ${facts.providerInitCall}` });\n }\n }\n return findings;\n },\n };\n const recorderSeam: Guard = {\n title: 'Functions tests capture through the recording seam, never a local mock of the monitoring package',\n description:\n `No Functions test replaces ${facts.monitoringPackage} with a local vi.mock / vi.doMock. A test that asserts a ` +\n `capture installs the recording adapter (${facts.functionsTestRecorder}) through the package's own adapter seam; a ` +\n 'test that only needs the handler to run needs no mock at all. A local mock lists only the exports its author ' +\n 'knew, and a stubbed scope wrapper never runs the wrapped handler.',\n run(context) {\n const findings: Finding[] = [];\n let seam = false;\n for (const file of context.files({ roots: ['functions'], kinds: ['code'], tests: 'only' })) {\n if (file.path === facts.functionsTestRecorder) seam = true;\n for (const node of packageMocks(file, facts.monitoringPackage)) {\n findings.push({ file: file.path, line: lineOfNode(file, node), detail: `mocks ${facts.monitoringPackage}` });\n }\n }\n if (!seam) findings.push({ file: facts.functionsTestRecorder, detail: 'the recording seam is gone or is not test code' });\n return findings;\n },\n };\n return [entryPoints, initOnce, providerNamed, recorderSeam];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Telemetry tag keys survive the content policy.\n\nexport interface TelemetryTagFacts {\n /** The app's telemetry content policy, as its monitoring package builds it, loaded at run time. */\n policy: () => Promise<{ isDiagnosticKey(key: string): boolean }> | { isDiagnosticKey(key: string): boolean };\n /** Tag keys whose value is always a flag, which passes under any key; a key set nowhere is stale. */\n flagKeys: ReadonlyArray<{ key: string; why: string }>;\n /** The name suffix of a constant whose values are tag keys (`_TAG_KEYS`). */\n tagKeyMapSuffix: string;\n}\n\n/** Every tag key a file sets: a `tags: { … }` literal's keys, `setTag('key', …)`, and a tag-key map's values. */\nexport function tagKeysSet(file: FileView, mapSuffix: string): Array<{ key: string; node: ts.Node }> {\n const sf = file.sourceFile;\n const out: Array<{ key: string; node: ts.Node }> = [];\n const keyOf = (name: ts.PropertyName) => (ts.isIdentifier(name) || ts.isStringLiteralLike(name) ? name.text : undefined);\n forEachNode(sf, (node) => {\n if (ts.isPropertyAssignment(node) && keyOf(node.name) === 'tags' && ts.isObjectLiteralExpression(node.initializer)) {\n for (const prop of node.initializer.properties) {\n const key = (ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop)) && keyOf(prop.name);\n if (key) out.push({ key, node: prop });\n }\n }\n if (ts.isCallExpression(node) && calleeName(node) === 'setTag' && node.arguments[0] && ts.isStringLiteralLike(node.arguments[0])) {\n out.push({ key: node.arguments[0].text, node });\n }\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text.endsWith(mapSuffix) && node.initializer) {\n let init: ts.Expression = node.initializer;\n while (ts.isAsExpression(init) || ts.isSatisfiesExpression(init)) init = init.expression;\n if (ts.isObjectLiteralExpression(init)) {\n for (const prop of init.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isStringLiteralLike(prop.initializer)) out.push({ key: prop.initializer.text, node: prop });\n }\n }\n }\n });\n return out;\n}\n\nexport const telemetryTagGuard: GenericGuardDefinition<TelemetryTagFacts> = {\n id: 'telemetryTagKeys',\n absentWhen: 'the app declares no telemetry content policy',\n factProblems(facts) {\n const problems: string[] = [];\n loaderProblem(facts?.policy, 'policy', problems);\n reviewedProblems(facts?.flagKeys, 'flagKeys', problems, { key: 'key' });\n textProblem(facts?.tagKeyMapSuffix, 'tagKeyMapSuffix', problems);\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'every backend telemetry tag key survives the content policy',\n description:\n 'A tag the backend sets survives the telemetry content policy only under a diagnostic key, so every tag key a ' +\n \"capture site sets — a `tags: { … }` literal's keys, a `setTag('key', …)`, a tag-key map's values — is one; \" +\n 'otherwise the policy silently drops it. Rename the tag to a diagnostic key, or widen the policy only to a key ' +\n 'that never holds prose. A key whose value is always a flag is a reviewed entry with its why.',\n async run(context) {\n const policy = await facts.policy();\n const flags = new Set(facts.flagKeys.map((f) => f.key));\n const findings: Finding[] = [];\n const seen = new Set<string>();\n for (const file of context.files(FUNCTIONS_CODE)) {\n for (const { key, node } of tagKeysSet(file, facts.tagKeyMapSuffix)) {\n seen.add(key);\n if (!flags.has(key) && !policy.isDiagnosticKey(key)) {\n findings.push({ file: file.path, line: lineOfNode(file, node), detail: `tag key ${key} is not a diagnostic key, so the policy drops it` });\n }\n }\n }\n if (!seen.size) findings.push({ file: '(functions)', detail: 'no tag key found, so the guard checks nothing' });\n for (const key of flags) if (!seen.has(key)) findings.push({ file: '(flagKeys)', detail: `stale flag key ${key}: no capture site sets it` });\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// A service the app does not use is named nowhere.\n\nexport interface UnusedServiceFacts {\n /** Services the product has no surface for, each with its why. */\n services: ReadonlyArray<{ name: string; why: string }>;\n /** Text that contains a service's name but is not the service (a word it is part of), each with its why. */\n collisions: ReadonlyArray<{ text: string; why: string }>;\n /** Files outside the roots read by name: manifests, deployed configuration, workflows, rules, index files. */\n namedFiles: readonly string[];\n}\n\nconst SERVICE_SCOPE: Scope = {\n roots: ['app', 'functions', 'e2e', 'hostedE2e', 'scripts', 'workers'],\n optionalRoots: ['functions', 'e2e', 'hostedE2e', 'scripts', 'workers'],\n kinds: ['code', 'config', 'rules'],\n tests: true,\n};\n\n/**\n * Where a service's name appears as a name: its lowercase form starting a word and not running on\n * into lowercase letters (`svc`, `svcSessionId`, `svc.`, `'svc'`, `@svc/`); its capitalized form\n * anywhere not running on (`Svc`, `loadSvc`); its uppercase form standing alone between non-letters\n * (`SVC_KEY`). A longer word that merely contains it (`svced`, `pinsvc`) is not the service.\n */\nexport function serviceNamePatterns(name: string): RegExp[] {\n const lower = escapeRegExp(name.toLowerCase());\n const cap = escapeRegExp(name.charAt(0).toUpperCase() + name.slice(1).toLowerCase());\n const upper = escapeRegExp(name.toUpperCase());\n return [\n new RegExp(`(?<![A-Za-z0-9])${lower}(?![a-z])`, 'g'),\n new RegExp(`${cap}(?![a-z])`, 'g'),\n new RegExp(`(?<![A-Z0-9])${upper}(?![A-Z0-9])`, 'g'),\n ];\n}\n\n/** The lines of a file's text a reader of the service name reads: comments skipped by line. */\nfunction readableLines(file: FileView): string[] {\n const lines = file.code.split('\\n');\n const name = file.path.slice(file.path.lastIndexOf('/') + 1);\n if (file.kind === 'config' && !/\\.jsonc?$/.test(name)) return lines.map((l) => (/^\\s*#/.test(l) ? '' : l));\n if (file.kind === 'rules') return lines.map((l) => (/^\\s*\\/\\//.test(l) ? '' : l));\n return lines;\n}\n\n/** Every place a file names a service, collisions taken out; `collisionHits` counts each collision seen. */\nexport function serviceNameSites(\n file: FileView,\n facts: Pick<UnusedServiceFacts, 'services' | 'collisions'>,\n collisionHits?: Map<string, number>,\n): Array<{ line: number; detail: string }> {\n const out: Array<{ line: number; detail: string }> = [];\n for (const { name } of facts.services) {\n const segment = new RegExp(`^${escapeRegExp(name)}(?:\\\\.[cm]?[jt]sx?)?$`, 'i');\n if (file.path.split('/').some((s) => segment.test(s))) out.push({ line: 1, detail: `the file path is named for ${name}` });\n }\n readableLines(file).forEach((line, index) => {\n const covered: Array<[number, number]> = [];\n for (const { text } of facts.collisions) {\n for (let i = line.indexOf(text); i !== -1; i = line.indexOf(text, i + 1)) {\n covered.push([i, i + text.length]);\n collisionHits?.set(text, (collisionHits.get(text) ?? 0) + 1);\n }\n }\n for (const { name } of facts.services) {\n for (const re of serviceNamePatterns(name)) {\n for (let m = re.exec(line); m; m = re.exec(line)) {\n const start = m.index;\n const end = start + m[0].length;\n if (!covered.some(([a, b]) => a <= start && end <= b)) out.push({ line: index + 1, detail: `names ${name}: ${line.trim().slice(0, 100)}` });\n }\n }\n }\n });\n const seen = new Set<string>();\n return out.filter((s) => {\n const key = `${s.line}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nexport const unusedServiceGuard: GenericGuardDefinition<UnusedServiceFacts> = {\n id: 'unusedService',\n absentWhen: 'the app has no external service it must keep out of the product',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.services, 'services', problems, { key: 'name', nonEmpty: true });\n for (const s of facts?.services ?? []) if (typeof s?.name === 'string' && !/^[A-Za-z][A-Za-z0-9]*$/.test(s.name)) problems.push(`service ${s.name} is not one word`);\n reviewedProblems(facts?.collisions, 'collisions', problems, { key: 'text' });\n namesProblem(facts?.namedFiles, 'namedFiles', problems, { nonEmpty: false });\n return problems;\n },\n build(facts) {\n const names = facts.services.map((s) => s.name).join(', ');\n return [\n {\n title: 'a service the product does not use is named nowhere',\n description:\n `The product has no surface for ${names}, so nothing names it: no source, test, or script — not its SDK ` +\n 'packages, its client or loader, a module of the tree named for it, a field, callable, hook, or handler built on ' +\n 'its name, or its credentials — and no manifest, deployed configuration, workflow, rules file, or index file. The ' +\n 'service returns only as a product decision that brings its own adapter, secret binding, rules, and tests. Text ' +\n 'that merely contains the name is a reviewed collision with its why; a collision found nowhere is stale.',\n run(context) {\n const findings: Finding[] = [];\n const collisionHits = new Map<string, number>();\n const files = context.files(SERVICE_SCOPE);\n const read = new Set(files.map((f) => f.path));\n for (const path of facts.namedFiles) {\n if (read.has(path)) continue;\n if (!context.reader.exists(path)) findings.push({ file: path, detail: 'a named file no longer exists' });\n else files.push(context.file(path));\n }\n for (const file of files) {\n for (const site of serviceNameSites(file, facts, collisionHits)) findings.push({ file: file.path, line: site.line, detail: site.detail });\n }\n for (const { text } of facts.collisions) if (!collisionHits.get(text)) findings.push({ file: '(collisions)', detail: `stale collision ${text}: it appears nowhere` });\n return findings;\n },\n },\n ];\n },\n};\n"]}
1
+ {"version":3,"file":"monitoring.js","sourceRoot":"","sources":["../../../src/modules/backend/monitoring.ts"],"names":[],"mappings":"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","sourcesContent":["// The monitoring guards: every Cloud Function entry point reports its failures, monitoring is bound\n// once per runtime in its adapters, the provider's SDK is named only where it starts, tests capture\n// through the recording seam, telemetry tags survive the content policy, and a service the app does\n// not use is named nowhere.\n\nimport ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../config.js';\nimport type { Finding, Guard } from '../../guard.js';\nimport type { Scope } from '../../reader/reader.js';\nimport type { FileView } from '../../reader/view.js';\nimport type { Reviewed } from '../../reader/layout.js';\nimport { calleeName, forEachNode, lineOfNode } from '../../support/ast.js';\nimport { loaderProblem, namesProblem, reviewedProblems, textProblem } from '../../support/facts.js';\nimport { MODULE_LOADS, moduleImports, namesModule } from '../../support/imports.js';\nimport { resolveRelative } from '../../support/paths.js';\nimport { escapeRegExp } from '../../support/text.js';\n\nconst FUNCTIONS_CODE: Scope = { roots: ['functions'], kinds: ['code'], tests: false };\nconst APP_CODE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\nconst APP_AND_FUNCTIONS_CODE: Scope = { roots: ['app', 'functions'], kinds: ['code'], tests: false };\n\n/** A pattern for a call to `name` (`a.b` matches `a . b (`), never a longer name ending in it. */\nfunction callPattern(name: string): RegExp {\n return new RegExp(`(?<![\\\\w$])${name.split('.').map(escapeRegExp).join('\\\\s*\\\\.\\\\s*')}\\\\s*\\\\(`, 'g');\n}\n\n/** The index of every match of a pattern in a file's comment-stripped code. */\nfunction matchIndexes(file: FileView, pattern: RegExp): number[] {\n const re = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : `${pattern.flags}g`);\n const out: number[] = [];\n for (let m = re.exec(file.code); m; m = re.exec(file.code)) out.push(m.index);\n return out;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Monitoring: entry points, one init per runtime, the provider SDK, the recording seam.\n\nexport interface MonitoringFacts {\n /** The one monitoring package every capture goes through. */\n monitoringPackage: string;\n /** The package's init call, which binds the provider. */\n initCall: string;\n /** The package's capture calls. */\n captureCalls: readonly string[];\n /** App calls through which a callable exits, each capturing every fault. */\n callableExits: readonly string[];\n /** The one Functions module that initializes monitoring. */\n functionsInit: string;\n /** The app root's reporter bindings: the file that initializes, and the layout that mounts it as an element. */\n appReporters: ReadonlyArray<{ file: string; mountedIn: string; element: string }>;\n /** The provider SDK's package names (or scope, `@vendor`), named only where the SDK starts. */\n providerSdks: readonly string[];\n /** The provider SDK's own init call (`Vendor.init`). */\n providerInitCall: string;\n /** The files that start the provider SDK, each with its why; one that no longer starts it is stale. */\n sdkInitFiles: readonly Reviewed[];\n /** The Functions test seam that records captures; tests use it instead of mocking the package. */\n functionsTestRecorder: string;\n /**\n * Entry points whose failures their core reports: the entry file, the core module it hands every\n * event to, and the why (`[]` when there is none). An entry is stale when the core no longer\n * captures, the entry file no longer imports it, or the entry file reports on its own.\n */\n reportedByCore: ReadonlyArray<{ path: string; core: string; why: string }>;\n}\n\n/** A module path without its source or emitted extension, for comparing an import to a file. */\nconst withoutExtension = (path: string): string => path.replace(/\\.(?:[cm]?[jt]sx?)$/, '');\n\n/** True when a file imports the module at `corePath` for its values. */\nfunction importsModule(file: FileView, corePath: string): boolean {\n const target = withoutExtension(corePath);\n return file.imports.some(({ spec, typeOnly }) => {\n if (typeOnly) return false;\n const resolved = resolveRelative(file.path, spec);\n return resolved !== null && !resolved.escapes && withoutExtension(resolved.path) === target;\n });\n}\n\n/** True when a file imports the monitoring package and calls one of its capture calls. */\nfunction reportsToMonitoring(file: FileView, facts: Pick<MonitoringFacts, 'monitoringPackage' | 'captureCalls'>): boolean {\n const importsMonitoring = moduleImports(file.sourceFile, MODULE_LOADS).some(({ spec, typeOnly }) => !typeOnly && namesModule(spec, facts.monitoringPackage));\n return importsMonitoring && facts.captureCalls.some((capture) => new RegExp(`\\\\b${escapeRegExp(capture)}\\\\s*\\\\(`).test(file.code));\n}\n\n/** Every Cloud Functions entry-point shape, with the label a finding reports. */\nconst ENTRY_POINT_SHAPES: ReadonlyArray<{ shape: string; re: RegExp }> = [\n { shape: 'onCall', re: /\\bonCall\\s*(?:<[^>]*>)?\\s*\\(/ },\n { shape: 'onRequest', re: /\\bonRequest\\s*\\(/ },\n { shape: 'onSchedule', re: /\\bonSchedule\\s*\\(/ },\n { shape: 'onDocument*', re: /\\bonDocument\\w*\\s*\\(/ },\n { shape: 'onObjectFinalized', re: /\\bonObjectFinalized\\s*\\(/ },\n { shape: 'onObjectDeleted', re: /\\bonObjectDeleted\\s*\\(/ },\n { shape: 'onMessagePublished', re: /\\bonMessagePublished\\s*\\(/ },\n { shape: 'onTaskDispatched', re: /\\bonTaskDispatched\\s*\\(/ },\n { shape: 'onValue*', re: /\\bonValue\\w*\\s*\\(/ },\n];\n\n/** The entry-point shapes a file defines, or none when its failures reach monitoring. */\nexport function unmonitoredEntryPoint(file: FileView, facts: Pick<MonitoringFacts, 'monitoringPackage' | 'captureCalls' | 'callableExits'>): string[] {\n const shapes = ENTRY_POINT_SHAPES.filter(({ re }) => re.test(file.code)).map(({ shape }) => shape);\n if (!shapes.length) return [];\n if (facts.callableExits.some((exit) => callPattern(exit).test(file.code))) return [];\n return reportsToMonitoring(file, facts) ? [] : shapes;\n}\n\n/** Every import of a provider SDK package. */\nexport function providerSdkImports(file: FileView, sdks: readonly string[]): Array<{ node: ts.Node; spec: string }> {\n return moduleImports(file.sourceFile, MODULE_LOADS)\n .filter(({ spec }) => sdks.some((sdk) => namesModule(spec, sdk)))\n .map(({ node, spec }) => ({ node, spec }));\n}\n\n/** Every `vi.mock` / `vi.doMock` of a package. */\nexport function packageMocks(file: FileView, pkg: string): ts.Node[] {\n return moduleImports(file.sourceFile, ['mock'])\n .filter(({ callee, spec }) => (callee === 'vi.mock' || callee === 'vi.doMock') && namesModule(spec, pkg))\n .map(({ node }) => node);\n}\n\n/** True when a file renders `<Element />` (or `<Element>…`). */\nconst mountsElement = (file: FileView, element: string) => new RegExp(`<${escapeRegExp(element)}(?=[\\\\s/>])`).test(file.code);\n\nexport const monitoringGuard: GenericGuardDefinition<MonitoringFacts> = {\n id: 'monitoring',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.monitoringPackage, 'monitoringPackage', problems);\n textProblem(facts?.initCall, 'initCall', problems);\n namesProblem(facts?.captureCalls, 'captureCalls', problems);\n namesProblem(facts?.callableExits, 'callableExits', problems, { nonEmpty: false });\n textProblem(facts?.functionsInit, 'functionsInit', problems);\n if (!Array.isArray(facts?.appReporters)) problems.push('appReporters is missing (declare [] when the app root binds no reporter)');\n for (const r of facts?.appReporters ?? []) {\n if (!r?.file || !r.mountedIn || !r.element) problems.push('an app reporter needs its file, the layout that mounts it, and the element');\n }\n namesProblem(facts?.providerSdks, 'providerSdks', problems);\n textProblem(facts?.providerInitCall, 'providerInitCall', problems);\n reviewedProblems(facts?.sdkInitFiles, 'sdkInitFiles', problems);\n textProblem(facts?.functionsTestRecorder, 'functionsTestRecorder', problems);\n if (!Array.isArray(facts?.reportedByCore)) problems.push('reportedByCore is missing (declare [] when every entry point reports its own failures)');\n for (const entry of facts?.reportedByCore ?? []) {\n if (!entry?.path || !entry.core || !entry.why?.trim()) problems.push('a reportedByCore entry needs its entry file, its core module, and its why');\n }\n return problems;\n },\n build(facts) {\n const initPattern = callPattern(facts.initCall);\n const providerInit = callPattern(facts.providerInitCall);\n const entryPoints: Guard = {\n title: 'every Cloud Function entry point reports its failures to monitoring',\n description:\n 'Every file that defines a deployed Cloud Function — callable, HTTP, schedule, Firestore, Storage, pub/sub, task, ' +\n `or database trigger — either exits its callable through ${facts.callableExits.join(' / ') || 'the app\\'s callable exit'} ` +\n `or imports ${facts.monitoringPackage} and calls ${facts.captureCalls.join(' / ')} on its failure path. A failure ` +\n 'path that only writes a log line is not monitored: nothing watches the log, so a background trigger fails ' +\n 'invisibly. An import that is never called is not monitoring either. An entry point whose core reports every ' +\n 'failure is a reviewed entry naming that core, with its why; it is stale when the core no longer captures, ' +\n 'the entry point no longer imports it, or the entry point reports on its own.',\n run(context) {\n const findings: Finding[] = [];\n const reviewed = new Map(facts.reportedByCore.map((entry) => [entry.path, entry]));\n const seen = new Set<string>();\n for (const file of context.files(FUNCTIONS_CODE)) {\n const shapes = unmonitoredEntryPoint(file, facts);\n const entry = reviewed.get(file.path);\n if (!entry) {\n if (shapes.length) findings.push({ file: file.path, detail: `defines ${shapes.join(', ')} and reports no failure to monitoring` });\n continue;\n }\n seen.add(file.path);\n if (!ENTRY_POINT_SHAPES.some(({ re }) => re.test(file.code))) {\n findings.push({ file: file.path, detail: 'a reportedByCore entry for a file that defines no entry point' });\n } else if (!shapes.length) {\n findings.push({ file: file.path, detail: 'a reportedByCore entry for an entry point that reports on its own' });\n } else if (!importsModule(file, entry.core)) {\n findings.push({ file: file.path, detail: `a reportedByCore entry names ${entry.core}, which the entry point does not import` });\n } else if (!context.reader.exists(entry.core) || !reportsToMonitoring(context.file(entry.core), facts)) {\n findings.push({ file: file.path, detail: `a reportedByCore entry names ${entry.core}, which reports no failure to monitoring` });\n }\n }\n for (const entry of facts.reportedByCore) {\n if (!seen.has(entry.path)) findings.push({ file: entry.path, detail: 'a reportedByCore entry for a file the Functions code does not hold' });\n }\n return findings;\n },\n };\n const initOnce: Guard = {\n title: 'monitoring is initialized once per runtime, only in its adapters',\n description:\n `The Functions runtime initializes monitoring in ${facts.functionsInit} and nowhere else; the app root binds its ` +\n `reporter only in its declared adapters, each initializing once and mounted by its layout. A second ` +\n `${facts.initCall} is a second configuration nothing keeps aligned with the first and double-reports the moment ` +\n 'both run; a missing one leaves every capture writing into an unbound client. Pass the values at the existing ' +\n 'adapter instead of opening a new init.',\n run(context) {\n const findings: Finding[] = [];\n let functionsInits = 0;\n for (const file of context.files(FUNCTIONS_CODE)) {\n const sites = matchIndexes(file, initPattern);\n if (file.path === facts.functionsInit) functionsInits += sites.length;\n else for (const i of sites) findings.push({ file: file.path, line: file.lineOf(i), detail: `${facts.initCall} outside the Functions adapter` });\n }\n if (functionsInits !== 1) findings.push({ file: facts.functionsInit, detail: `the Functions adapter calls ${facts.initCall} ${functionsInits} times, not once` });\n const reporters = new Map(facts.appReporters.map((r) => [r.file, r]));\n const reporterInits = new Map<string, number>();\n for (const file of context.files(APP_CODE)) {\n const sites = matchIndexes(file, initPattern);\n if (reporters.has(file.path)) reporterInits.set(file.path, sites.length);\n else for (const i of sites) findings.push({ file: file.path, line: file.lineOf(i), detail: `${facts.initCall} outside the app's reporter adapters` });\n }\n for (const reporter of facts.appReporters) {\n const count = reporterInits.get(reporter.file) ?? 0;\n if (count !== 1) findings.push({ file: reporter.file, detail: `the reporter adapter calls ${facts.initCall} ${count} times, not once` });\n if (!context.reader.exists(reporter.mountedIn)) findings.push({ file: reporter.mountedIn, detail: 'the layout that mounts the reporter no longer exists' });\n else if (!mountsElement(context.file(reporter.mountedIn), reporter.element)) {\n findings.push({ file: reporter.mountedIn, detail: `does not mount <${reporter.element} />, so the reporter is never bound` });\n }\n }\n return findings;\n },\n };\n const providerNamed: Guard = {\n title: 'the monitoring provider SDK is named only where it starts',\n description:\n `No file in the app or Functions roots imports a provider SDK package (${facts.providerSdks.join(', ')}) or calls ` +\n `${facts.providerInitCall}: the provider binds inside ${facts.monitoringPackage}, and a direct import is a third ` +\n 'binding site whose DSN, environment, and sample rate the app boundary can no longer supply. Capture through the ' +\n 'monitoring package instead. Each declared SDK init file still starts the SDK; one that no longer does is stale.',\n run(context) {\n const findings: Finding[] = [];\n for (const file of context.files(APP_AND_FUNCTIONS_CODE)) {\n for (const { node, spec } of providerSdkImports(file, facts.providerSdks)) {\n findings.push({ file: file.path, line: lineOfNode(file, node), detail: `imports ${spec}` });\n }\n for (const i of matchIndexes(file, providerInit)) findings.push({ file: file.path, line: file.lineOf(i), detail: `calls ${facts.providerInitCall}` });\n }\n for (const entry of facts.sdkInitFiles) {\n if (!context.reader.exists(entry.path)) findings.push({ file: entry.path, detail: 'stale SDK init file: it no longer exists' });\n else if (!matchIndexes(context.file(entry.path), providerInit).length) {\n findings.push({ file: entry.path, detail: `stale SDK init file: it no longer calls ${facts.providerInitCall}` });\n }\n }\n return findings;\n },\n };\n const recorderSeam: Guard = {\n title: 'Functions tests capture through the recording seam, never a local mock of the monitoring package',\n description:\n `No Functions test replaces ${facts.monitoringPackage} with a local vi.mock / vi.doMock. A test that asserts a ` +\n `capture installs the recording adapter (${facts.functionsTestRecorder}) through the package's own adapter seam; a ` +\n 'test that only needs the handler to run needs no mock at all. A local mock lists only the exports its author ' +\n 'knew, and a stubbed scope wrapper never runs the wrapped handler.',\n run(context) {\n const findings: Finding[] = [];\n let seam = false;\n for (const file of context.files({ roots: ['functions'], kinds: ['code'], tests: 'only' })) {\n if (file.path === facts.functionsTestRecorder) seam = true;\n for (const node of packageMocks(file, facts.monitoringPackage)) {\n findings.push({ file: file.path, line: lineOfNode(file, node), detail: `mocks ${facts.monitoringPackage}` });\n }\n }\n if (!seam) findings.push({ file: facts.functionsTestRecorder, detail: 'the recording seam is gone or is not test code' });\n return findings;\n },\n };\n return [entryPoints, initOnce, providerNamed, recorderSeam];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Telemetry tag keys survive the content policy.\n\nexport interface TelemetryTagFacts {\n /** The app's telemetry content policy, as its monitoring package builds it, loaded at run time. */\n policy: () => Promise<{ isDiagnosticKey(key: string): boolean }> | { isDiagnosticKey(key: string): boolean };\n /** Tag keys whose value is always a flag, which passes under any key; a key set nowhere is stale. */\n flagKeys: ReadonlyArray<{ key: string; why: string }>;\n /** The name suffix of a constant whose values are tag keys (`_TAG_KEYS`). */\n tagKeyMapSuffix: string;\n}\n\n/** Every tag key a file sets: a `tags: { … }` literal's keys, `setTag('key', …)`, and a tag-key map's values. */\nexport function tagKeysSet(file: FileView, mapSuffix: string): Array<{ key: string; node: ts.Node }> {\n const sf = file.sourceFile;\n const out: Array<{ key: string; node: ts.Node }> = [];\n const keyOf = (name: ts.PropertyName) => (ts.isIdentifier(name) || ts.isStringLiteralLike(name) ? name.text : undefined);\n forEachNode(sf, (node) => {\n if (ts.isPropertyAssignment(node) && keyOf(node.name) === 'tags' && ts.isObjectLiteralExpression(node.initializer)) {\n for (const prop of node.initializer.properties) {\n const key = (ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop)) && keyOf(prop.name);\n if (key) out.push({ key, node: prop });\n }\n }\n if (ts.isCallExpression(node) && calleeName(node) === 'setTag' && node.arguments[0] && ts.isStringLiteralLike(node.arguments[0])) {\n out.push({ key: node.arguments[0].text, node });\n }\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text.endsWith(mapSuffix) && node.initializer) {\n let init: ts.Expression = node.initializer;\n while (ts.isAsExpression(init) || ts.isSatisfiesExpression(init)) init = init.expression;\n if (ts.isObjectLiteralExpression(init)) {\n for (const prop of init.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isStringLiteralLike(prop.initializer)) out.push({ key: prop.initializer.text, node: prop });\n }\n }\n }\n });\n return out;\n}\n\nexport const telemetryTagGuard: GenericGuardDefinition<TelemetryTagFacts> = {\n id: 'telemetryTagKeys',\n absentWhen: 'the app declares no telemetry content policy',\n factProblems(facts) {\n const problems: string[] = [];\n loaderProblem(facts?.policy, 'policy', problems);\n reviewedProblems(facts?.flagKeys, 'flagKeys', problems, { key: 'key' });\n textProblem(facts?.tagKeyMapSuffix, 'tagKeyMapSuffix', problems);\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'every backend telemetry tag key survives the content policy',\n description:\n 'A tag the backend sets survives the telemetry content policy only under a diagnostic key, so every tag key a ' +\n \"capture site sets — a `tags: { … }` literal's keys, a `setTag('key', …)`, a tag-key map's values — is one; \" +\n 'otherwise the policy silently drops it. Rename the tag to a diagnostic key, or widen the policy only to a key ' +\n 'that never holds prose. A key whose value is always a flag is a reviewed entry with its why.',\n async run(context) {\n const policy = await facts.policy();\n const flags = new Set(facts.flagKeys.map((f) => f.key));\n const findings: Finding[] = [];\n const seen = new Set<string>();\n for (const file of context.files(FUNCTIONS_CODE)) {\n for (const { key, node } of tagKeysSet(file, facts.tagKeyMapSuffix)) {\n seen.add(key);\n if (!flags.has(key) && !policy.isDiagnosticKey(key)) {\n findings.push({ file: file.path, line: lineOfNode(file, node), detail: `tag key ${key} is not a diagnostic key, so the policy drops it` });\n }\n }\n }\n if (!seen.size) findings.push({ file: '(functions)', detail: 'no tag key found, so the guard checks nothing' });\n for (const key of flags) if (!seen.has(key)) findings.push({ file: '(flagKeys)', detail: `stale flag key ${key}: no capture site sets it` });\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// A service the app does not use is named nowhere.\n\nexport interface UnusedServiceFacts {\n /** Services the product has no surface for, each with its why. */\n services: ReadonlyArray<{ name: string; why: string }>;\n /** Text that contains a service's name but is not the service (a word it is part of), each with its why. */\n collisions: ReadonlyArray<{ text: string; why: string }>;\n /** Files outside the roots read by name: manifests, deployed configuration, workflows, rules, index files. */\n namedFiles: readonly string[];\n}\n\nconst SERVICE_SCOPE: Scope = {\n roots: ['app', 'functions', 'e2e', 'hostedE2e', 'scripts', 'workers'],\n optionalRoots: ['functions', 'e2e', 'hostedE2e', 'scripts', 'workers'],\n kinds: ['code', 'config', 'rules'],\n tests: true,\n};\n\n/**\n * Where a service's name appears as a name: its lowercase form starting a word and not running on\n * into lowercase letters (`svc`, `svcSessionId`, `svc.`, `'svc'`, `@svc/`); its capitalized form\n * anywhere not running on (`Svc`, `loadSvc`); its uppercase form standing alone between non-letters\n * (`SVC_KEY`). A longer word that merely contains it (`svced`, `pinsvc`) is not the service.\n */\nexport function serviceNamePatterns(name: string): RegExp[] {\n const lower = escapeRegExp(name.toLowerCase());\n const cap = escapeRegExp(name.charAt(0).toUpperCase() + name.slice(1).toLowerCase());\n const upper = escapeRegExp(name.toUpperCase());\n return [\n new RegExp(`(?<![A-Za-z0-9])${lower}(?![a-z])`, 'g'),\n new RegExp(`${cap}(?![a-z])`, 'g'),\n new RegExp(`(?<![A-Z0-9])${upper}(?![A-Z0-9])`, 'g'),\n ];\n}\n\n/** The lines of a file's text a reader of the service name reads: comments skipped by line. */\nfunction readableLines(file: FileView): string[] {\n const lines = file.code.split('\\n');\n const name = file.path.slice(file.path.lastIndexOf('/') + 1);\n if (file.kind === 'config' && !/\\.jsonc?$/.test(name)) return lines.map((l) => (/^\\s*#/.test(l) ? '' : l));\n if (file.kind === 'rules') return lines.map((l) => (/^\\s*\\/\\//.test(l) ? '' : l));\n return lines;\n}\n\n/** Every place a file names a service, collisions taken out; `collisionHits` counts each collision seen. */\nexport function serviceNameSites(\n file: FileView,\n facts: Pick<UnusedServiceFacts, 'services' | 'collisions'>,\n collisionHits?: Map<string, number>,\n): Array<{ line: number; detail: string }> {\n const out: Array<{ line: number; detail: string }> = [];\n for (const { name } of facts.services) {\n const segment = new RegExp(`^${escapeRegExp(name)}(?:\\\\.[cm]?[jt]sx?)?$`, 'i');\n if (file.path.split('/').some((s) => segment.test(s))) out.push({ line: 1, detail: `the file path is named for ${name}` });\n }\n readableLines(file).forEach((line, index) => {\n const covered: Array<[number, number]> = [];\n for (const { text } of facts.collisions) {\n for (let i = line.indexOf(text); i !== -1; i = line.indexOf(text, i + 1)) {\n covered.push([i, i + text.length]);\n collisionHits?.set(text, (collisionHits.get(text) ?? 0) + 1);\n }\n }\n for (const { name } of facts.services) {\n for (const re of serviceNamePatterns(name)) {\n for (let m = re.exec(line); m; m = re.exec(line)) {\n const start = m.index;\n const end = start + m[0].length;\n if (!covered.some(([a, b]) => a <= start && end <= b)) out.push({ line: index + 1, detail: `names ${name}: ${line.trim().slice(0, 100)}` });\n }\n }\n }\n });\n const seen = new Set<string>();\n return out.filter((s) => {\n const key = `${s.line}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nexport const unusedServiceGuard: GenericGuardDefinition<UnusedServiceFacts> = {\n id: 'unusedService',\n absentWhen: 'the app has no external service it must keep out of the product',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.services, 'services', problems, { key: 'name', nonEmpty: true });\n for (const s of facts?.services ?? []) if (typeof s?.name === 'string' && !/^[A-Za-z][A-Za-z0-9]*$/.test(s.name)) problems.push(`service ${s.name} is not one word`);\n reviewedProblems(facts?.collisions, 'collisions', problems, { key: 'text' });\n namesProblem(facts?.namedFiles, 'namedFiles', problems, { nonEmpty: false });\n return problems;\n },\n build(facts) {\n const names = facts.services.map((s) => s.name).join(', ');\n return [\n {\n title: 'a service the product does not use is named nowhere',\n description:\n `The product has no surface for ${names}, so nothing names it: no source, test, or script — not its SDK ` +\n 'packages, its client or loader, a module of the tree named for it, a field, callable, hook, or handler built on ' +\n 'its name, or its credentials — and no manifest, deployed configuration, workflow, rules file, or index file. The ' +\n 'service returns only as a product decision that brings its own adapter, secret binding, rules, and tests. Text ' +\n 'that merely contains the name is a reviewed collision with its why; a collision found nowhere is stale.',\n run(context) {\n const findings: Finding[] = [];\n const collisionHits = new Map<string, number>();\n const files = context.files(SERVICE_SCOPE);\n const read = new Set(files.map((f) => f.path));\n for (const path of facts.namedFiles) {\n if (read.has(path)) continue;\n if (!context.reader.exists(path)) findings.push({ file: path, detail: 'a named file no longer exists' });\n else files.push(context.file(path));\n }\n for (const file of files) {\n for (const site of serviceNameSites(file, facts, collisionHits)) findings.push({ file: file.path, line: site.line, detail: site.detail });\n }\n for (const { text } of facts.collisions) if (!collisionHits.get(text)) findings.push({ file: '(collisions)', detail: `stale collision ${text}: it appears nowhere` });\n return findings;\n },\n },\n ];\n },\n};\n"]}
@@ -27,7 +27,7 @@ export declare function boundaryDerivations(file: FileView, facts: Pick<ClientAu
27
27
  detail: string;
28
28
  }>;
29
29
  /** A second export of the accessor's name, or a context holding auth vocabulary, in one file. */
30
- export declare function secondAuthAccessors(path: string, code: string, facts: Pick<ClientAuthBoundaryFacts, 'accessor' | 'authContextVocabulary' | 'boundaryModules'>): Array<{
30
+ export declare function secondAuthAccessors(path: string, code: string, sourceFile: ts.SourceFile, facts: Pick<ClientAuthBoundaryFacts, 'accessor' | 'authContextVocabulary' | 'boundaryModules'>): Array<{
31
31
  index: number;
32
32
  detail: string;
33
33
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/modules/frontend-actions/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/modules/frontend-actions/auth.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,15 @@
1
1
  // The guards over the client's auth boundary: one place that answers "who is this", auth failures
2
2
  // that reach monitoring, sign-out liveness through its owner, and editors no permission read can drop.
3
3
  import ts from 'typescript';
4
+ import { calleeName, forEachNode } from '../../support/ast.js';
4
5
  import { namesProblem, objectProblem, reviewedProblems, textProblem } from '../../support/facts.js';
5
6
  import { fromStatements, moduleImports, namesModule } from '../../support/imports.js';
6
7
  import { escapeRegExp, isUnder } from '../../support/text.js';
7
8
  import { memberOrBareCalls, throughNamespace } from './text.js';
8
9
  const APP_CODE = { roots: ['app'], kinds: ['code'], tests: false };
9
- const declares = (code, name) => new RegExp(`\\b(?:function|const|let)\\s+${escapeRegExp(name)}\\b`).test(code);
10
+ /** The keywords that declare a name a module can export: a function, a binding, or a class. */
11
+ const DECLARATION_KEYWORDS = '(?:function|const|let|class)';
12
+ const declares = (code, name) => new RegExp(`\\b${DECLARATION_KEYWORDS}\\s+${escapeRegExp(name)}\\b`).test(code);
10
13
  /**
11
14
  * Each place outside the boundary that derives identity, claims, or auth loading itself. A call is
12
15
  * matched bare or as a member (`auth.onAuthStateChanged(cb)`, `getAuth().onIdTokenChanged(cb)`),
@@ -43,7 +46,7 @@ export function boundaryDerivations(file, facts) {
43
46
  return out;
44
47
  }
45
48
  /** A second export of the accessor's name, or a context holding auth vocabulary, in one file. */
46
- export function secondAuthAccessors(path, code, facts) {
49
+ export function secondAuthAccessors(path, code, sourceFile, facts) {
47
50
  const out = [];
48
51
  const name = escapeRegExp(facts.accessor.name);
49
52
  if (path !== facts.accessor.file) {
@@ -55,13 +58,56 @@ export function secondAuthAccessors(path, code, facts) {
55
58
  }
56
59
  if (!facts.boundaryModules.some((m) => m.path === path)) {
57
60
  const vocabulary = new RegExp(`\\b(?:${facts.authContextVocabulary.map(escapeRegExp).join('|')})\\b`);
58
- if (vocabulary.test(code)) {
59
- for (const m of code.matchAll(/\bcreateContext\s*[<(]/g))
60
- out.push({ index: m.index, detail: 'a second auth context' });
61
+ for (const call of contextCreations(sourceFile)) {
62
+ if (contextShapeTexts(call, sourceFile, code).some((text) => vocabulary.test(text))) {
63
+ out.push({ index: call.getStart(sourceFile), detail: 'a second auth context' });
64
+ }
61
65
  }
62
66
  }
63
67
  return out;
64
68
  }
69
+ /** Every `createContext(…)` call in a file, bare or through a namespace. */
70
+ function contextCreations(sourceFile) {
71
+ const calls = [];
72
+ forEachNode(sourceFile, (node) => {
73
+ if (ts.isCallExpression(node) && calleeName(node) === 'createContext')
74
+ calls.push(node);
75
+ });
76
+ return calls;
77
+ }
78
+ /**
79
+ * The comment-free text of what a context holds: its type argument, the same-file interface or type
80
+ * alias that argument names, its default value, and the same-file constant that value names. Only
81
+ * these say whether the context carries auth state; the rest of the file does not.
82
+ */
83
+ function contextShapeTexts(call, sourceFile, code) {
84
+ const textOf = (node) => code.slice(node.getStart(sourceFile), node.getEnd());
85
+ const declared = (name) => {
86
+ const found = [];
87
+ forEachNode(sourceFile, (node) => {
88
+ if ((ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) && node.name.text === name)
89
+ found.push(node);
90
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === name && node.initializer)
91
+ found.push(node.initializer);
92
+ });
93
+ return found;
94
+ };
95
+ const texts = [];
96
+ for (const typeArg of call.typeArguments ?? []) {
97
+ texts.push(textOf(typeArg));
98
+ forEachNode(typeArg, (node) => {
99
+ if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName))
100
+ texts.push(...declared(node.typeName.text).map(textOf));
101
+ });
102
+ }
103
+ const initial = call.arguments[0];
104
+ if (initial) {
105
+ texts.push(textOf(initial));
106
+ if (ts.isIdentifier(initial))
107
+ texts.push(...declared(initial.text).map(textOf));
108
+ }
109
+ return texts;
110
+ }
65
111
  export const clientAuthBoundaryGuard = {
66
112
  id: 'clientAuthBoundary',
67
113
  absentWhen: 'the app has no signed-in users',
@@ -94,7 +140,7 @@ export const clientAuthBoundaryGuard = {
94
140
  const inBoundary = facts.boundaryModules.some((m) => m.path === file.path);
95
141
  const hits = [
96
142
  ...(inBoundary ? [] : boundaryDerivations(file, facts)),
97
- ...secondAuthAccessors(file.path, file.code, facts),
143
+ ...secondAuthAccessors(file.path, file.code, file.sourceFile, facts),
98
144
  ];
99
145
  for (const hit of hits)
100
146
  findings.push({ file: file.path, line: file.lineOf(hit.index), detail: hit.detail });
@@ -235,7 +281,7 @@ export const signOutLivenessGuard = {
235
281
  return problems;
236
282
  },
237
283
  build(facts) {
238
- const redeclared = new RegExp(`\\b(?:function|const)\\s+(?:${facts.ownerExports.map(escapeRegExp).join('|')})\\b`, 'g');
284
+ const redeclared = new RegExp(`\\b${DECLARATION_KEYWORDS}\\s+(?:${facts.ownerExports.map(escapeRegExp).join('|')})\\b`, 'g');
239
285
  const negatedSkip = new RegExp(`!\\s*${escapeRegExp(facts.authAccessor)}\\(\\)\\s*\\??\\.\\s*currentUser`, 'g');
240
286
  return [
241
287
  {
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/modules/frontend-actions/auth.ts"],"names":[],"mappings":"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","sourcesContent":["// The guards over the client's auth boundary: one place that answers \"who is this\", auth failures\n// that reach monitoring, sign-out liveness through its owner, and editors no permission read can drop.\n\nimport ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../config.js';\nimport type { Finding, Guard } from '../../guard.js';\nimport type { Reviewed } from '../../reader/layout.js';\nimport type { Scope } from '../../reader/reader.js';\nimport type { FileView } from '../../reader/view.js';\nimport { namesProblem, objectProblem, reviewedProblems, textProblem } from '../../support/facts.js';\nimport { fromStatements, moduleImports, namesModule } from '../../support/imports.js';\nimport { escapeRegExp, isUnder } from '../../support/text.js';\nimport { memberOrBareCalls, throughNamespace } from './text.js';\n\nconst APP_CODE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\n\nconst declares = (code: string, name: string) => new RegExp(`\\\\b(?:function|const|let)\\\\s+${escapeRegExp(name)}\\\\b`).test(code);\n\n// ---------------------------------------------------------------------------------------------\n// Client auth boundary: one derivation of identity and claims, and one auth context and accessor.\n// Where a signed-out visitor is sent is business: an app browsable signed out shows a sign-in gate in\n// place, an app that requires sign-in sends the visitor to its sign-in route. It is not checked here.\n\nexport interface ClientAuthBoundaryFacts {\n /** The modules that ARE the boundary — the provider mount, its configuration, the accessor — each with why. */\n boundaryModules: readonly Reviewed[];\n /** The one accessor every other module reads auth through. */\n accessor: { file: string; name: string };\n /** Symbols that derive identity, claims, or auth loading state. */\n derivationSymbols: readonly string[];\n /** Modules those symbols can be reached through as a namespace (a module covers its subpaths). */\n authSourceModules: readonly string[];\n /** Names only an auth context holds; a `createContext` beside one is a second auth context. */\n authContextVocabulary: readonly string[];\n}\n\n/**\n * Each place outside the boundary that derives identity, claims, or auth loading itself. A call is\n * matched bare or as a member (`auth.onAuthStateChanged(cb)`, `getAuth().onIdTokenChanged(cb)`),\n * since the SDK hands out the same derivations as instance methods.\n */\nexport function boundaryDerivations(file: FileView, facts: Pick<ClientAuthBoundaryFacts, 'derivationSymbols' | 'authSourceModules'>): Array<{ index: number; detail: string }> {\n const { code, sourceFile } = file;\n const out: Array<{ index: number; detail: string }> = [];\n for (const site of moduleImports(sourceFile, ['import'])) {\n if (site.typeOnly) continue;\n for (const { imported, typeOnly } of site.named) {\n if (!typeOnly && facts.derivationSymbols.includes(imported)) out.push({ index: site.node.getStart(sourceFile), detail: `imports ${imported}` });\n }\n }\n const namespaces: string[] = [];\n for (const site of fromStatements(sourceFile)) {\n if (site.namespace && facts.authSourceModules.some((m) => namesModule(site.spec, m))) namespaces.push(site.namespace);\n }\n for (const namespace of namespaces) {\n for (const symbol of facts.derivationSymbols) {\n const m = new RegExp(`\\\\b${escapeRegExp(namespace)}\\\\s*\\\\.\\\\s*${escapeRegExp(symbol)}\\\\b`).exec(code);\n if (m) out.push({ index: m.index, detail: `reaches ${namespace}.${symbol}` });\n }\n }\n for (const symbol of facts.derivationSymbols) {\n const call = memberOrBareCalls(code, symbol).find((index) => !throughNamespace(code, index, namespaces));\n if (call !== undefined) out.push({ index: call, detail: `calls ${symbol}(` });\n }\n return out;\n}\n\n/** A second export of the accessor's name, or a context holding auth vocabulary, in one file. */\nexport function secondAuthAccessors(\n path: string,\n code: string,\n facts: Pick<ClientAuthBoundaryFacts, 'accessor' | 'authContextVocabulary' | 'boundaryModules'>,\n): Array<{ index: number; detail: string }> {\n const out: Array<{ index: number; detail: string }> = [];\n const name = escapeRegExp(facts.accessor.name);\n if (path !== facts.accessor.file) {\n const exported =\n new RegExp(`\\\\bexport\\\\s+function\\\\s+${name}\\\\s*[(<]`).exec(code) ??\n new RegExp(`\\\\bexport\\\\s+(?:const|let|var)\\\\s+${name}\\\\b`).exec(code) ??\n new RegExp(`\\\\bexport\\\\s*\\\\{[^}]*\\\\b${name}\\\\b[^}]*\\\\}`).exec(code);\n if (exported) out.push({ index: exported.index, detail: `a second export of ${facts.accessor.name}` });\n }\n if (!facts.boundaryModules.some((m) => m.path === path)) {\n const vocabulary = new RegExp(`\\\\b(?:${facts.authContextVocabulary.map(escapeRegExp).join('|')})\\\\b`);\n if (vocabulary.test(code)) {\n for (const m of code.matchAll(/\\bcreateContext\\s*[<(]/g)) out.push({ index: m.index!, detail: 'a second auth context' });\n }\n }\n return out;\n}\n\nexport const clientAuthBoundaryGuard: GenericGuardDefinition<ClientAuthBoundaryFacts> = {\n id: 'clientAuthBoundary',\n absentWhen: 'the app has no signed-in users',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.boundaryModules, 'boundaryModules', problems);\n if (objectProblem(facts?.accessor, 'accessor', problems)) {\n textProblem(facts.accessor.file, 'accessor.file', problems);\n textProblem(facts.accessor.name, 'accessor.name', problems);\n if (Array.isArray(facts.boundaryModules) && !facts.boundaryModules.some((m) => m?.path === facts.accessor.file)) {\n problems.push(`the accessor ${facts.accessor.file} is not one of the boundaryModules`);\n }\n }\n namesProblem(facts?.derivationSymbols, 'derivationSymbols', problems);\n namesProblem(facts?.authSourceModules, 'authSourceModules', problems);\n namesProblem(facts?.authContextVocabulary, 'authContextVocabulary', problems);\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'the client has one auth boundary',\n description:\n `Identity, claims, and auth loading state come from one provider, read through \\`${facts.accessor.name}\\` ` +\n `(${facts.accessor.file}). Outside the boundary modules nothing imports, reaches, or calls ` +\n `${facts.derivationSymbols.join(', ')}; no other module exports \\`${facts.accessor.name}\\` or creates a ` +\n 'context holding auth state. Read the accessor.',\n run(context) {\n const findings: Finding[] = [];\n for (const file of context.files(APP_CODE)) {\n const inBoundary = facts.boundaryModules.some((m) => m.path === file.path);\n const hits = [\n ...(inBoundary ? [] : boundaryDerivations(file, facts)),\n ...secondAuthAccessors(file.path, file.code, facts),\n ];\n for (const hit of hits) findings.push({ file: file.path, line: file.lineOf(hit.index), detail: hit.detail });\n }\n for (const module of facts.boundaryModules) {\n if (!context.reader.exists(module.path)) findings.push({ file: module.path, detail: 'stale boundary module: it no longer exists' });\n }\n if (context.reader.exists(facts.accessor.file)) {\n const code = context.file(facts.accessor.file).code;\n if (!new RegExp(`\\\\bexport\\\\s+(?:function|const)\\\\s+${escapeRegExp(facts.accessor.name)}\\\\b`).test(code)) {\n findings.push({ file: facts.accessor.file, detail: `the accessor no longer exports ${facts.accessor.name}` });\n }\n }\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Banned auth calls: a call the auth surfaces must never make.\n\nexport interface BannedAuthCallFacts {\n /** The folders and files that make up the auth surfaces. */\n surfaces: readonly string[];\n /** Each banned call and why it is banned. */\n banned: ReadonlyArray<{ name: string; why: string }>;\n /** A long-lived auth surface the scan must reach. */\n anchor: string;\n}\n\nexport const bannedAuthCallGuard: GenericGuardDefinition<BannedAuthCallFacts> = {\n id: 'bannedAuthCalls',\n absentWhen: 'the app has no signed-in users',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.surfaces, 'surfaces', problems);\n if (!Array.isArray(facts?.banned) || !facts.banned.length) problems.push('banned is missing or empty');\n else for (const b of facts.banned) {\n textProblem(b?.name, 'a banned call', problems);\n textProblem(b?.why, `banned call ${String(b?.name)}'s why`, problems);\n }\n textProblem(facts?.anchor, 'anchor', problems);\n if (typeof facts?.anchor === 'string' && Array.isArray(facts?.surfaces) && !facts.surfaces.some((s) => isUnder(facts.anchor, s))) {\n problems.push(`the anchor ${facts.anchor} is not inside any surface`);\n }\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'the auth surfaces never name a banned auth call',\n description:\n `No file under ${facts.surfaces.join(', ')} imports or calls ` +\n facts.banned.map((b) => `\\`${b.name}\\` (${b.why})`).join('; ') +\n '. The symbol must not be reachable from these modules at all.',\n run(context) {\n const findings: Finding[] = [];\n const files = context.files(APP_CODE).filter((f) => facts.surfaces.some((s) => isUnder(f.path, s)));\n if (!files.some((f) => f.path === facts.anchor)) findings.push({ file: facts.anchor, detail: 'the anchor surface was not reached (gone, or outside the surfaces)' });\n for (const file of files) {\n for (const { name, why } of facts.banned) {\n const re = new RegExp(`\\\\b${escapeRegExp(name)}\\\\b`, 'g');\n for (let m = re.exec(file.code); m; m = re.exec(file.code)) {\n findings.push({ file: file.path, line: file.lineOf(m.index), detail: `names ${name}: ${why}` });\n }\n }\n }\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Auth failure capture: every source calling a Firebase Auth operation that can fail reports it.\n\nexport interface AuthFailureCaptureFacts {\n /** The function every auth failure is reported through. */\n reporter: string;\n /** Sources that leave the report to the code that catches their failure, each with why and the file that reports it. */\n reportedElsewhere: ReadonlyArray<{ path: string; why: string; reportedBy: string }>;\n}\n\n/** The Firebase Auth operations that reach the service and can fail. */\nconst FAILING_AUTH_OPERATION =\n /^(?:createUserWithEmailAndPassword|signInWith\\w+|signOut|sendPasswordResetEmail|confirmPasswordReset|verifyPasswordResetCode|checkActionCode|applyActionCode|sendEmailVerification|reauthenticateWith\\w+|updatePassword|updateEmail|verifyBeforeUpdateEmail|linkWith\\w+|deleteUser)$/;\n\n/** The failing operations a source imports as values from the Firebase Auth SDK. */\nexport function failingAuthImports(file: FileView): string[] {\n const names: string[] = [];\n for (const site of moduleImports(file.sourceFile, ['import'])) {\n if (site.typeOnly || site.spec !== 'firebase/auth') continue;\n for (const { imported, typeOnly } of site.named) if (!typeOnly && FAILING_AUTH_OPERATION.test(imported)) names.push(imported);\n }\n return names;\n}\n\nexport const authFailureCaptureGuard: GenericGuardDefinition<AuthFailureCaptureFacts> = {\n id: 'authFailureCapture',\n absentWhen: 'the app has no signed-in users',\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.reporter, 'reporter', problems);\n reviewedProblems(facts?.reportedElsewhere, 'reportedElsewhere', problems);\n for (const e of Array.isArray(facts?.reportedElsewhere) ? facts.reportedElsewhere : []) {\n if (e && (typeof e.reportedBy !== 'string' || !e.reportedBy.trim())) {\n problems.push(`reportedElsewhere entry ${e.path} names no reportedBy file (the file that reports its failures)`);\n }\n }\n return problems;\n },\n build(facts) {\n const reports = new RegExp(`\\\\b${escapeRegExp(facts.reporter)}\\\\s*\\\\(`);\n return [\n {\n title: 'every Firebase Auth failure reaches monitoring',\n description:\n `A source that calls a Firebase Auth operation that can fail reports its failure through \\`${facts.reporter}\\`; ` +\n 'a catch that only shows a message leaves a broken sign-up or sign-in invisible to monitoring. A source that ' +\n 'never catches the failure itself is a reviewed entry naming who reports for it; an entry that no longer calls ' +\n 'a failing operation, now reports itself, or whose reporter no longer reports is stale.',\n run(context) {\n const findings: Finding[] = [];\n const callers = context.files(APP_CODE).map((f) => ({ file: f, ops: failingAuthImports(f) })).filter((c) => c.ops.length);\n if (!callers.length) findings.push({ file: '(app)', detail: 'no source imports a failing Firebase Auth operation — the scan found no auth surface' });\n const reviewed = new Map(facts.reportedElsewhere.map((e) => [e.path, e]));\n for (const { file, ops } of callers) {\n if (!reports.test(file.code) && !reviewed.has(file.path)) findings.push({ file: file.path, detail: `calls ${ops.join(', ')} and never reports a failure` });\n }\n for (const entry of facts.reportedElsewhere) {\n const caller = callers.find((c) => c.file.path === entry.path);\n if (!caller) findings.push({ file: entry.path, detail: 'stale entry: it no longer calls a failing auth operation' });\n else if (reports.test(caller.file.code)) findings.push({ file: entry.path, detail: 'stale entry: it reports its own failures now' });\n if (!context.reader.exists(entry.reportedBy)) findings.push({ file: entry.reportedBy, detail: `the reporter named for ${entry.path} no longer exists` });\n else if (!reports.test(context.file(entry.reportedBy).code)) findings.push({ file: entry.reportedBy, detail: `the reporter named for ${entry.path} no longer reports` });\n }\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Sign-out liveness: the \"still signed in\" check has one owner.\n\nexport interface SignOutLivenessFacts {\n /** The module that owns the liveness check. */\n owner: string;\n /** The names the owner exports for it. */\n ownerExports: readonly string[];\n /** The function that returns the client auth instance. */\n authAccessor: string;\n}\n\nexport const signOutLivenessGuard: GenericGuardDefinition<SignOutLivenessFacts> = {\n id: 'signOutLiveness',\n absentWhen: 'the app has no signed-in users',\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.owner, 'owner', problems);\n namesProblem(facts?.ownerExports, 'ownerExports', problems);\n textProblem(facts?.authAccessor, 'authAccessor', problems);\n return problems;\n },\n build(facts) {\n const redeclared = new RegExp(`\\\\b(?:function|const)\\\\s+(?:${facts.ownerExports.map(escapeRegExp).join('|')})\\\\b`, 'g');\n const negatedSkip = new RegExp(`!\\\\s*${escapeRegExp(facts.authAccessor)}\\\\(\\\\)\\\\s*\\\\??\\\\.\\\\s*currentUser`, 'g');\n return [\n {\n title: 'the signed-in check before an awaited call has one owner',\n description:\n `A check that the user is still signed in, made across an awaited hop before a call, is ${facts.owner}'s ` +\n `(${facts.ownerExports.join(', ')}). Nothing else re-declares those names or hand-rolls a negated ` +\n `\\`${facts.authAccessor}().currentUser\\` skip guard: import the owner.`,\n run(context) {\n const findings: Finding[] = [];\n for (const file of context.files(APP_CODE)) {\n if (file.path === facts.owner) continue;\n for (const re of [redeclared, negatedSkip]) {\n re.lastIndex = 0;\n for (let m = re.exec(file.code); m; m = re.exec(file.code)) {\n findings.push({ file: file.path, line: file.lineOf(m.index), detail: re === redeclared ? `re-declares ${m[0].split(/\\s+/).pop()}` : 'hand-rolls a negated currentUser skip guard' });\n }\n }\n }\n if (!context.reader.exists(facts.owner)) findings.push({ file: facts.owner, detail: 'the owner no longer exists' });\n else {\n const code = context.file(facts.owner).code;\n for (const name of facts.ownerExports) if (!declares(code, name)) findings.push({ file: facts.owner, detail: `the owner no longer declares ${name}` });\n }\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Editor permission gate: an editor holding typed input is never mounted under a permission read.\n\nexport interface EditorPermissionGateFacts {\n /** The hook an editor calls to guard its unsaved input: a file calling it holds an editor. */\n editorMarker: string;\n /** The element the editor mounts in. */\n editorElement: string;\n /** Permission reads: identifiers starting with this prefix and a capital letter. */\n permissionNamePrefix: string;\n /** Permission reads: calls to these functions (declare [] when none). */\n permissionCalls: readonly string[];\n}\n\n/** Each editor element with an ancestor `{<permission read> && …}`. */\nexport function permissionGatedEditors(sf: ts.SourceFile, facts: Omit<EditorPermissionGateFacts, 'editorMarker'>): ts.Node[] {\n const prefix = new RegExp(`^${escapeRegExp(facts.permissionNamePrefix)}[A-Z]`);\n const readsPermission = (expr: ts.Expression) => {\n let found = false;\n const visit = (node: ts.Node) => {\n if (ts.isIdentifier(node) && prefix.test(node.text)) found = true;\n if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && facts.permissionCalls.includes(node.expression.text)) found = true;\n ts.forEachChild(node, visit);\n };\n visit(expr);\n return found;\n };\n const out: ts.Node[] = [];\n const visit = (node: ts.Node) => {\n if ((ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) && node.tagName.getText(sf) === facts.editorElement) {\n for (let p: ts.Node | undefined = node.parent; p; p = p.parent) {\n if (\n ts.isJsxExpression(p) &&\n p.expression &&\n ts.isBinaryExpression(p.expression) &&\n p.expression.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&\n readsPermission(p.expression.left)\n ) {\n out.push(node);\n break;\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return out;\n}\n\nexport const editorPermissionGateGuard: GenericGuardDefinition<EditorPermissionGateFacts> = {\n id: 'editorPermissionGate',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.editorMarker, 'editorMarker', problems);\n textProblem(facts?.editorElement, 'editorElement', problems);\n textProblem(facts?.permissionNamePrefix, 'permissionNamePrefix', problems);\n namesProblem(facts?.permissionCalls, 'permissionCalls', problems, { nonEmpty: false });\n return problems;\n },\n build(facts): Guard[] {\n return [\n {\n title: 'an editor holding typed input is never mounted under a permission gate',\n description:\n `A component that guards its unsaved input (\\`${facts.editorMarker}\\`) gates only the control that opens its ` +\n `editor on a permission; its \\`<${facts.editorElement}>\\` stays mounted, so a permission read that changes or ` +\n 'fails while it is open can never unmount it and drop what was typed. Gate the trigger, and key the editor to ' +\n 'the account that opened it.',\n run(context) {\n const findings: Finding[] = [];\n const marker = new RegExp(`\\\\b${escapeRegExp(facts.editorMarker)}\\\\s*\\\\(`);\n const editors = context.files(APP_CODE).filter((f) => marker.test(f.code));\n if (!editors.length) findings.push({ file: '(app)', detail: `no component calls ${facts.editorMarker} — the scan found no editor to check` });\n for (const file of editors) {\n for (const node of permissionGatedEditors(file.sourceFile, facts)) {\n findings.push({ file: file.path, line: file.lineOf(node.getStart(file.sourceFile)), detail: `<${facts.editorElement}> mounted under a permission gate` });\n }\n }\n return findings;\n },\n },\n ];\n },\n};\n"]}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/modules/frontend-actions/auth.ts"],"names":[],"mappings":"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","sourcesContent":["// The guards over the client's auth boundary: one place that answers \"who is this\", auth failures\n// that reach monitoring, sign-out liveness through its owner, and editors no permission read can drop.\n\nimport ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../config.js';\nimport type { Finding, Guard } from '../../guard.js';\nimport type { Reviewed } from '../../reader/layout.js';\nimport type { Scope } from '../../reader/reader.js';\nimport type { FileView } from '../../reader/view.js';\nimport { calleeName, forEachNode } from '../../support/ast.js';\nimport { namesProblem, objectProblem, reviewedProblems, textProblem } from '../../support/facts.js';\nimport { fromStatements, moduleImports, namesModule } from '../../support/imports.js';\nimport { escapeRegExp, isUnder } from '../../support/text.js';\nimport { memberOrBareCalls, throughNamespace } from './text.js';\n\nconst APP_CODE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\n\n/** The keywords that declare a name a module can export: a function, a binding, or a class. */\nconst DECLARATION_KEYWORDS = '(?:function|const|let|class)';\nconst declares = (code: string, name: string) => new RegExp(`\\\\b${DECLARATION_KEYWORDS}\\\\s+${escapeRegExp(name)}\\\\b`).test(code);\n\n// ---------------------------------------------------------------------------------------------\n// Client auth boundary: one derivation of identity and claims, and one auth context and accessor.\n// Where a signed-out visitor is sent is business: an app browsable signed out shows a sign-in gate in\n// place, an app that requires sign-in sends the visitor to its sign-in route. It is not checked here.\n\nexport interface ClientAuthBoundaryFacts {\n /** The modules that ARE the boundary — the provider mount, its configuration, the accessor — each with why. */\n boundaryModules: readonly Reviewed[];\n /** The one accessor every other module reads auth through. */\n accessor: { file: string; name: string };\n /** Symbols that derive identity, claims, or auth loading state. */\n derivationSymbols: readonly string[];\n /** Modules those symbols can be reached through as a namespace (a module covers its subpaths). */\n authSourceModules: readonly string[];\n /** Names only an auth context holds; a `createContext` beside one is a second auth context. */\n authContextVocabulary: readonly string[];\n}\n\n/**\n * Each place outside the boundary that derives identity, claims, or auth loading itself. A call is\n * matched bare or as a member (`auth.onAuthStateChanged(cb)`, `getAuth().onIdTokenChanged(cb)`),\n * since the SDK hands out the same derivations as instance methods.\n */\nexport function boundaryDerivations(file: FileView, facts: Pick<ClientAuthBoundaryFacts, 'derivationSymbols' | 'authSourceModules'>): Array<{ index: number; detail: string }> {\n const { code, sourceFile } = file;\n const out: Array<{ index: number; detail: string }> = [];\n for (const site of moduleImports(sourceFile, ['import'])) {\n if (site.typeOnly) continue;\n for (const { imported, typeOnly } of site.named) {\n if (!typeOnly && facts.derivationSymbols.includes(imported)) out.push({ index: site.node.getStart(sourceFile), detail: `imports ${imported}` });\n }\n }\n const namespaces: string[] = [];\n for (const site of fromStatements(sourceFile)) {\n if (site.namespace && facts.authSourceModules.some((m) => namesModule(site.spec, m))) namespaces.push(site.namespace);\n }\n for (const namespace of namespaces) {\n for (const symbol of facts.derivationSymbols) {\n const m = new RegExp(`\\\\b${escapeRegExp(namespace)}\\\\s*\\\\.\\\\s*${escapeRegExp(symbol)}\\\\b`).exec(code);\n if (m) out.push({ index: m.index, detail: `reaches ${namespace}.${symbol}` });\n }\n }\n for (const symbol of facts.derivationSymbols) {\n const call = memberOrBareCalls(code, symbol).find((index) => !throughNamespace(code, index, namespaces));\n if (call !== undefined) out.push({ index: call, detail: `calls ${symbol}(` });\n }\n return out;\n}\n\n/** A second export of the accessor's name, or a context holding auth vocabulary, in one file. */\nexport function secondAuthAccessors(\n path: string,\n code: string,\n sourceFile: ts.SourceFile,\n facts: Pick<ClientAuthBoundaryFacts, 'accessor' | 'authContextVocabulary' | 'boundaryModules'>,\n): Array<{ index: number; detail: string }> {\n const out: Array<{ index: number; detail: string }> = [];\n const name = escapeRegExp(facts.accessor.name);\n if (path !== facts.accessor.file) {\n const exported =\n new RegExp(`\\\\bexport\\\\s+function\\\\s+${name}\\\\s*[(<]`).exec(code) ??\n new RegExp(`\\\\bexport\\\\s+(?:const|let|var)\\\\s+${name}\\\\b`).exec(code) ??\n new RegExp(`\\\\bexport\\\\s*\\\\{[^}]*\\\\b${name}\\\\b[^}]*\\\\}`).exec(code);\n if (exported) out.push({ index: exported.index, detail: `a second export of ${facts.accessor.name}` });\n }\n if (!facts.boundaryModules.some((m) => m.path === path)) {\n const vocabulary = new RegExp(`\\\\b(?:${facts.authContextVocabulary.map(escapeRegExp).join('|')})\\\\b`);\n for (const call of contextCreations(sourceFile)) {\n if (contextShapeTexts(call, sourceFile, code).some((text) => vocabulary.test(text))) {\n out.push({ index: call.getStart(sourceFile), detail: 'a second auth context' });\n }\n }\n }\n return out;\n}\n\n/** Every `createContext(…)` call in a file, bare or through a namespace. */\nfunction contextCreations(sourceFile: ts.SourceFile): ts.CallExpression[] {\n const calls: ts.CallExpression[] = [];\n forEachNode(sourceFile, (node) => {\n if (ts.isCallExpression(node) && calleeName(node) === 'createContext') calls.push(node);\n });\n return calls;\n}\n\n/**\n * The comment-free text of what a context holds: its type argument, the same-file interface or type\n * alias that argument names, its default value, and the same-file constant that value names. Only\n * these say whether the context carries auth state; the rest of the file does not.\n */\nfunction contextShapeTexts(call: ts.CallExpression, sourceFile: ts.SourceFile, code: string): string[] {\n const textOf = (node: ts.Node) => code.slice(node.getStart(sourceFile), node.getEnd());\n const declared = (name: string): ts.Node[] => {\n const found: ts.Node[] = [];\n forEachNode(sourceFile, (node) => {\n if ((ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) && node.name.text === name) found.push(node);\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === name && node.initializer) found.push(node.initializer);\n });\n return found;\n };\n const texts: string[] = [];\n for (const typeArg of call.typeArguments ?? []) {\n texts.push(textOf(typeArg));\n forEachNode(typeArg, (node) => {\n if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) texts.push(...declared(node.typeName.text).map(textOf));\n });\n }\n const initial = call.arguments[0];\n if (initial) {\n texts.push(textOf(initial));\n if (ts.isIdentifier(initial)) texts.push(...declared(initial.text).map(textOf));\n }\n return texts;\n}\n\nexport const clientAuthBoundaryGuard: GenericGuardDefinition<ClientAuthBoundaryFacts> = {\n id: 'clientAuthBoundary',\n absentWhen: 'the app has no signed-in users',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.boundaryModules, 'boundaryModules', problems);\n if (objectProblem(facts?.accessor, 'accessor', problems)) {\n textProblem(facts.accessor.file, 'accessor.file', problems);\n textProblem(facts.accessor.name, 'accessor.name', problems);\n if (Array.isArray(facts.boundaryModules) && !facts.boundaryModules.some((m) => m?.path === facts.accessor.file)) {\n problems.push(`the accessor ${facts.accessor.file} is not one of the boundaryModules`);\n }\n }\n namesProblem(facts?.derivationSymbols, 'derivationSymbols', problems);\n namesProblem(facts?.authSourceModules, 'authSourceModules', problems);\n namesProblem(facts?.authContextVocabulary, 'authContextVocabulary', problems);\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'the client has one auth boundary',\n description:\n `Identity, claims, and auth loading state come from one provider, read through \\`${facts.accessor.name}\\` ` +\n `(${facts.accessor.file}). Outside the boundary modules nothing imports, reaches, or calls ` +\n `${facts.derivationSymbols.join(', ')}; no other module exports \\`${facts.accessor.name}\\` or creates a ` +\n 'context holding auth state. Read the accessor.',\n run(context) {\n const findings: Finding[] = [];\n for (const file of context.files(APP_CODE)) {\n const inBoundary = facts.boundaryModules.some((m) => m.path === file.path);\n const hits = [\n ...(inBoundary ? [] : boundaryDerivations(file, facts)),\n ...secondAuthAccessors(file.path, file.code, file.sourceFile, facts),\n ];\n for (const hit of hits) findings.push({ file: file.path, line: file.lineOf(hit.index), detail: hit.detail });\n }\n for (const module of facts.boundaryModules) {\n if (!context.reader.exists(module.path)) findings.push({ file: module.path, detail: 'stale boundary module: it no longer exists' });\n }\n if (context.reader.exists(facts.accessor.file)) {\n const code = context.file(facts.accessor.file).code;\n if (!new RegExp(`\\\\bexport\\\\s+(?:function|const)\\\\s+${escapeRegExp(facts.accessor.name)}\\\\b`).test(code)) {\n findings.push({ file: facts.accessor.file, detail: `the accessor no longer exports ${facts.accessor.name}` });\n }\n }\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Banned auth calls: a call the auth surfaces must never make.\n\nexport interface BannedAuthCallFacts {\n /** The folders and files that make up the auth surfaces. */\n surfaces: readonly string[];\n /** Each banned call and why it is banned. */\n banned: ReadonlyArray<{ name: string; why: string }>;\n /** A long-lived auth surface the scan must reach. */\n anchor: string;\n}\n\nexport const bannedAuthCallGuard: GenericGuardDefinition<BannedAuthCallFacts> = {\n id: 'bannedAuthCalls',\n absentWhen: 'the app has no signed-in users',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.surfaces, 'surfaces', problems);\n if (!Array.isArray(facts?.banned) || !facts.banned.length) problems.push('banned is missing or empty');\n else for (const b of facts.banned) {\n textProblem(b?.name, 'a banned call', problems);\n textProblem(b?.why, `banned call ${String(b?.name)}'s why`, problems);\n }\n textProblem(facts?.anchor, 'anchor', problems);\n if (typeof facts?.anchor === 'string' && Array.isArray(facts?.surfaces) && !facts.surfaces.some((s) => isUnder(facts.anchor, s))) {\n problems.push(`the anchor ${facts.anchor} is not inside any surface`);\n }\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'the auth surfaces never name a banned auth call',\n description:\n `No file under ${facts.surfaces.join(', ')} imports or calls ` +\n facts.banned.map((b) => `\\`${b.name}\\` (${b.why})`).join('; ') +\n '. The symbol must not be reachable from these modules at all.',\n run(context) {\n const findings: Finding[] = [];\n const files = context.files(APP_CODE).filter((f) => facts.surfaces.some((s) => isUnder(f.path, s)));\n if (!files.some((f) => f.path === facts.anchor)) findings.push({ file: facts.anchor, detail: 'the anchor surface was not reached (gone, or outside the surfaces)' });\n for (const file of files) {\n for (const { name, why } of facts.banned) {\n const re = new RegExp(`\\\\b${escapeRegExp(name)}\\\\b`, 'g');\n for (let m = re.exec(file.code); m; m = re.exec(file.code)) {\n findings.push({ file: file.path, line: file.lineOf(m.index), detail: `names ${name}: ${why}` });\n }\n }\n }\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Auth failure capture: every source calling a Firebase Auth operation that can fail reports it.\n\nexport interface AuthFailureCaptureFacts {\n /** The function every auth failure is reported through. */\n reporter: string;\n /** Sources that leave the report to the code that catches their failure, each with why and the file that reports it. */\n reportedElsewhere: ReadonlyArray<{ path: string; why: string; reportedBy: string }>;\n}\n\n/** The Firebase Auth operations that reach the service and can fail. */\nconst FAILING_AUTH_OPERATION =\n /^(?:createUserWithEmailAndPassword|signInWith\\w+|signOut|sendPasswordResetEmail|confirmPasswordReset|verifyPasswordResetCode|checkActionCode|applyActionCode|sendEmailVerification|reauthenticateWith\\w+|updatePassword|updateEmail|verifyBeforeUpdateEmail|linkWith\\w+|deleteUser)$/;\n\n/** The failing operations a source imports as values from the Firebase Auth SDK. */\nexport function failingAuthImports(file: FileView): string[] {\n const names: string[] = [];\n for (const site of moduleImports(file.sourceFile, ['import'])) {\n if (site.typeOnly || site.spec !== 'firebase/auth') continue;\n for (const { imported, typeOnly } of site.named) if (!typeOnly && FAILING_AUTH_OPERATION.test(imported)) names.push(imported);\n }\n return names;\n}\n\nexport const authFailureCaptureGuard: GenericGuardDefinition<AuthFailureCaptureFacts> = {\n id: 'authFailureCapture',\n absentWhen: 'the app has no signed-in users',\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.reporter, 'reporter', problems);\n reviewedProblems(facts?.reportedElsewhere, 'reportedElsewhere', problems);\n for (const e of Array.isArray(facts?.reportedElsewhere) ? facts.reportedElsewhere : []) {\n if (e && (typeof e.reportedBy !== 'string' || !e.reportedBy.trim())) {\n problems.push(`reportedElsewhere entry ${e.path} names no reportedBy file (the file that reports its failures)`);\n }\n }\n return problems;\n },\n build(facts) {\n const reports = new RegExp(`\\\\b${escapeRegExp(facts.reporter)}\\\\s*\\\\(`);\n return [\n {\n title: 'every Firebase Auth failure reaches monitoring',\n description:\n `A source that calls a Firebase Auth operation that can fail reports its failure through \\`${facts.reporter}\\`; ` +\n 'a catch that only shows a message leaves a broken sign-up or sign-in invisible to monitoring. A source that ' +\n 'never catches the failure itself is a reviewed entry naming who reports for it; an entry that no longer calls ' +\n 'a failing operation, now reports itself, or whose reporter no longer reports is stale.',\n run(context) {\n const findings: Finding[] = [];\n const callers = context.files(APP_CODE).map((f) => ({ file: f, ops: failingAuthImports(f) })).filter((c) => c.ops.length);\n if (!callers.length) findings.push({ file: '(app)', detail: 'no source imports a failing Firebase Auth operation — the scan found no auth surface' });\n const reviewed = new Map(facts.reportedElsewhere.map((e) => [e.path, e]));\n for (const { file, ops } of callers) {\n if (!reports.test(file.code) && !reviewed.has(file.path)) findings.push({ file: file.path, detail: `calls ${ops.join(', ')} and never reports a failure` });\n }\n for (const entry of facts.reportedElsewhere) {\n const caller = callers.find((c) => c.file.path === entry.path);\n if (!caller) findings.push({ file: entry.path, detail: 'stale entry: it no longer calls a failing auth operation' });\n else if (reports.test(caller.file.code)) findings.push({ file: entry.path, detail: 'stale entry: it reports its own failures now' });\n if (!context.reader.exists(entry.reportedBy)) findings.push({ file: entry.reportedBy, detail: `the reporter named for ${entry.path} no longer exists` });\n else if (!reports.test(context.file(entry.reportedBy).code)) findings.push({ file: entry.reportedBy, detail: `the reporter named for ${entry.path} no longer reports` });\n }\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Sign-out liveness: the \"still signed in\" check has one owner.\n\nexport interface SignOutLivenessFacts {\n /** The module that owns the liveness check. */\n owner: string;\n /** The names the owner exports for it. */\n ownerExports: readonly string[];\n /** The function that returns the client auth instance. */\n authAccessor: string;\n}\n\nexport const signOutLivenessGuard: GenericGuardDefinition<SignOutLivenessFacts> = {\n id: 'signOutLiveness',\n absentWhen: 'the app has no signed-in users',\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.owner, 'owner', problems);\n namesProblem(facts?.ownerExports, 'ownerExports', problems);\n textProblem(facts?.authAccessor, 'authAccessor', problems);\n return problems;\n },\n build(facts) {\n const redeclared = new RegExp(`\\\\b${DECLARATION_KEYWORDS}\\\\s+(?:${facts.ownerExports.map(escapeRegExp).join('|')})\\\\b`, 'g');\n const negatedSkip = new RegExp(`!\\\\s*${escapeRegExp(facts.authAccessor)}\\\\(\\\\)\\\\s*\\\\??\\\\.\\\\s*currentUser`, 'g');\n return [\n {\n title: 'the signed-in check before an awaited call has one owner',\n description:\n `A check that the user is still signed in, made across an awaited hop before a call, is ${facts.owner}'s ` +\n `(${facts.ownerExports.join(', ')}). Nothing else re-declares those names or hand-rolls a negated ` +\n `\\`${facts.authAccessor}().currentUser\\` skip guard: import the owner.`,\n run(context) {\n const findings: Finding[] = [];\n for (const file of context.files(APP_CODE)) {\n if (file.path === facts.owner) continue;\n for (const re of [redeclared, negatedSkip]) {\n re.lastIndex = 0;\n for (let m = re.exec(file.code); m; m = re.exec(file.code)) {\n findings.push({ file: file.path, line: file.lineOf(m.index), detail: re === redeclared ? `re-declares ${m[0].split(/\\s+/).pop()}` : 'hand-rolls a negated currentUser skip guard' });\n }\n }\n }\n if (!context.reader.exists(facts.owner)) findings.push({ file: facts.owner, detail: 'the owner no longer exists' });\n else {\n const code = context.file(facts.owner).code;\n for (const name of facts.ownerExports) if (!declares(code, name)) findings.push({ file: facts.owner, detail: `the owner no longer declares ${name}` });\n }\n return findings;\n },\n },\n ];\n },\n};\n\n// ---------------------------------------------------------------------------------------------\n// Editor permission gate: an editor holding typed input is never mounted under a permission read.\n\nexport interface EditorPermissionGateFacts {\n /** The hook an editor calls to guard its unsaved input: a file calling it holds an editor. */\n editorMarker: string;\n /** The element the editor mounts in. */\n editorElement: string;\n /** Permission reads: identifiers starting with this prefix and a capital letter. */\n permissionNamePrefix: string;\n /** Permission reads: calls to these functions (declare [] when none). */\n permissionCalls: readonly string[];\n}\n\n/** Each editor element with an ancestor `{<permission read> && …}`. */\nexport function permissionGatedEditors(sf: ts.SourceFile, facts: Omit<EditorPermissionGateFacts, 'editorMarker'>): ts.Node[] {\n const prefix = new RegExp(`^${escapeRegExp(facts.permissionNamePrefix)}[A-Z]`);\n const readsPermission = (expr: ts.Expression) => {\n let found = false;\n const visit = (node: ts.Node) => {\n if (ts.isIdentifier(node) && prefix.test(node.text)) found = true;\n if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && facts.permissionCalls.includes(node.expression.text)) found = true;\n ts.forEachChild(node, visit);\n };\n visit(expr);\n return found;\n };\n const out: ts.Node[] = [];\n const visit = (node: ts.Node) => {\n if ((ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) && node.tagName.getText(sf) === facts.editorElement) {\n for (let p: ts.Node | undefined = node.parent; p; p = p.parent) {\n if (\n ts.isJsxExpression(p) &&\n p.expression &&\n ts.isBinaryExpression(p.expression) &&\n p.expression.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken &&\n readsPermission(p.expression.left)\n ) {\n out.push(node);\n break;\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return out;\n}\n\nexport const editorPermissionGateGuard: GenericGuardDefinition<EditorPermissionGateFacts> = {\n id: 'editorPermissionGate',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.editorMarker, 'editorMarker', problems);\n textProblem(facts?.editorElement, 'editorElement', problems);\n textProblem(facts?.permissionNamePrefix, 'permissionNamePrefix', problems);\n namesProblem(facts?.permissionCalls, 'permissionCalls', problems, { nonEmpty: false });\n return problems;\n },\n build(facts): Guard[] {\n return [\n {\n title: 'an editor holding typed input is never mounted under a permission gate',\n description:\n `A component that guards its unsaved input (\\`${facts.editorMarker}\\`) gates only the control that opens its ` +\n `editor on a permission; its \\`<${facts.editorElement}>\\` stays mounted, so a permission read that changes or ` +\n 'fails while it is open can never unmount it and drop what was typed. Gate the trigger, and key the editor to ' +\n 'the account that opened it.',\n run(context) {\n const findings: Finding[] = [];\n const marker = new RegExp(`\\\\b${escapeRegExp(facts.editorMarker)}\\\\s*\\\\(`);\n const editors = context.files(APP_CODE).filter((f) => marker.test(f.code));\n if (!editors.length) findings.push({ file: '(app)', detail: `no component calls ${facts.editorMarker} — the scan found no editor to check` });\n for (const file of editors) {\n for (const node of permissionGatedEditors(file.sourceFile, facts)) {\n findings.push({ file: file.path, line: file.lineOf(node.getStart(file.sourceFile)), detail: `<${facts.editorElement}> mounted under a permission gate` });\n }\n }\n return findings;\n },\n },\n ];\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/modules/frontend-reads/cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/modules/frontend-reads/cache.ts"],"names":[],"mappings":"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"}
@@ -467,7 +467,11 @@ export const domainEventRegistryGuard = {
467
467
  description: `Every variant of the core's domain-event schema has an entry in the registry in ${facts.registry.path}, and the entry answers, ` +
468
468
  'for every shape of its ids (each optional id present and absent), a list of invalidations that are each an exact or prefix ' +
469
469
  'target with a non-empty key, or a predicate with a description and a matcher.',
470
- async run() {
470
+ async run(context) {
471
+ // The loaded registry is judged, but the file the facts name must be the one it comes from.
472
+ if (!context.reader.exists(facts.registry.path))
473
+ return [{ file: facts.registry.path, detail: 'the registry file does not exist' }];
474
+ context.file(facts.registry.path);
471
475
  const registry = (await facts.registry.load()) ?? {};
472
476
  const schema = (await facts.eventSchema());
473
477
  const variants = (schema?.options ?? []);
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/modules/frontend-reads/cache.ts"],"names":[],"mappings":"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","sourcesContent":["// What may touch the query cache, and how: invalidation only through the domain-event registry,\n// aimed at keys a live query reads and never at an infinite list; an infinite list never reloaded\n// by an action; a whole-cache drop only by the session-retirement owner; and a registry whose every\n// event is produced, well formed, and awaited.\n\nimport ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../config.js';\nimport type { Finding, Guard, GuardContext } from '../../guard.js';\nimport type { FileView } from '../../reader/view.js';\nimport { identifierProblem, loaderProblem, pathProblem, reviewedProblems, type Loader } from '../../support/facts.js';\nimport { escapeRegExp } from '../../support/text.js';\nimport {\n APP_CODE,\n alternation,\n callSpan,\n collapse,\n familyOf,\n filesUnder,\n identifierListProblem,\n infiniteKeyFamilies,\n isPrefix,\n keyModuleProblem,\n loadKeyObjects,\n pathListProblem,\n reachesInfinite,\n requiredFile,\n reviewedCallProblem,\n sampleKey,\n type KeyBuilders,\n type KeyModuleFacts,\n type ReviewedCall,\n} from './shared.js';\n\n/** query-core's registry factory and the two invalidation builders a registry entry uses. */\nconst REGISTRY_FACTORY = 'createDomainEventInvalidator';\nconst EXACT = 'exact';\n\n/** The registry: where it is. */\nexport interface RegistryFacts {\n path: string;\n}\n\n/** The object literal the registry module hands to query-core's registry factory, as code. */\nexport function registryObjectCode(file: FileView): { name: string; code: string } | null {\n const sf = file.sourceFile;\n let name: string | null = null;\n const find = (node: ts.Node) => {\n if (!name && ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === REGISTRY_FACTORY && node.arguments[0] && ts.isIdentifier(node.arguments[0])) {\n name = node.arguments[0].text;\n }\n ts.forEachChild(node, find);\n };\n find(sf);\n if (!name) return null;\n let found: { name: string; code: string } | null = null;\n const visit = (node: ts.Node) => {\n if (!found && ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === name && node.initializer) {\n found = { name: name!, code: file.code.slice(node.initializer.getStart(sf), node.initializer.getEnd()) };\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return found;\n}\n\nconst keyRefPattern = (objects: readonly string[]) => new RegExp(`\\\\b(${alternation(objects)})\\\\.(\\\\w+)`, 'g');\n\n// =============================================================================================\n// Cache invalidation only through the registry; the registry's targets are read, and never an infinite list.\n// =============================================================================================\n\nexport interface CacheInvalidationFacts {\n registry: RegistryFacts;\n keyModule: KeyModuleFacts;\n /** The trees whose `queryKey:` sites are the app's live reads (hooks, components, pages). */\n readTrees: readonly string[];\n /** The suffix the key module names a family helper with (`listPrefix()` → `Prefix`). */\n familySuffix: string;\n}\n\n/** What the registry rule leaves to the other cache owners: the session-retirement owner, and a person's own refreshes. */\ninterface OwnedElsewhere {\n sessionOwner: string;\n memberRefreshes: readonly ReviewedCall[];\n}\n\nconst CLEAR_CALL = /\\.\\s*(invalidateQueries|removeQueries|resetQueries)(\\s*\\()/g;\nconst CACHE_WRITE_CALL =\n /\\b(refetchQueries|resetQueries|cancelQueries|setQueryData|setQueriesData|getQueryData|getQueriesData|invalidateQueries|removeQueries|ensureQueryData|prefetchQuery)\\b/;\n\n/** Every invalidate / remove / reset call in a file, as its collapsed text from the method name on. */\nexport function clearCalls(file: FileView): Array<{ index: number; call: string }> {\n return [...file.code.matchAll(CLEAR_CALL)].map((m) => {\n const name = (m.index ?? 0) + m[0].indexOf(m[1]);\n const open = (m.index ?? 0) + m[0].length - 1;\n return { index: name, call: collapse(callSpan(file.code, name, open)) };\n });\n}\n\n/** Key families some live query reads: a `queryKey` built from a key method outside a cache call, or a key object handed whole. */\nexport function readKeyFamilies(files: ReadonlyArray<{ code: string }>, objects: readonly string[], familySuffix: string): Set<string> {\n const read = new Set<string>();\n const names = alternation(objects);\n for (const { code } of files) {\n for (const line of code.split('\\n')) {\n if (CACHE_WRITE_CALL.test(line)) continue;\n for (const m of line.matchAll(new RegExp(`\\\\bqueryKey\\\\s*[:=]\\\\s*(${names})\\\\.(\\\\w+)`, 'g'))) read.add(familyOf(`${m[1]}.${m[2]}`, familySuffix));\n for (const m of line.matchAll(new RegExp(`[\\\\w$]+\\\\s*:\\\\s*(${names})\\\\b(?![\\\\w$]|\\\\s*\\\\.)`, 'g'))) read.add(`${m[1]}.*`);\n }\n }\n return read;\n}\n\n/** The argument count of the call whose `(` is at `open`, or null when there is no call there. */\nfunction argCountAt(code: string, open: number): number | null {\n if (code[open] !== '(') return null;\n let depth = 0;\n let count = 0;\n let sawToken = false;\n for (let i = open; i < code.length; i += 1) {\n const ch = code[i];\n if ('([{'.includes(ch)) {\n depth += 1;\n if (depth > 1) sawToken = true;\n } else if (')]}'.includes(ch)) {\n depth -= 1;\n if (depth === 0) return sawToken ? count + 1 : 0;\n } else if (ch === ',' && depth === 1) count += 1;\n else if (depth >= 1 && !/\\s/.test(ch)) sawToken = true;\n }\n return null;\n}\n\n/** Each key method → the argument counts the app's live reads build it with. */\nexport function readArgCounts(files: ReadonlyArray<{ code: string }>, objects: readonly string[]): Map<string, Set<number>> {\n const counts = new Map<string, Set<number>>();\n const re = new RegExp(`\\\\bqueryKey\\\\s*[:=]\\\\s*(${alternation(objects)})\\\\.(\\\\w+)\\\\(`, 'g');\n for (const { code } of files) {\n for (const line of code.split('\\n')) {\n if (CACHE_WRITE_CALL.test(line)) continue;\n for (const m of line.matchAll(re)) {\n const n = argCountAt(line, (m.index ?? 0) + m[0].length - 1);\n if (n === null) continue;\n const ref = `${m[1]}.${m[2]}`;\n counts.set(ref, (counts.get(ref) ?? new Set()).add(n));\n }\n }\n }\n return counts;\n}\n\n/** Registry targets that miss: unread, an exact on a family, an exact shaped unlike every read, or one reaching an infinite list. */\nexport function registryTargetProblems(input: {\n registryCode: string;\n reads: ReadonlyArray<{ code: string }>;\n builders: KeyBuilders;\n familySuffix: string;\n}): string[] {\n const { registryCode, reads, builders, familySuffix } = input;\n const objects = Object.keys(builders);\n const refs = [...new Set([...registryCode.matchAll(keyRefPattern(objects))].map((m) => `${m[1]}.${m[2]}`))];\n const read = readKeyFamilies(reads, objects, familySuffix);\n const readKeys = [...read].map((f) => sampleKey(f, builders)).filter((k): k is unknown[] => k !== null);\n const problems: string[] = [];\n for (const ref of refs) {\n if (read.has(familyOf(ref, familySuffix)) || read.has(`${ref.split('.')[0]}.*`)) continue;\n const key = sampleKey(ref, builders);\n if (key === null || !readKeys.some((readKey) => isPrefix(key, readKey))) problems.push(`${ref}: no live query reads this key`);\n }\n const counts = readArgCounts(reads, objects);\n const exactRe = new RegExp(`\\\\b${EXACT}\\\\(\\\\s*(${alternation(objects)})\\\\.(\\\\w+)`, 'g');\n const shaped = new Set<string>();\n for (const m of registryCode.matchAll(exactRe)) {\n const ref = `${m[1]}.${m[2]}`;\n if (shaped.has(ref)) continue;\n if (m[2] === 'all' || (m[2].endsWith(familySuffix) && m[2] !== familySuffix)) {\n shaped.add(ref);\n problems.push(`${ref}: an exact target on a key family (only a prefix target reaches a family)`);\n continue;\n }\n const n = argCountAt(registryCode, (m.index ?? 0) + m[0].length);\n const readCounts = counts.get(ref);\n if (n !== null && readCounts && !readCounts.has(n)) {\n shaped.add(ref);\n problems.push(`${ref}: an exact target built with ${n} argument(s), which no live read builds`);\n }\n }\n const infinite = infiniteKeyFamilies(reads, objects, familySuffix);\n for (const ref of refs) if (reachesInfinite(ref, infinite, builders, familySuffix)) problems.push(`${ref}: reaches an infinite list`);\n return problems;\n}\n\nfunction registryProblem(value: unknown, problems: string[]): void {\n const facts = value as RegistryFacts | undefined;\n if (!facts || typeof facts !== 'object') problems.push('registry is missing');\n else pathProblem(facts.path, 'registry.path', problems);\n}\n\nconst cacheInvalidationProblems = (facts: CacheInvalidationFacts) => {\n const problems: string[] = [];\n registryProblem(facts?.registry, problems);\n keyModuleProblem(facts?.keyModule, problems);\n pathListProblem(facts?.readTrees, 'readTrees', problems);\n identifierProblem(facts?.familySuffix, 'familySuffix', problems);\n return problems;\n};\n\nconst cacheInvalidationGuards = (facts: CacheInvalidationFacts, owned: OwnedElsewhere): Guard[] => [\n {\n title: 'saved reads are refreshed, removed, or reset only through the domain-event registry',\n description:\n `${facts.registry.path} — the object it hands to query-core's ${REGISTRY_FACTORY} — is the one place that turns something that ` +\n 'happened into what the cache does: refresh, remove, or reset. No other file calls invalidateQueries, removeQueries, or ' +\n 'resetQueries: emit the domain event instead, and patch an infinite list in place. The only other owners are the session-' +\n `retirement owner (${owned.sessionOwner}) and a person's own refresh, declared once beside the list-reload rule.`,\n run(context) {\n const { file: registry, findings } = requiredFile(context, facts.registry.path, 'the domain-event registry');\n if (registry && !registryObjectCode(registry)) findings.push({ file: registry.path, detail: `no registry object handed to ${REGISTRY_FACTORY}` });\n const refreshes = new Set(owned.memberRefreshes.map((r) => `${r.path} ${r.call}`));\n for (const file of context.files(APP_CODE)) {\n if (file.path === facts.registry.path || file.path === owned.sessionOwner) continue;\n for (const { index, call } of clearCalls(file)) {\n if (refreshes.has(`${file.path} ${call}`)) continue;\n findings.push({ file: file.path, line: file.lineOf(index), detail: `outside the registry: ${call.slice(0, 120)}` });\n }\n }\n return findings;\n },\n },\n {\n title: 'every registry cache target is a key a live query reads, and never an infinite list',\n description:\n `Every key the registry in ${facts.registry.path} writes is reached by a live query's key (a queryKey built from the same key ` +\n `method in ${facts.readTrees.join(', ')}, or a key object handed whole to a reader); an exact target names a leaf the reads build ` +\n `with the same arguments, never a family (all, or a …${facts.familySuffix} helper); and no target reaches an infinite list — named, ` +\n \"through its family helper, or through its scope. A write aimed at a key nothing reads is a silent no-op, and invalidating an \" +\n 'infinite list re-runs every loaded page.',\n timeoutMs: 120_000,\n async run(context: GuardContext): Promise<Finding[]> {\n const { file: registry, findings } = requiredFile(context, facts.registry.path, 'the domain-event registry');\n if (!registry) return findings;\n const object = registryObjectCode(registry);\n if (!object) return [{ file: registry.path, detail: `no registry object handed to ${REGISTRY_FACTORY}` }];\n const builders = await loadKeyObjects(facts.keyModule);\n const { files, findings: missing } = filesUnder(context, facts.readTrees);\n findings.push(...missing);\n for (const detail of registryTargetProblems({ registryCode: object.code, reads: files, builders, familySuffix: facts.familySuffix })) {\n findings.push({ file: registry.path, detail });\n }\n return findings;\n },\n },\n];\n\n// =============================================================================================\n// No action-driven reload of an infinite list.\n// =============================================================================================\n\nexport interface ListResetFacts {\n keyModule: KeyModuleFacts;\n familySuffix: string;\n /** The app predicate that is true for a query holding loaded pages; a reload filtered by its negation reloads no shown list. */\n loadedPagesPredicate: string;\n /** A person's own refreshes (pull-to-refresh, a Refresh button): each call site with its why. */\n memberRefreshes: readonly ReviewedCall[];\n /** Hooks that run a member's own refresh, each handed only to its refresh control on the named prop; [] for none. */\n refreshHandoffs: ReadonlyArray<{ hook: string; control: string; prop: string }>;\n}\n\nconst RELOAD_CALL = /\\b(resetQueries|refetchQueries|removeQueries)\\s*\\(/g;\nconst PATCH_CALL = /\\b(setQueryData|setQueriesData)\\s*(?:<[^>]*>)?\\s*\\(/g;\nconst FIRST_PAGE_TRIM = /\\bpages\\.slice\\(\\s*0\\s*,\\s*1\\s*\\)|\\bpageParams\\.slice\\(\\s*0\\s*,\\s*1\\s*\\)|\\bpages\\s*:\\s*\\[\\s*[\\w.?]+\\.pages\\[0\\]\\s*\\]/;\n\n/** The key refs a call targets: its key method, or every one a constant map it indexes holds; null when unresolved. */\nfunction targetRefs(call: string, code: string, objects: readonly string[]): string[] | null {\n const names = alternation(objects);\n const direct = call.match(new RegExp(`\\\\bqueryKey\\\\s*:\\\\s*(${names})\\\\.(\\\\w+)`));\n if (direct) return [`${direct[1]}.${direct[2]}`];\n const indexed = call.match(/\\bqueryKey\\s*:\\s*([A-Za-z_]\\w*)\\[/);\n if (!indexed) return null;\n const decl = code.match(new RegExp(`\\\\bconst \\\\s*${escapeRegExp(indexed[1])}\\\\b[^=]*=\\\\s*\\\\{`));\n if (!decl) return null;\n const open = (decl.index ?? 0) + decl[0].length - 1;\n const refs = [...callSpan(code, open, open).matchAll(keyRefPattern(objects))].map((m) => `${m[1]}.${m[2]}`);\n return refs.length ? refs : null;\n}\n\n/** Every call that reloads or trims an infinite list, outside the reviewed reloads. */\nexport function listReloads(\n files: readonly FileView[],\n builders: KeyBuilders,\n facts: Pick<ListResetFacts, 'familySuffix' | 'loadedPagesPredicate' | 'memberRefreshes'>,\n sessionOwner?: string,\n) {\n const objects = Object.keys(builders);\n const infinite = infiniteKeyFamilies(files, objects, facts.familySuffix);\n const pinned = new Set(facts.memberRefreshes.map((r) => `${r.path} ${r.call}`));\n const excluded = new RegExp(`!${escapeRegExp(facts.loadedPagesPredicate)}\\\\(\\\\s*query\\\\s*\\\\)`);\n const found: Finding[] = [];\n const present = new Set<string>();\n for (const file of files) {\n if (file.path === sessionOwner) continue;\n const code = file.code;\n for (const m of code.matchAll(RELOAD_CALL)) {\n const call = collapse(callSpan(code, m.index ?? 0, (m.index ?? 0) + m[0].length - 1));\n present.add(`${file.path} ${call}`);\n if (pinned.has(`${file.path} ${call}`)) continue;\n const refs = targetRefs(call, code, objects);\n const reloads = refs ? refs.some((ref) => reachesInfinite(ref, infinite, builders, facts.familySuffix)) : !excluded.test(call);\n if (reloads) found.push({ file: file.path, line: file.lineOf(m.index ?? 0), detail: `${refs ? 'reloads an infinite list' : 'reloads queries its key does not name'}: ${call.slice(0, 120)}` });\n }\n for (const m of code.matchAll(PATCH_CALL)) {\n const call = callSpan(code, m.index ?? 0, (m.index ?? 0) + m[0].length - 1);\n if (FIRST_PAGE_TRIM.test(call)) found.push({ file: file.path, line: file.lineOf(m.index ?? 0), detail: `trims a list to its first page: ${collapse(call).slice(0, 120)}` });\n }\n }\n for (const r of facts.memberRefreshes) if (!present.has(`${r.path} ${r.call}`)) found.push({ file: r.path, detail: `stale member refresh: ${r.call} is no longer there` });\n return { infinite, findings: found };\n}\n\n/** Each refresh hook's result used anywhere but on its refresh control's prop, and each hook no file calls. */\nexport function refreshHandoffMisuses(files: readonly FileView[], handoffs: ListResetFacts['refreshHandoffs']): Finding[] {\n const findings: Finding[] = [];\n for (const { hook, control, prop } of handoffs) {\n let callers = 0;\n for (const file of files) {\n for (const m of file.code.matchAll(new RegExp(`const\\\\s+(\\\\w+)\\\\s*=\\\\s*${escapeRegExp(hook)}\\\\(`, 'g'))) {\n callers += 1;\n const name = m[1];\n const uses = [...file.code.matchAll(new RegExp(`\\\\b${name}\\\\b`, 'g'))].length - 1;\n const handed = [...file.code.matchAll(new RegExp(`<${escapeRegExp(control)}[^>]*${escapeRegExp(prop)}=\\\\{${name}\\\\}`, 'g'))].length;\n if (uses !== handed) findings.push({ file: file.path, line: file.lineOf(m.index ?? 0), detail: `${hook}()'s refresh is used other than as <${control} ${prop}>` });\n }\n }\n if (!callers) findings.push({ file: '(refreshHandoffs)', detail: `stale entry: nothing calls ${hook}` });\n }\n return findings;\n}\n\nconst listResetProblems = (facts: ListResetFacts) => {\n const problems: string[] = [];\n keyModuleProblem(facts?.keyModule, problems);\n identifierProblem(facts?.familySuffix, 'familySuffix', problems);\n identifierProblem(facts?.loadedPagesPredicate, 'loadedPagesPredicate', problems);\n reviewedCallProblem(facts?.memberRefreshes, 'memberRefreshes', problems);\n if (!Array.isArray(facts?.refreshHandoffs)) problems.push('refreshHandoffs is missing (declare [] when there is none)');\n else\n facts.refreshHandoffs.forEach((h, i) => {\n identifierProblem(h?.hook, `refreshHandoffs[${i}].hook`, problems);\n identifierProblem(h?.control, `refreshHandoffs[${i}].control`, problems);\n identifierProblem(h?.prop, `refreshHandoffs[${i}].prop`, problems);\n });\n return problems;\n};\n\nconst listResetGuards = (facts: ListResetFacts, sessionOwner: string): Guard[] => [\n {\n title: 'an action never reloads an infinite list',\n description:\n \"An action's change is placed, moved, or patched in place in an infinite list; no resetQueries / refetchQueries / removeQueries \" +\n `whose key reaches one (directly, through its family helper or scope, or through a constant map of keys), none whose key cannot ` +\n `be resolved unless its predicate excludes every query holding loaded pages (!${facts.loadedPagesPredicate}(query)), and no cache ` +\n \"write that trims a list to its first page. A person's own refresh is declared with its why, and a refresh hook's result is only \" +\n 'ever handed to its refresh control.',\n timeoutMs: 120_000,\n async run(context) {\n const builders = await loadKeyObjects(facts.keyModule);\n const files = context.files(APP_CODE);\n const { infinite, findings } = listReloads(files, builders, facts, sessionOwner);\n if (!infinite.size) findings.push({ file: facts.keyModule.path, detail: 'no infinite list found in the app, so the guard checks nothing' });\n findings.push(...refreshHandoffMisuses(files, facts.refreshHandoffs));\n return findings;\n },\n },\n];\n\n// =============================================================================================\n// An unscoped cancel or a whole-cache clear only by session retirement.\n// =============================================================================================\n\nexport interface SessionRetirementFacts {\n /** The session-retirement owner. */\n owner: string;\n /** Retirements beyond a session's end that the owner runs by predicate (a member leaving a group), each with its why; [] for none. */\n predicateRetirements: ReadonlyArray<{ trigger: string; why: string }>;\n}\n\nconst WHOLE_CACHE_DROP = [\n /\\bcancelQueries\\(\\s*\\)/g,\n /\\bcancelQueries\\(\\s*undefined\\b/g,\n /\\bcancelQueries\\(\\s*\\{(?![^}]*\\bqueryKey\\b)/g,\n /\\bget(?:Query|Mutation)Cache\\(\\)\\s*\\.clear\\(/g,\n /\\b\\w*[cC]lient\\s*\\.clear\\(\\s*\\)/g,\n];\n\nexport function wholeCacheDrops(file: FileView): Array<{ index: number; text: string }> {\n return WHOLE_CACHE_DROP.flatMap((re) => [...file.code.matchAll(re)].map((m) => ({ index: m.index ?? 0, text: m[0] }))).sort((a, b) => a.index - b.index);\n}\n\nconst sessionRetirementPart = {\n factProblems(facts: SessionRetirementFacts) {\n const problems: string[] = [];\n pathProblem(facts?.owner, 'owner', problems);\n reviewedProblems(facts?.predicateRetirements, 'predicateRetirements', problems, { key: 'trigger' });\n return problems;\n },\n build: (facts: SessionRetirementFacts): Guard[] => [\n {\n title: 'an unscoped cancel or a whole-cache clear runs only in the session-retirement owner',\n description:\n `A cancelQueries with no key (bare, or selected by a predicate) and a query or mutation cache clear drop reads the call site ` +\n `cannot name, so only ${facts.owner} runs them: when a session ends it cancels every query and clears the query cache` +\n (facts.predicateRetirements.length ? `, and it cancels by predicate for ${facts.predicateRetirements.map((r) => r.trigger).join('; ')}` : '') +\n '. Everywhere else a cancel names its key, and nothing clears a cache.',\n run(context) {\n const { file: owner, findings } = requiredFile(context, facts.owner, 'the session-retirement owner');\n for (const file of context.files(APP_CODE)) {\n if (file.path === facts.owner) continue;\n for (const drop of wholeCacheDrops(file)) findings.push({ file: file.path, line: file.lineOf(drop.index), detail: `outside the session-retirement owner: ${drop.text}` });\n }\n if (owner) {\n if (!/\\bcancelQueries\\(\\s*\\)/.test(owner.code)) findings.push({ file: owner.path, detail: 'the owner no longer cancels every query when a session ends' });\n if (!/getQueryCache\\(\\)\\s*\\.clear\\(/.test(owner.code)) findings.push({ file: owner.path, detail: 'the owner no longer clears the query cache when a session ends' });\n const byPredicate = [...owner.code.matchAll(/\\bcancelQueries\\(\\s*\\{\\s*predicate\\s*:/g)].length;\n if (byPredicate !== facts.predicateRetirements.length) {\n findings.push({ file: owner.path, detail: `the owner cancels by predicate ${byPredicate} time(s); ${facts.predicateRetirements.length} predicate retirement(s) are reviewed` });\n }\n }\n return findings;\n },\n },\n ],\n};\n\n// =============================================================================================\n// The domain-event registry: every event produced, every variant registered and well formed, every\n// notification handed on.\n// =============================================================================================\n\nexport interface DomainEventRegistryFacts {\n registry: RegistryFacts & {\n /** A loader of the registry object itself (event type → invalidation builder). */\n load: Loader<Record<string, unknown>>;\n };\n /** A loader of the core's domain-event schema: a discriminated union on `type`, each variant carrying an `ids` object. */\n eventSchema: Loader<unknown>;\n /** The app's functions that dispatch a domain event and return the refresh's promise. */\n notifiers: readonly string[];\n}\n\ntype ZodLike = { def?: any; _def?: any; shape?: Record<string, ZodLike>; options?: unknown[]; value?: unknown };\nconst defOf = (field: ZodLike) => field?.def ?? field?._def ?? {};\nconst kindOf = (field: ZodLike): 'optional' | 'nullable' | 'enum' | 'required' => {\n const type = defOf(field).type;\n return type === 'optional' || type === 'nullable' || type === 'enum' ? type : 'required';\n};\n\n/** Synthetic `ids` for one variant: every field filled, then each optional field dropped in turn. */\nexport function syntheticIds(idsSchema: ZodLike): Array<Record<string, unknown>> {\n const baseline: Record<string, unknown> = {};\n const optional: string[] = [];\n for (const [key, field] of Object.entries(idsSchema?.shape ?? {})) {\n const kind = kindOf(field);\n if (kind === 'enum') baseline[key] = (field.options as unknown[])[0];\n else if (kind === 'optional') {\n optional.push(key);\n const inner = defOf(field).innerType as ZodLike;\n baseline[key] = kindOf(inner) === 'enum' ? (inner.options as unknown[])[0] : `test-${key}`;\n } else baseline[key] = `test-${key}`;\n }\n return [{ ...baseline }, ...optional.map((key) => Object.fromEntries(Object.entries(baseline).filter(([k]) => k !== key)))];\n}\n\n/** What a query-core registry entry may do to the reads it matches, and how a refresh refetches. */\nconst CACHE_ACTIONS: ReadonlySet<unknown> = new Set([undefined, 'refresh', 'remove', 'reset']);\nconst REFETCH_TYPES: ReadonlySet<unknown> = new Set([undefined, 'active', 'all', 'none']);\n\n/** Why a builder's answer is not a list of well-formed invalidations, or null. */\nexport function malformedInvalidations(answer: unknown): string | null {\n if (!Array.isArray(answer)) return 'does not answer a list of invalidations';\n for (const inv of answer as Array<Record<string, unknown>>) {\n if (inv?.kind === 'exact' || inv?.kind === 'prefix') {\n if (!Array.isArray(inv.queryKey) || !inv.queryKey.length) return `a ${inv.kind} invalidation with no key`;\n } else if (inv?.kind === 'predicate') {\n if (typeof inv.description !== 'string' || !inv.description || typeof inv.match !== 'function') return 'a predicate invalidation with no description or matcher';\n } else return `an invalidation of unknown kind ${String(inv?.kind)}`;\n if (!CACHE_ACTIONS.has(inv.action)) return `a ${inv.kind} invalidation with unknown action ${String(inv.action)}`;\n if (!REFETCH_TYPES.has(inv.refetchType)) return `a ${inv.kind} invalidation with unknown refetchType ${String(inv.refetchType)}`;\n if ((inv.action === 'remove' || inv.action === 'reset') && inv.refetchType !== undefined) {\n return `a ${inv.action} invalidation with a refetchType, which only a refresh takes`;\n }\n }\n return null;\n}\n\n/** Whether the call at `index` starts a statement, so its promise is dropped. */\nfunction startsStatement(code: string, index: number): boolean {\n const before = code.slice(0, index).trimEnd();\n return before.length === 0 || ';{})'.includes(before.charAt(before.length - 1));\n}\n\nexport function droppedNotifications(file: FileView, notifiers: readonly string[]): Array<{ index: number; name: string }> {\n const hits: Array<{ index: number; name: string }> = [];\n for (const m of file.code.matchAll(new RegExp(`\\\\b(${alternation(notifiers)})\\\\(`, 'g'))) {\n const index = m.index ?? 0;\n if (/function\\s+$/.test(file.code.slice(0, index))) continue;\n if (startsStatement(file.code, index)) hits.push({ index, name: m[1] });\n }\n return hits;\n}\n\nexport const domainEventRegistryGuard: GenericGuardDefinition<DomainEventRegistryFacts> = {\n id: 'domainEventRegistry',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n registryProblem(facts?.registry, problems);\n loaderProblem(facts?.registry?.load, 'registry.load', problems);\n loaderProblem(facts?.eventSchema, 'eventSchema', problems);\n identifierListProblem(facts?.notifiers, 'notifiers', problems, { nonEmpty: true });\n return problems;\n },\n build: (facts) => [\n {\n title: 'every registered domain event has a producer in the app',\n description:\n `Every event type the registry in ${facts.registry.path} handles is emitted somewhere in the app's own code (its quoted type ` +\n \"outside the registry, in the client or functions tree); the core's schema holds every variant by construction, so it is no \" +\n 'evidence. Restore the producer, or delete the event from the core and the registry.',\n async run(context) {\n const registry = (await facts.registry.load()) ?? {};\n const findings: Finding[] = [];\n const haystack = context\n .files({ roots: ['app', 'functions'], optionalRoots: ['functions'], kinds: ['code'], tests: false })\n .filter((f) => f.path !== facts.registry.path)\n .map((f) => f.code)\n .join('\\n');\n const produced = (type: string) => haystack.includes(`'${type}'`) || haystack.includes(`\"${type}\"`);\n for (const type of Object.keys(registry)) if (!produced(type)) findings.push({ file: facts.registry.path, detail: `${type}: no producer in the app` });\n return findings;\n },\n },\n {\n title: \"every core domain-event variant has a registry entry with well-formed invalidations\",\n description:\n `Every variant of the core's domain-event schema has an entry in the registry in ${facts.registry.path}, and the entry answers, ` +\n 'for every shape of its ids (each optional id present and absent), a list of invalidations that are each an exact or prefix ' +\n 'target with a non-empty key, or a predicate with a description and a matcher.',\n async run() {\n const registry = (await facts.registry.load()) ?? {};\n const schema = (await facts.eventSchema()) as ZodLike;\n const variants = (schema?.options ?? []) as ZodLike[];\n if (!variants.length) return [{ file: '(eventSchema)', detail: 'the loader did not answer a discriminated union of variants' }];\n const findings: Finding[] = [];\n for (const variant of variants) {\n const type = String(variant.shape?.type?.value ?? '');\n if (!type) {\n findings.push({ file: '(eventSchema)', detail: 'a variant carries no literal type' });\n continue;\n }\n const build = registry[type];\n if (typeof build !== 'function') {\n findings.push({ file: facts.registry.path, detail: `${type}: no registry entry` });\n continue;\n }\n for (const ids of syntheticIds(variant.shape?.ids as ZodLike)) {\n let problem: string | null;\n try {\n problem = malformedInvalidations((build as (ids: unknown) => unknown)(ids));\n } catch (err) {\n problem = `throws for ids ${JSON.stringify(ids)}: ${(err as Error)?.message ?? err}`;\n }\n if (problem) findings.push({ file: facts.registry.path, detail: `${type}: ${problem}` });\n }\n }\n return findings;\n },\n },\n {\n title: 'every domain-event notification hands its refresh promise on',\n description:\n `A call to ${facts.notifiers.join(' / ')} returns the promise of the refresh it starts; a mutation returns or awaits it so it stays ` +\n 'pending until the refreshed data is on screen. A call in statement position drops it silently: return it, await it, pass it ' +\n 'on, or mark a deliberate fire-and-forget with void.',\n run(context) {\n const findings: Finding[] = [];\n let calls = 0;\n const callRe = new RegExp(`\\\\b(?:${alternation(facts.notifiers)})\\\\(`, 'g');\n for (const file of context.files(APP_CODE)) {\n calls += [...file.code.matchAll(callRe)].length;\n for (const hit of droppedNotifications(file, facts.notifiers)) {\n findings.push({ file: file.path, line: file.lineOf(hit.index), detail: `${hit.name}(…) in statement position drops its refresh` });\n }\n }\n if (!calls) findings.push({ file: '(notifiers)', detail: `nothing in the app calls ${facts.notifiers.join(' / ')}, so the guard checks nothing` });\n return findings;\n },\n },\n ],\n};\n\n/**\n * Every fact the query-cache owners need, declared once: the registry (the one place something that\n * happened changes saved reads), a person's own refreshes, and the session-retirement owner.\n */\nexport interface QueryCacheFacts extends CacheInvalidationFacts {\n loadedPagesPredicate: string;\n memberRefreshes: readonly ReviewedCall[];\n refreshHandoffs: ListResetFacts['refreshHandoffs'];\n sessionOwner: string;\n predicateRetirements: SessionRetirementFacts['predicateRetirements'];\n}\n\nconst listFacts = (f: QueryCacheFacts | undefined): ListResetFacts => ({\n keyModule: f?.keyModule as KeyModuleFacts,\n familySuffix: f?.familySuffix as string,\n loadedPagesPredicate: f?.loadedPagesPredicate as string,\n memberRefreshes: f?.memberRefreshes as readonly ReviewedCall[],\n refreshHandoffs: f?.refreshHandoffs as ListResetFacts['refreshHandoffs'],\n});\n\nexport const queryCacheGuard: GenericGuardDefinition<QueryCacheFacts> = {\n id: 'queryCache',\n absentWhen: false,\n factProblems: (f) => [\n ...new Set([\n ...cacheInvalidationProblems(f),\n ...listResetProblems(listFacts(f)),\n ...sessionRetirementPart.factProblems({ owner: f?.sessionOwner, predicateRetirements: f?.predicateRetirements }).map((p) =>\n p.startsWith('owner') ? `session${p[0].toUpperCase()}${p.slice(1)}` : p,\n ),\n ]),\n ],\n build: (f) => [\n ...cacheInvalidationGuards(f, { sessionOwner: f.sessionOwner, memberRefreshes: f.memberRefreshes }),\n ...listResetGuards(listFacts(f), f.sessionOwner),\n ...sessionRetirementPart.build({ owner: f.sessionOwner, predicateRetirements: f.predicateRetirements }),\n ],\n};\n\nexport const CACHE_GUARDS = [queryCacheGuard, domainEventRegistryGuard] as const;\n"]}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/modules/frontend-reads/cache.ts"],"names":[],"mappings":"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","sourcesContent":["// What may touch the query cache, and how: invalidation only through the domain-event registry,\n// aimed at keys a live query reads and never at an infinite list; an infinite list never reloaded\n// by an action; a whole-cache drop only by the session-retirement owner; and a registry whose every\n// event is produced, well formed, and awaited.\n\nimport ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../config.js';\nimport type { Finding, Guard, GuardContext } from '../../guard.js';\nimport type { FileView } from '../../reader/view.js';\nimport { identifierProblem, loaderProblem, pathProblem, reviewedProblems, type Loader } from '../../support/facts.js';\nimport { escapeRegExp } from '../../support/text.js';\nimport {\n APP_CODE,\n alternation,\n callSpan,\n collapse,\n familyOf,\n filesUnder,\n identifierListProblem,\n infiniteKeyFamilies,\n isPrefix,\n keyModuleProblem,\n loadKeyObjects,\n pathListProblem,\n reachesInfinite,\n requiredFile,\n reviewedCallProblem,\n sampleKey,\n type KeyBuilders,\n type KeyModuleFacts,\n type ReviewedCall,\n} from './shared.js';\n\n/** query-core's registry factory and the two invalidation builders a registry entry uses. */\nconst REGISTRY_FACTORY = 'createDomainEventInvalidator';\nconst EXACT = 'exact';\n\n/** The registry: where it is. */\nexport interface RegistryFacts {\n path: string;\n}\n\n/** The object literal the registry module hands to query-core's registry factory, as code. */\nexport function registryObjectCode(file: FileView): { name: string; code: string } | null {\n const sf = file.sourceFile;\n let name: string | null = null;\n const find = (node: ts.Node) => {\n if (!name && ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === REGISTRY_FACTORY && node.arguments[0] && ts.isIdentifier(node.arguments[0])) {\n name = node.arguments[0].text;\n }\n ts.forEachChild(node, find);\n };\n find(sf);\n if (!name) return null;\n let found: { name: string; code: string } | null = null;\n const visit = (node: ts.Node) => {\n if (!found && ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === name && node.initializer) {\n found = { name: name!, code: file.code.slice(node.initializer.getStart(sf), node.initializer.getEnd()) };\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return found;\n}\n\nconst keyRefPattern = (objects: readonly string[]) => new RegExp(`\\\\b(${alternation(objects)})\\\\.(\\\\w+)`, 'g');\n\n// =============================================================================================\n// Cache invalidation only through the registry; the registry's targets are read, and never an infinite list.\n// =============================================================================================\n\nexport interface CacheInvalidationFacts {\n registry: RegistryFacts;\n keyModule: KeyModuleFacts;\n /** The trees whose `queryKey:` sites are the app's live reads (hooks, components, pages). */\n readTrees: readonly string[];\n /** The suffix the key module names a family helper with (`listPrefix()` → `Prefix`). */\n familySuffix: string;\n}\n\n/** What the registry rule leaves to the other cache owners: the session-retirement owner, and a person's own refreshes. */\ninterface OwnedElsewhere {\n sessionOwner: string;\n memberRefreshes: readonly ReviewedCall[];\n}\n\nconst CLEAR_CALL = /\\.\\s*(invalidateQueries|removeQueries|resetQueries)(\\s*\\()/g;\nconst CACHE_WRITE_CALL =\n /\\b(refetchQueries|resetQueries|cancelQueries|setQueryData|setQueriesData|getQueryData|getQueriesData|invalidateQueries|removeQueries|ensureQueryData|prefetchQuery)\\b/;\n\n/** Every invalidate / remove / reset call in a file, as its collapsed text from the method name on. */\nexport function clearCalls(file: FileView): Array<{ index: number; call: string }> {\n return [...file.code.matchAll(CLEAR_CALL)].map((m) => {\n const name = (m.index ?? 0) + m[0].indexOf(m[1]);\n const open = (m.index ?? 0) + m[0].length - 1;\n return { index: name, call: collapse(callSpan(file.code, name, open)) };\n });\n}\n\n/** Key families some live query reads: a `queryKey` built from a key method outside a cache call, or a key object handed whole. */\nexport function readKeyFamilies(files: ReadonlyArray<{ code: string }>, objects: readonly string[], familySuffix: string): Set<string> {\n const read = new Set<string>();\n const names = alternation(objects);\n for (const { code } of files) {\n for (const line of code.split('\\n')) {\n if (CACHE_WRITE_CALL.test(line)) continue;\n for (const m of line.matchAll(new RegExp(`\\\\bqueryKey\\\\s*[:=]\\\\s*(${names})\\\\.(\\\\w+)`, 'g'))) read.add(familyOf(`${m[1]}.${m[2]}`, familySuffix));\n for (const m of line.matchAll(new RegExp(`[\\\\w$]+\\\\s*:\\\\s*(${names})\\\\b(?![\\\\w$]|\\\\s*\\\\.)`, 'g'))) read.add(`${m[1]}.*`);\n }\n }\n return read;\n}\n\n/** The argument count of the call whose `(` is at `open`, or null when there is no call there. */\nfunction argCountAt(code: string, open: number): number | null {\n if (code[open] !== '(') return null;\n let depth = 0;\n let count = 0;\n let sawToken = false;\n for (let i = open; i < code.length; i += 1) {\n const ch = code[i];\n if ('([{'.includes(ch)) {\n depth += 1;\n if (depth > 1) sawToken = true;\n } else if (')]}'.includes(ch)) {\n depth -= 1;\n if (depth === 0) return sawToken ? count + 1 : 0;\n } else if (ch === ',' && depth === 1) count += 1;\n else if (depth >= 1 && !/\\s/.test(ch)) sawToken = true;\n }\n return null;\n}\n\n/** Each key method → the argument counts the app's live reads build it with. */\nexport function readArgCounts(files: ReadonlyArray<{ code: string }>, objects: readonly string[]): Map<string, Set<number>> {\n const counts = new Map<string, Set<number>>();\n const re = new RegExp(`\\\\bqueryKey\\\\s*[:=]\\\\s*(${alternation(objects)})\\\\.(\\\\w+)\\\\(`, 'g');\n for (const { code } of files) {\n for (const line of code.split('\\n')) {\n if (CACHE_WRITE_CALL.test(line)) continue;\n for (const m of line.matchAll(re)) {\n const n = argCountAt(line, (m.index ?? 0) + m[0].length - 1);\n if (n === null) continue;\n const ref = `${m[1]}.${m[2]}`;\n counts.set(ref, (counts.get(ref) ?? new Set()).add(n));\n }\n }\n }\n return counts;\n}\n\n/** Registry targets that miss: unread, an exact on a family, an exact shaped unlike every read, or one reaching an infinite list. */\nexport function registryTargetProblems(input: {\n registryCode: string;\n reads: ReadonlyArray<{ code: string }>;\n builders: KeyBuilders;\n familySuffix: string;\n}): string[] {\n const { registryCode, reads, builders, familySuffix } = input;\n const objects = Object.keys(builders);\n const refs = [...new Set([...registryCode.matchAll(keyRefPattern(objects))].map((m) => `${m[1]}.${m[2]}`))];\n const read = readKeyFamilies(reads, objects, familySuffix);\n const readKeys = [...read].map((f) => sampleKey(f, builders)).filter((k): k is unknown[] => k !== null);\n const problems: string[] = [];\n for (const ref of refs) {\n if (read.has(familyOf(ref, familySuffix)) || read.has(`${ref.split('.')[0]}.*`)) continue;\n const key = sampleKey(ref, builders);\n if (key === null || !readKeys.some((readKey) => isPrefix(key, readKey))) problems.push(`${ref}: no live query reads this key`);\n }\n const counts = readArgCounts(reads, objects);\n const exactRe = new RegExp(`\\\\b${EXACT}\\\\(\\\\s*(${alternation(objects)})\\\\.(\\\\w+)`, 'g');\n const shaped = new Set<string>();\n for (const m of registryCode.matchAll(exactRe)) {\n const ref = `${m[1]}.${m[2]}`;\n if (shaped.has(ref)) continue;\n if (m[2] === 'all' || (m[2].endsWith(familySuffix) && m[2] !== familySuffix)) {\n shaped.add(ref);\n problems.push(`${ref}: an exact target on a key family (only a prefix target reaches a family)`);\n continue;\n }\n const n = argCountAt(registryCode, (m.index ?? 0) + m[0].length);\n const readCounts = counts.get(ref);\n if (n !== null && readCounts && !readCounts.has(n)) {\n shaped.add(ref);\n problems.push(`${ref}: an exact target built with ${n} argument(s), which no live read builds`);\n }\n }\n const infinite = infiniteKeyFamilies(reads, objects, familySuffix);\n for (const ref of refs) if (reachesInfinite(ref, infinite, builders, familySuffix)) problems.push(`${ref}: reaches an infinite list`);\n return problems;\n}\n\nfunction registryProblem(value: unknown, problems: string[]): void {\n const facts = value as RegistryFacts | undefined;\n if (!facts || typeof facts !== 'object') problems.push('registry is missing');\n else pathProblem(facts.path, 'registry.path', problems);\n}\n\nconst cacheInvalidationProblems = (facts: CacheInvalidationFacts) => {\n const problems: string[] = [];\n registryProblem(facts?.registry, problems);\n keyModuleProblem(facts?.keyModule, problems);\n pathListProblem(facts?.readTrees, 'readTrees', problems);\n identifierProblem(facts?.familySuffix, 'familySuffix', problems);\n return problems;\n};\n\nconst cacheInvalidationGuards = (facts: CacheInvalidationFacts, owned: OwnedElsewhere): Guard[] => [\n {\n title: 'saved reads are refreshed, removed, or reset only through the domain-event registry',\n description:\n `${facts.registry.path} — the object it hands to query-core's ${REGISTRY_FACTORY} — is the one place that turns something that ` +\n 'happened into what the cache does: refresh, remove, or reset. No other file calls invalidateQueries, removeQueries, or ' +\n 'resetQueries: emit the domain event instead, and patch an infinite list in place. The only other owners are the session-' +\n `retirement owner (${owned.sessionOwner}) and a person's own refresh, declared once beside the list-reload rule.`,\n run(context) {\n const { file: registry, findings } = requiredFile(context, facts.registry.path, 'the domain-event registry');\n if (registry && !registryObjectCode(registry)) findings.push({ file: registry.path, detail: `no registry object handed to ${REGISTRY_FACTORY}` });\n const refreshes = new Set(owned.memberRefreshes.map((r) => `${r.path} ${r.call}`));\n for (const file of context.files(APP_CODE)) {\n if (file.path === facts.registry.path || file.path === owned.sessionOwner) continue;\n for (const { index, call } of clearCalls(file)) {\n if (refreshes.has(`${file.path} ${call}`)) continue;\n findings.push({ file: file.path, line: file.lineOf(index), detail: `outside the registry: ${call.slice(0, 120)}` });\n }\n }\n return findings;\n },\n },\n {\n title: 'every registry cache target is a key a live query reads, and never an infinite list',\n description:\n `Every key the registry in ${facts.registry.path} writes is reached by a live query's key (a queryKey built from the same key ` +\n `method in ${facts.readTrees.join(', ')}, or a key object handed whole to a reader); an exact target names a leaf the reads build ` +\n `with the same arguments, never a family (all, or a …${facts.familySuffix} helper); and no target reaches an infinite list — named, ` +\n \"through its family helper, or through its scope. A write aimed at a key nothing reads is a silent no-op, and invalidating an \" +\n 'infinite list re-runs every loaded page.',\n timeoutMs: 120_000,\n async run(context: GuardContext): Promise<Finding[]> {\n const { file: registry, findings } = requiredFile(context, facts.registry.path, 'the domain-event registry');\n if (!registry) return findings;\n const object = registryObjectCode(registry);\n if (!object) return [{ file: registry.path, detail: `no registry object handed to ${REGISTRY_FACTORY}` }];\n const builders = await loadKeyObjects(facts.keyModule);\n const { files, findings: missing } = filesUnder(context, facts.readTrees);\n findings.push(...missing);\n for (const detail of registryTargetProblems({ registryCode: object.code, reads: files, builders, familySuffix: facts.familySuffix })) {\n findings.push({ file: registry.path, detail });\n }\n return findings;\n },\n },\n];\n\n// =============================================================================================\n// No action-driven reload of an infinite list.\n// =============================================================================================\n\nexport interface ListResetFacts {\n keyModule: KeyModuleFacts;\n familySuffix: string;\n /** The app predicate that is true for a query holding loaded pages; a reload filtered by its negation reloads no shown list. */\n loadedPagesPredicate: string;\n /** A person's own refreshes (pull-to-refresh, a Refresh button): each call site with its why. */\n memberRefreshes: readonly ReviewedCall[];\n /** Hooks that run a member's own refresh, each handed only to its refresh control on the named prop; [] for none. */\n refreshHandoffs: ReadonlyArray<{ hook: string; control: string; prop: string }>;\n}\n\nconst RELOAD_CALL = /\\b(resetQueries|refetchQueries|removeQueries)\\s*\\(/g;\nconst PATCH_CALL = /\\b(setQueryData|setQueriesData)\\s*(?:<[^>]*>)?\\s*\\(/g;\nconst FIRST_PAGE_TRIM = /\\bpages\\.slice\\(\\s*0\\s*,\\s*1\\s*\\)|\\bpageParams\\.slice\\(\\s*0\\s*,\\s*1\\s*\\)|\\bpages\\s*:\\s*\\[\\s*[\\w.?]+\\.pages\\[0\\]\\s*\\]/;\n\n/** The key refs a call targets: its key method, or every one a constant map it indexes holds; null when unresolved. */\nfunction targetRefs(call: string, code: string, objects: readonly string[]): string[] | null {\n const names = alternation(objects);\n const direct = call.match(new RegExp(`\\\\bqueryKey\\\\s*:\\\\s*(${names})\\\\.(\\\\w+)`));\n if (direct) return [`${direct[1]}.${direct[2]}`];\n const indexed = call.match(/\\bqueryKey\\s*:\\s*([A-Za-z_]\\w*)\\[/);\n if (!indexed) return null;\n const decl = code.match(new RegExp(`\\\\bconst \\\\s*${escapeRegExp(indexed[1])}\\\\b[^=]*=\\\\s*\\\\{`));\n if (!decl) return null;\n const open = (decl.index ?? 0) + decl[0].length - 1;\n const refs = [...callSpan(code, open, open).matchAll(keyRefPattern(objects))].map((m) => `${m[1]}.${m[2]}`);\n return refs.length ? refs : null;\n}\n\n/** Every call that reloads or trims an infinite list, outside the reviewed reloads. */\nexport function listReloads(\n files: readonly FileView[],\n builders: KeyBuilders,\n facts: Pick<ListResetFacts, 'familySuffix' | 'loadedPagesPredicate' | 'memberRefreshes'>,\n sessionOwner?: string,\n) {\n const objects = Object.keys(builders);\n const infinite = infiniteKeyFamilies(files, objects, facts.familySuffix);\n const pinned = new Set(facts.memberRefreshes.map((r) => `${r.path} ${r.call}`));\n const excluded = new RegExp(`!${escapeRegExp(facts.loadedPagesPredicate)}\\\\(\\\\s*query\\\\s*\\\\)`);\n const found: Finding[] = [];\n const present = new Set<string>();\n for (const file of files) {\n if (file.path === sessionOwner) continue;\n const code = file.code;\n for (const m of code.matchAll(RELOAD_CALL)) {\n const call = collapse(callSpan(code, m.index ?? 0, (m.index ?? 0) + m[0].length - 1));\n present.add(`${file.path} ${call}`);\n if (pinned.has(`${file.path} ${call}`)) continue;\n const refs = targetRefs(call, code, objects);\n const reloads = refs ? refs.some((ref) => reachesInfinite(ref, infinite, builders, facts.familySuffix)) : !excluded.test(call);\n if (reloads) found.push({ file: file.path, line: file.lineOf(m.index ?? 0), detail: `${refs ? 'reloads an infinite list' : 'reloads queries its key does not name'}: ${call.slice(0, 120)}` });\n }\n for (const m of code.matchAll(PATCH_CALL)) {\n const call = callSpan(code, m.index ?? 0, (m.index ?? 0) + m[0].length - 1);\n if (FIRST_PAGE_TRIM.test(call)) found.push({ file: file.path, line: file.lineOf(m.index ?? 0), detail: `trims a list to its first page: ${collapse(call).slice(0, 120)}` });\n }\n }\n for (const r of facts.memberRefreshes) if (!present.has(`${r.path} ${r.call}`)) found.push({ file: r.path, detail: `stale member refresh: ${r.call} is no longer there` });\n return { infinite, findings: found };\n}\n\n/** Each refresh hook's result used anywhere but on its refresh control's prop, and each hook no file calls. */\nexport function refreshHandoffMisuses(files: readonly FileView[], handoffs: ListResetFacts['refreshHandoffs']): Finding[] {\n const findings: Finding[] = [];\n for (const { hook, control, prop } of handoffs) {\n let callers = 0;\n for (const file of files) {\n for (const m of file.code.matchAll(new RegExp(`const\\\\s+(\\\\w+)\\\\s*=\\\\s*${escapeRegExp(hook)}\\\\(`, 'g'))) {\n callers += 1;\n const name = m[1];\n const uses = [...file.code.matchAll(new RegExp(`\\\\b${name}\\\\b`, 'g'))].length - 1;\n const handed = [...file.code.matchAll(new RegExp(`<${escapeRegExp(control)}[^>]*${escapeRegExp(prop)}=\\\\{${name}\\\\}`, 'g'))].length;\n if (uses !== handed) findings.push({ file: file.path, line: file.lineOf(m.index ?? 0), detail: `${hook}()'s refresh is used other than as <${control} ${prop}>` });\n }\n }\n if (!callers) findings.push({ file: '(refreshHandoffs)', detail: `stale entry: nothing calls ${hook}` });\n }\n return findings;\n}\n\nconst listResetProblems = (facts: ListResetFacts) => {\n const problems: string[] = [];\n keyModuleProblem(facts?.keyModule, problems);\n identifierProblem(facts?.familySuffix, 'familySuffix', problems);\n identifierProblem(facts?.loadedPagesPredicate, 'loadedPagesPredicate', problems);\n reviewedCallProblem(facts?.memberRefreshes, 'memberRefreshes', problems);\n if (!Array.isArray(facts?.refreshHandoffs)) problems.push('refreshHandoffs is missing (declare [] when there is none)');\n else\n facts.refreshHandoffs.forEach((h, i) => {\n identifierProblem(h?.hook, `refreshHandoffs[${i}].hook`, problems);\n identifierProblem(h?.control, `refreshHandoffs[${i}].control`, problems);\n identifierProblem(h?.prop, `refreshHandoffs[${i}].prop`, problems);\n });\n return problems;\n};\n\nconst listResetGuards = (facts: ListResetFacts, sessionOwner: string): Guard[] => [\n {\n title: 'an action never reloads an infinite list',\n description:\n \"An action's change is placed, moved, or patched in place in an infinite list; no resetQueries / refetchQueries / removeQueries \" +\n `whose key reaches one (directly, through its family helper or scope, or through a constant map of keys), none whose key cannot ` +\n `be resolved unless its predicate excludes every query holding loaded pages (!${facts.loadedPagesPredicate}(query)), and no cache ` +\n \"write that trims a list to its first page. A person's own refresh is declared with its why, and a refresh hook's result is only \" +\n 'ever handed to its refresh control.',\n timeoutMs: 120_000,\n async run(context) {\n const builders = await loadKeyObjects(facts.keyModule);\n const files = context.files(APP_CODE);\n const { infinite, findings } = listReloads(files, builders, facts, sessionOwner);\n if (!infinite.size) findings.push({ file: facts.keyModule.path, detail: 'no infinite list found in the app, so the guard checks nothing' });\n findings.push(...refreshHandoffMisuses(files, facts.refreshHandoffs));\n return findings;\n },\n },\n];\n\n// =============================================================================================\n// An unscoped cancel or a whole-cache clear only by session retirement.\n// =============================================================================================\n\nexport interface SessionRetirementFacts {\n /** The session-retirement owner. */\n owner: string;\n /** Retirements beyond a session's end that the owner runs by predicate (a member leaving a group), each with its why; [] for none. */\n predicateRetirements: ReadonlyArray<{ trigger: string; why: string }>;\n}\n\nconst WHOLE_CACHE_DROP = [\n /\\bcancelQueries\\(\\s*\\)/g,\n /\\bcancelQueries\\(\\s*undefined\\b/g,\n /\\bcancelQueries\\(\\s*\\{(?![^}]*\\bqueryKey\\b)/g,\n /\\bget(?:Query|Mutation)Cache\\(\\)\\s*\\.clear\\(/g,\n /\\b\\w*[cC]lient\\s*\\.clear\\(\\s*\\)/g,\n];\n\nexport function wholeCacheDrops(file: FileView): Array<{ index: number; text: string }> {\n return WHOLE_CACHE_DROP.flatMap((re) => [...file.code.matchAll(re)].map((m) => ({ index: m.index ?? 0, text: m[0] }))).sort((a, b) => a.index - b.index);\n}\n\nconst sessionRetirementPart = {\n factProblems(facts: SessionRetirementFacts) {\n const problems: string[] = [];\n pathProblem(facts?.owner, 'owner', problems);\n reviewedProblems(facts?.predicateRetirements, 'predicateRetirements', problems, { key: 'trigger' });\n return problems;\n },\n build: (facts: SessionRetirementFacts): Guard[] => [\n {\n title: 'an unscoped cancel or a whole-cache clear runs only in the session-retirement owner',\n description:\n `A cancelQueries with no key (bare, or selected by a predicate) and a query or mutation cache clear drop reads the call site ` +\n `cannot name, so only ${facts.owner} runs them: when a session ends it cancels every query and clears the query cache` +\n (facts.predicateRetirements.length ? `, and it cancels by predicate for ${facts.predicateRetirements.map((r) => r.trigger).join('; ')}` : '') +\n '. Everywhere else a cancel names its key, and nothing clears a cache.',\n run(context) {\n const { file: owner, findings } = requiredFile(context, facts.owner, 'the session-retirement owner');\n for (const file of context.files(APP_CODE)) {\n if (file.path === facts.owner) continue;\n for (const drop of wholeCacheDrops(file)) findings.push({ file: file.path, line: file.lineOf(drop.index), detail: `outside the session-retirement owner: ${drop.text}` });\n }\n if (owner) {\n if (!/\\bcancelQueries\\(\\s*\\)/.test(owner.code)) findings.push({ file: owner.path, detail: 'the owner no longer cancels every query when a session ends' });\n if (!/getQueryCache\\(\\)\\s*\\.clear\\(/.test(owner.code)) findings.push({ file: owner.path, detail: 'the owner no longer clears the query cache when a session ends' });\n const byPredicate = [...owner.code.matchAll(/\\bcancelQueries\\(\\s*\\{\\s*predicate\\s*:/g)].length;\n if (byPredicate !== facts.predicateRetirements.length) {\n findings.push({ file: owner.path, detail: `the owner cancels by predicate ${byPredicate} time(s); ${facts.predicateRetirements.length} predicate retirement(s) are reviewed` });\n }\n }\n return findings;\n },\n },\n ],\n};\n\n// =============================================================================================\n// The domain-event registry: every event produced, every variant registered and well formed, every\n// notification handed on.\n// =============================================================================================\n\nexport interface DomainEventRegistryFacts {\n registry: RegistryFacts & {\n /** A loader of the registry object itself (event type → invalidation builder). */\n load: Loader<Record<string, unknown>>;\n };\n /** A loader of the core's domain-event schema: a discriminated union on `type`, each variant carrying an `ids` object. */\n eventSchema: Loader<unknown>;\n /** The app's functions that dispatch a domain event and return the refresh's promise. */\n notifiers: readonly string[];\n}\n\ntype ZodLike = { def?: any; _def?: any; shape?: Record<string, ZodLike>; options?: unknown[]; value?: unknown };\nconst defOf = (field: ZodLike) => field?.def ?? field?._def ?? {};\nconst kindOf = (field: ZodLike): 'optional' | 'nullable' | 'enum' | 'required' => {\n const type = defOf(field).type;\n return type === 'optional' || type === 'nullable' || type === 'enum' ? type : 'required';\n};\n\n/** Synthetic `ids` for one variant: every field filled, then each optional field dropped in turn. */\nexport function syntheticIds(idsSchema: ZodLike): Array<Record<string, unknown>> {\n const baseline: Record<string, unknown> = {};\n const optional: string[] = [];\n for (const [key, field] of Object.entries(idsSchema?.shape ?? {})) {\n const kind = kindOf(field);\n if (kind === 'enum') baseline[key] = (field.options as unknown[])[0];\n else if (kind === 'optional') {\n optional.push(key);\n const inner = defOf(field).innerType as ZodLike;\n baseline[key] = kindOf(inner) === 'enum' ? (inner.options as unknown[])[0] : `test-${key}`;\n } else baseline[key] = `test-${key}`;\n }\n return [{ ...baseline }, ...optional.map((key) => Object.fromEntries(Object.entries(baseline).filter(([k]) => k !== key)))];\n}\n\n/** What a query-core registry entry may do to the reads it matches, and how a refresh refetches. */\nconst CACHE_ACTIONS: ReadonlySet<unknown> = new Set([undefined, 'refresh', 'remove', 'reset']);\nconst REFETCH_TYPES: ReadonlySet<unknown> = new Set([undefined, 'active', 'all', 'none']);\n\n/** Why a builder's answer is not a list of well-formed invalidations, or null. */\nexport function malformedInvalidations(answer: unknown): string | null {\n if (!Array.isArray(answer)) return 'does not answer a list of invalidations';\n for (const inv of answer as Array<Record<string, unknown>>) {\n if (inv?.kind === 'exact' || inv?.kind === 'prefix') {\n if (!Array.isArray(inv.queryKey) || !inv.queryKey.length) return `a ${inv.kind} invalidation with no key`;\n } else if (inv?.kind === 'predicate') {\n if (typeof inv.description !== 'string' || !inv.description || typeof inv.match !== 'function') return 'a predicate invalidation with no description or matcher';\n } else return `an invalidation of unknown kind ${String(inv?.kind)}`;\n if (!CACHE_ACTIONS.has(inv.action)) return `a ${inv.kind} invalidation with unknown action ${String(inv.action)}`;\n if (!REFETCH_TYPES.has(inv.refetchType)) return `a ${inv.kind} invalidation with unknown refetchType ${String(inv.refetchType)}`;\n if ((inv.action === 'remove' || inv.action === 'reset') && inv.refetchType !== undefined) {\n return `a ${inv.action} invalidation with a refetchType, which only a refresh takes`;\n }\n }\n return null;\n}\n\n/** Whether the call at `index` starts a statement, so its promise is dropped. */\nfunction startsStatement(code: string, index: number): boolean {\n const before = code.slice(0, index).trimEnd();\n return before.length === 0 || ';{})'.includes(before.charAt(before.length - 1));\n}\n\nexport function droppedNotifications(file: FileView, notifiers: readonly string[]): Array<{ index: number; name: string }> {\n const hits: Array<{ index: number; name: string }> = [];\n for (const m of file.code.matchAll(new RegExp(`\\\\b(${alternation(notifiers)})\\\\(`, 'g'))) {\n const index = m.index ?? 0;\n if (/function\\s+$/.test(file.code.slice(0, index))) continue;\n if (startsStatement(file.code, index)) hits.push({ index, name: m[1] });\n }\n return hits;\n}\n\nexport const domainEventRegistryGuard: GenericGuardDefinition<DomainEventRegistryFacts> = {\n id: 'domainEventRegistry',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n registryProblem(facts?.registry, problems);\n loaderProblem(facts?.registry?.load, 'registry.load', problems);\n loaderProblem(facts?.eventSchema, 'eventSchema', problems);\n identifierListProblem(facts?.notifiers, 'notifiers', problems, { nonEmpty: true });\n return problems;\n },\n build: (facts) => [\n {\n title: 'every registered domain event has a producer in the app',\n description:\n `Every event type the registry in ${facts.registry.path} handles is emitted somewhere in the app's own code (its quoted type ` +\n \"outside the registry, in the client or functions tree); the core's schema holds every variant by construction, so it is no \" +\n 'evidence. Restore the producer, or delete the event from the core and the registry.',\n async run(context) {\n const registry = (await facts.registry.load()) ?? {};\n const findings: Finding[] = [];\n const haystack = context\n .files({ roots: ['app', 'functions'], optionalRoots: ['functions'], kinds: ['code'], tests: false })\n .filter((f) => f.path !== facts.registry.path)\n .map((f) => f.code)\n .join('\\n');\n const produced = (type: string) => haystack.includes(`'${type}'`) || haystack.includes(`\"${type}\"`);\n for (const type of Object.keys(registry)) if (!produced(type)) findings.push({ file: facts.registry.path, detail: `${type}: no producer in the app` });\n return findings;\n },\n },\n {\n title: \"every core domain-event variant has a registry entry with well-formed invalidations\",\n description:\n `Every variant of the core's domain-event schema has an entry in the registry in ${facts.registry.path}, and the entry answers, ` +\n 'for every shape of its ids (each optional id present and absent), a list of invalidations that are each an exact or prefix ' +\n 'target with a non-empty key, or a predicate with a description and a matcher.',\n async run(context) {\n // The loaded registry is judged, but the file the facts name must be the one it comes from.\n if (!context.reader.exists(facts.registry.path)) return [{ file: facts.registry.path, detail: 'the registry file does not exist' }];\n context.file(facts.registry.path);\n const registry = (await facts.registry.load()) ?? {};\n const schema = (await facts.eventSchema()) as ZodLike;\n const variants = (schema?.options ?? []) as ZodLike[];\n if (!variants.length) return [{ file: '(eventSchema)', detail: 'the loader did not answer a discriminated union of variants' }];\n const findings: Finding[] = [];\n for (const variant of variants) {\n const type = String(variant.shape?.type?.value ?? '');\n if (!type) {\n findings.push({ file: '(eventSchema)', detail: 'a variant carries no literal type' });\n continue;\n }\n const build = registry[type];\n if (typeof build !== 'function') {\n findings.push({ file: facts.registry.path, detail: `${type}: no registry entry` });\n continue;\n }\n for (const ids of syntheticIds(variant.shape?.ids as ZodLike)) {\n let problem: string | null;\n try {\n problem = malformedInvalidations((build as (ids: unknown) => unknown)(ids));\n } catch (err) {\n problem = `throws for ids ${JSON.stringify(ids)}: ${(err as Error)?.message ?? err}`;\n }\n if (problem) findings.push({ file: facts.registry.path, detail: `${type}: ${problem}` });\n }\n }\n return findings;\n },\n },\n {\n title: 'every domain-event notification hands its refresh promise on',\n description:\n `A call to ${facts.notifiers.join(' / ')} returns the promise of the refresh it starts; a mutation returns or awaits it so it stays ` +\n 'pending until the refreshed data is on screen. A call in statement position drops it silently: return it, await it, pass it ' +\n 'on, or mark a deliberate fire-and-forget with void.',\n run(context) {\n const findings: Finding[] = [];\n let calls = 0;\n const callRe = new RegExp(`\\\\b(?:${alternation(facts.notifiers)})\\\\(`, 'g');\n for (const file of context.files(APP_CODE)) {\n calls += [...file.code.matchAll(callRe)].length;\n for (const hit of droppedNotifications(file, facts.notifiers)) {\n findings.push({ file: file.path, line: file.lineOf(hit.index), detail: `${hit.name}(…) in statement position drops its refresh` });\n }\n }\n if (!calls) findings.push({ file: '(notifiers)', detail: `nothing in the app calls ${facts.notifiers.join(' / ')}, so the guard checks nothing` });\n return findings;\n },\n },\n ],\n};\n\n/**\n * Every fact the query-cache owners need, declared once: the registry (the one place something that\n * happened changes saved reads), a person's own refreshes, and the session-retirement owner.\n */\nexport interface QueryCacheFacts extends CacheInvalidationFacts {\n loadedPagesPredicate: string;\n memberRefreshes: readonly ReviewedCall[];\n refreshHandoffs: ListResetFacts['refreshHandoffs'];\n sessionOwner: string;\n predicateRetirements: SessionRetirementFacts['predicateRetirements'];\n}\n\nconst listFacts = (f: QueryCacheFacts | undefined): ListResetFacts => ({\n keyModule: f?.keyModule as KeyModuleFacts,\n familySuffix: f?.familySuffix as string,\n loadedPagesPredicate: f?.loadedPagesPredicate as string,\n memberRefreshes: f?.memberRefreshes as readonly ReviewedCall[],\n refreshHandoffs: f?.refreshHandoffs as ListResetFacts['refreshHandoffs'],\n});\n\nexport const queryCacheGuard: GenericGuardDefinition<QueryCacheFacts> = {\n id: 'queryCache',\n absentWhen: false,\n factProblems: (f) => [\n ...new Set([\n ...cacheInvalidationProblems(f),\n ...listResetProblems(listFacts(f)),\n ...sessionRetirementPart.factProblems({ owner: f?.sessionOwner, predicateRetirements: f?.predicateRetirements }).map((p) =>\n p.startsWith('owner') ? `session${p[0].toUpperCase()}${p.slice(1)}` : p,\n ),\n ]),\n ],\n build: (f) => [\n ...cacheInvalidationGuards(f, { sessionOwner: f.sessionOwner, memberRefreshes: f.memberRefreshes }),\n ...listResetGuards(listFacts(f), f.sessionOwner),\n ...sessionRetirementPart.build({ owner: f.sessionOwner, predicateRetirements: f.predicateRetirements }),\n ],\n};\n\nexport const CACHE_GUARDS = [queryCacheGuard, domainEventRegistryGuard] as const;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-overrides.d.ts","sourceRoot":"","sources":["../../../src/modules/repo/dependency-overrides.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAI9D,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAC1C;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAU/K;AAED,eAAO,MAAM,uBAAuB,EAAE,sBAAsB,CAAC,uBAAuB,CA8CnF,CAAC"}
1
+ {"version":3,"file":"dependency-overrides.d.ts","sourceRoot":"","sources":["../../../src/modules/repo/dependency-overrides.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAI9D,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAC1C;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAU/K;AAED,eAAO,MAAM,uBAAuB,EAAE,sBAAsB,CAAC,uBAAuB,CA+CnF,CAAC"}
@@ -25,8 +25,9 @@ export const dependencyOverrideGuard = {
25
25
  const problems = [];
26
26
  reviewedProblems(facts?.overrides, 'overrides', problems, {
27
27
  key: 'parent',
28
- id: (o) => (isText(o.child) ? `${o.parent} → ${o.child}` : undefined),
29
- idNames: 'child',
28
+ // One override per manifest: each manifest that installs the parent carries its own copy.
29
+ id: (o) => (isText(o.child) && isText(o.manifest) ? `${o.manifest}: ${o.parent} → ${o.child}` : undefined),
30
+ idNames: 'manifest or child',
30
31
  nonEmpty: true,
31
32
  extra(o, label) {
32
33
  textProblem(o.manifest, `${label}'s manifest`, problems);
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-overrides.js","sourceRoot":"","sources":["../../../src/modules/repo/dependency-overrides.ts"],"names":[],"mappings":"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","sourcesContent":["// A dependency override exists only while it is needed: while the parent's declared range for the\n// child can still resolve to an affected version. Once the parent's range can no longer reach one,\n// the override is redundant and is removed; while it can, the override is present and its own range\n// admits no affected version.\n\nimport semver from 'semver';\nimport type { GenericGuardDefinition } from '../../config.js';\nimport type { Finding } from '../../guard.js';\nimport { isText, reviewedProblems, textProblem } from '../../support/facts.js';\n\nexport interface DependencyOverride {\n /** The manifest holding the parent-scoped `overrides` entry, repo-relative. */\n manifest: string;\n /** The folder whose `node_modules` holds the installed parent ('' for the repository root). */\n installedUnder: string;\n parent: string;\n child: string;\n /** The child's affected versions, as a semver range. */\n affected: string;\n why: string;\n}\n\nexport interface DependencyOverrideFacts {\n overrides: readonly DependencyOverride[];\n}\n\n/** Why the override is wrong for these ranges, or null when it is exactly as it must be. */\nexport function overrideProblem(o: Pick<DependencyOverride, 'parent' | 'child' | 'affected'>, parentRange: string | undefined, overrideRange: string | undefined): string | null {\n if (parentRange === undefined) return `${o.parent} no longer declares ${o.child}: remove the override`;\n if (semver.validRange(parentRange) !== null && !semver.intersects(parentRange, o.affected)) {\n return `${o.parent} now declares ${o.child} ${parentRange}, which reaches no affected version: remove the override`;\n }\n if (overrideRange === undefined) return `${o.parent} still declares ${o.child} ${parentRange}, which can reach an affected version, and no override pins it`;\n if (semver.validRange(overrideRange) === null || semver.intersects(overrideRange, o.affected)) {\n return `the override pins ${o.child} to ${overrideRange}, which admits an affected version (${o.affected})`;\n }\n return null;\n}\n\nexport const dependencyOverrideGuard: GenericGuardDefinition<DependencyOverrideFacts> = {\n id: 'dependencyOverrides',\n absentWhen: 'the app carries no dependency override',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.overrides, 'overrides', problems, {\n key: 'parent',\n id: (o) => (isText(o.child) ? `${o.parent} → ${o.child}` : undefined),\n idNames: 'child',\n nonEmpty: true,\n extra(o, label) {\n textProblem(o.manifest, `${label}'s manifest`, problems);\n if (typeof o.installedUnder !== 'string') problems.push(`${label}'s installedUnder is missing ('' for the repository root)`);\n if (!isText(o.affected) || semver.validRange(o.affected) === null) problems.push(`${label}'s affected is not a semver range`);\n },\n });\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'every dependency override exists exactly while its parent can still reach an affected version',\n description:\n \"An override pins a child dependency under one parent because the parent's own range can resolve to an affected \" +\n \"version. Once it cannot, the override is redundant and is removed; while it can, the override's range admits no \" +\n 'affected version.',\n run(context) {\n const findings: Finding[] = [];\n for (const o of facts.overrides) {\n const manifest = JSON.parse(context.file(o.manifest).text) as { overrides?: Record<string, unknown> };\n const parentPath = `${o.installedUnder ? `${o.installedUnder}/` : ''}node_modules/${o.parent}/package.json`;\n if (!context.reader.exists(parentPath)) {\n findings.push({ file: o.manifest, detail: `${o.parent} is not installed under ${o.installedUnder || 'the root'}, so the override cannot be judged` });\n continue;\n }\n const parent = JSON.parse(context.file(parentPath).text) as { dependencies?: Record<string, string> };\n const scoped = manifest.overrides?.[o.parent];\n const pinned = scoped !== null && typeof scoped === 'object' ? (scoped as Record<string, unknown>)[o.child] : undefined;\n const problem = overrideProblem(o, parent.dependencies?.[o.child], typeof pinned === 'string' ? pinned : undefined);\n if (problem) findings.push({ file: o.manifest, detail: problem });\n }\n return findings;\n },\n },\n ];\n },\n};\n"]}
1
+ {"version":3,"file":"dependency-overrides.js","sourceRoot":"","sources":["../../../src/modules/repo/dependency-overrides.ts"],"names":[],"mappings":"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","sourcesContent":["// A dependency override exists only while it is needed: while the parent's declared range for the\n// child can still resolve to an affected version. Once the parent's range can no longer reach one,\n// the override is redundant and is removed; while it can, the override is present and its own range\n// admits no affected version.\n\nimport semver from 'semver';\nimport type { GenericGuardDefinition } from '../../config.js';\nimport type { Finding } from '../../guard.js';\nimport { isText, reviewedProblems, textProblem } from '../../support/facts.js';\n\nexport interface DependencyOverride {\n /** The manifest holding the parent-scoped `overrides` entry, repo-relative. */\n manifest: string;\n /** The folder whose `node_modules` holds the installed parent ('' for the repository root). */\n installedUnder: string;\n parent: string;\n child: string;\n /** The child's affected versions, as a semver range. */\n affected: string;\n why: string;\n}\n\nexport interface DependencyOverrideFacts {\n overrides: readonly DependencyOverride[];\n}\n\n/** Why the override is wrong for these ranges, or null when it is exactly as it must be. */\nexport function overrideProblem(o: Pick<DependencyOverride, 'parent' | 'child' | 'affected'>, parentRange: string | undefined, overrideRange: string | undefined): string | null {\n if (parentRange === undefined) return `${o.parent} no longer declares ${o.child}: remove the override`;\n if (semver.validRange(parentRange) !== null && !semver.intersects(parentRange, o.affected)) {\n return `${o.parent} now declares ${o.child} ${parentRange}, which reaches no affected version: remove the override`;\n }\n if (overrideRange === undefined) return `${o.parent} still declares ${o.child} ${parentRange}, which can reach an affected version, and no override pins it`;\n if (semver.validRange(overrideRange) === null || semver.intersects(overrideRange, o.affected)) {\n return `the override pins ${o.child} to ${overrideRange}, which admits an affected version (${o.affected})`;\n }\n return null;\n}\n\nexport const dependencyOverrideGuard: GenericGuardDefinition<DependencyOverrideFacts> = {\n id: 'dependencyOverrides',\n absentWhen: 'the app carries no dependency override',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.overrides, 'overrides', problems, {\n key: 'parent',\n // One override per manifest: each manifest that installs the parent carries its own copy.\n id: (o) => (isText(o.child) && isText(o.manifest) ? `${o.manifest}: ${o.parent} → ${o.child}` : undefined),\n idNames: 'manifest or child',\n nonEmpty: true,\n extra(o, label) {\n textProblem(o.manifest, `${label}'s manifest`, problems);\n if (typeof o.installedUnder !== 'string') problems.push(`${label}'s installedUnder is missing ('' for the repository root)`);\n if (!isText(o.affected) || semver.validRange(o.affected) === null) problems.push(`${label}'s affected is not a semver range`);\n },\n });\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'every dependency override exists exactly while its parent can still reach an affected version',\n description:\n \"An override pins a child dependency under one parent because the parent's own range can resolve to an affected \" +\n \"version. Once it cannot, the override is redundant and is removed; while it can, the override's range admits no \" +\n 'affected version.',\n run(context) {\n const findings: Finding[] = [];\n for (const o of facts.overrides) {\n const manifest = JSON.parse(context.file(o.manifest).text) as { overrides?: Record<string, unknown> };\n const parentPath = `${o.installedUnder ? `${o.installedUnder}/` : ''}node_modules/${o.parent}/package.json`;\n if (!context.reader.exists(parentPath)) {\n findings.push({ file: o.manifest, detail: `${o.parent} is not installed under ${o.installedUnder || 'the root'}, so the override cannot be judged` });\n continue;\n }\n const parent = JSON.parse(context.file(parentPath).text) as { dependencies?: Record<string, string> };\n const scoped = manifest.overrides?.[o.parent];\n const pinned = scoped !== null && typeof scoped === 'object' ? (scoped as Record<string, unknown>)[o.child] : undefined;\n const problem = overrideProblem(o, parent.dependencies?.[o.child], typeof pinned === 'string' ? pinned : undefined);\n if (problem) findings.push({ file: o.manifest, detail: problem });\n }\n return findings;\n },\n },\n ];\n },\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/repo-guards",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ttt-productions/ttt-packages.git",