@ttt-productions/repo-guards 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/backend/auth.d.ts +2 -1
- package/dist/modules/backend/auth.d.ts.map +1 -1
- package/dist/modules/backend/auth.js +38 -10
- package/dist/modules/backend/auth.js.map +1 -1
- package/dist/modules/backend/functions-build.d.ts.map +1 -1
- package/dist/modules/backend/functions-build.js +7 -6
- package/dist/modules/backend/functions-build.js.map +1 -1
- package/dist/modules/backend/guards.d.ts +2 -2
- package/dist/modules/backend/guards.d.ts.map +1 -1
- package/dist/modules/backend/guards.js.map +1 -1
- package/dist/modules/core-definitions/contracts.d.ts.map +1 -1
- package/dist/modules/core-definitions/contracts.js +5 -4
- package/dist/modules/core-definitions/contracts.js.map +1 -1
- package/dist/modules/core-definitions/guards.d.ts +2 -2
- package/dist/modules/core-definitions/guards.d.ts.map +1 -1
- package/dist/modules/core-definitions/guards.js.map +1 -1
- package/dist/modules/core-definitions/redeclaration.d.ts.map +1 -1
- package/dist/modules/core-definitions/redeclaration.js +7 -6
- package/dist/modules/core-definitions/redeclaration.js.map +1 -1
- package/dist/modules/core-definitions/schema-length-literal.d.ts.map +1 -1
- package/dist/modules/core-definitions/schema-length-literal.js +3 -2
- package/dist/modules/core-definitions/schema-length-literal.js.map +1 -1
- package/dist/modules/core-definitions/text-field-declarations.d.ts.map +1 -1
- package/dist/modules/core-definitions/text-field-declarations.js +4 -3
- package/dist/modules/core-definitions/text-field-declarations.js.map +1 -1
- package/dist/modules/firestore/analyzer.d.ts +295 -319
- package/dist/modules/firestore/analyzer.d.ts.map +1 -1
- package/dist/modules/firestore/analyzer.js +258 -265
- package/dist/modules/firestore/analyzer.js.map +1 -1
- package/dist/modules/firestore/guard.d.ts +8 -60
- package/dist/modules/firestore/guard.d.ts.map +1 -1
- package/dist/modules/firestore/guard.js +5 -4
- package/dist/modules/firestore/guard.js.map +1 -1
- package/dist/modules/firestore/guards.d.ts +2 -2
- package/dist/modules/firestore/guards.d.ts.map +1 -1
- package/dist/modules/firestore/guards.js.map +1 -1
- package/dist/modules/firestore/index-guard.d.ts.map +1 -1
- package/dist/modules/firestore/index-guard.js +2 -1
- package/dist/modules/firestore/index-guard.js.map +1 -1
- package/dist/modules/firestore/path-guards.d.ts.map +1 -1
- package/dist/modules/firestore/path-guards.js +5 -4
- package/dist/modules/firestore/path-guards.js.map +1 -1
- package/dist/modules/firestore/storage-guards.d.ts.map +1 -1
- package/dist/modules/firestore/storage-guards.js +2 -1
- package/dist/modules/firestore/storage-guards.js.map +1 -1
- package/dist/modules/firestore/support.d.ts.map +1 -1
- package/dist/modules/firestore/support.js +2 -1
- package/dist/modules/firestore/support.js.map +1 -1
- package/dist/modules/firestore/test-paths.d.ts +3 -7
- package/dist/modules/firestore/test-paths.d.ts.map +1 -1
- package/dist/modules/firestore/test-paths.js +0 -5
- package/dist/modules/firestore/test-paths.js.map +1 -1
- package/dist/modules/frontend-actions/auth.d.ts.map +1 -1
- package/dist/modules/frontend-actions/auth.js +5 -5
- package/dist/modules/frontend-actions/auth.js.map +1 -1
- package/dist/modules/frontend-actions/callables.d.ts.map +1 -1
- package/dist/modules/frontend-actions/callables.js +2 -2
- package/dist/modules/frontend-actions/callables.js.map +1 -1
- package/dist/modules/frontend-actions/client.d.ts.map +1 -1
- package/dist/modules/frontend-actions/client.js +5 -7
- package/dist/modules/frontend-actions/client.js.map +1 -1
- package/dist/modules/frontend-actions/guards.d.ts +2 -2
- package/dist/modules/frontend-actions/guards.d.ts.map +1 -1
- package/dist/modules/frontend-actions/guards.js.map +1 -1
- package/dist/modules/frontend-reads/cache.d.ts +6 -2
- package/dist/modules/frontend-reads/cache.d.ts.map +1 -1
- package/dist/modules/frontend-reads/cache.js +7 -6
- package/dist/modules/frontend-reads/cache.js.map +1 -1
- package/dist/modules/frontend-reads/guards.d.ts +2 -2
- package/dist/modules/frontend-reads/guards.d.ts.map +1 -1
- package/dist/modules/frontend-reads/guards.js.map +1 -1
- package/dist/modules/frontend-reads/read-failures.js +4 -4
- package/dist/modules/frontend-reads/read-failures.js.map +1 -1
- package/dist/modules/frontend-reads/read-state-branches.d.ts.map +1 -1
- package/dist/modules/frontend-reads/read-state-branches.js +5 -0
- package/dist/modules/frontend-reads/read-state-branches.js.map +1 -1
- package/dist/modules/frontend-reads/shared.d.ts +1 -1
- package/dist/modules/frontend-reads/shared.d.ts.map +1 -1
- package/dist/modules/frontend-reads/shared.js +8 -8
- package/dist/modules/frontend-reads/shared.js.map +1 -1
- package/dist/modules/import-paths/analyzer.d.ts +68 -99
- package/dist/modules/import-paths/analyzer.d.ts.map +1 -1
- package/dist/modules/import-paths/analyzer.js +33 -51
- package/dist/modules/import-paths/analyzer.js.map +1 -1
- package/dist/modules/import-paths/application-data.d.ts.map +1 -1
- package/dist/modules/import-paths/application-data.js +2 -1
- package/dist/modules/import-paths/application-data.js.map +1 -1
- package/dist/modules/import-paths/entry-purity.d.ts.map +1 -1
- package/dist/modules/import-paths/entry-purity.js +6 -5
- package/dist/modules/import-paths/entry-purity.js.map +1 -1
- package/dist/modules/import-paths/guard.d.ts.map +1 -1
- package/dist/modules/import-paths/guard.js +4 -3
- package/dist/modules/import-paths/guard.js.map +1 -1
- package/dist/modules/import-paths/guards.d.ts +2 -2
- package/dist/modules/import-paths/guards.d.ts.map +1 -1
- package/dist/modules/import-paths/guards.js.map +1 -1
- package/dist/modules/import-paths/package-entries.d.ts.map +1 -1
- package/dist/modules/import-paths/package-entries.js +3 -2
- package/dist/modules/import-paths/package-entries.js.map +1 -1
- package/dist/modules/import-paths/package-imports.d.ts.map +1 -1
- package/dist/modules/import-paths/package-imports.js +3 -2
- package/dist/modules/import-paths/package-imports.js.map +1 -1
- package/dist/modules/repo/cross-root.d.ts.map +1 -1
- package/dist/modules/repo/cross-root.js +9 -8
- package/dist/modules/repo/cross-root.js.map +1 -1
- package/dist/modules/repo/document-drift.js +3 -3
- package/dist/modules/repo/document-drift.js.map +1 -1
- package/dist/modules/repo/guards.d.ts +4 -2
- package/dist/modules/repo/guards.d.ts.map +1 -1
- package/dist/modules/repo/guards.js +2 -0
- package/dist/modules/repo/guards.js.map +1 -1
- package/dist/modules/repo/installed-packages-agnostic.d.ts.map +1 -1
- package/dist/modules/repo/installed-packages-agnostic.js +5 -4
- package/dist/modules/repo/installed-packages-agnostic.js.map +1 -1
- package/dist/modules/repo/secret-bindings.d.ts.map +1 -1
- package/dist/modules/repo/secret-bindings.js +2 -1
- package/dist/modules/repo/secret-bindings.js.map +1 -1
- package/dist/modules/repo/shared-fakes.d.ts.map +1 -1
- package/dist/modules/repo/shared-fakes.js +5 -7
- package/dist/modules/repo/shared-fakes.js.map +1 -1
- package/dist/modules/repo/shell-safe.d.ts.map +1 -1
- package/dist/modules/repo/shell-safe.js +2 -1
- package/dist/modules/repo/shell-safe.js.map +1 -1
- package/dist/modules/repo/swallowed-rejections.d.ts +15 -0
- package/dist/modules/repo/swallowed-rejections.d.ts.map +1 -0
- package/dist/modules/repo/swallowed-rejections.js +117 -0
- package/dist/modules/repo/swallowed-rejections.js.map +1 -0
- package/dist/modules/repo/test-case-module-loads.d.ts.map +1 -1
- package/dist/modules/repo/test-case-module-loads.js +2 -1
- package/dist/modules/repo/test-case-module-loads.js.map +1 -1
- package/dist/modules/repo/test-timeouts.d.ts.map +1 -1
- package/dist/modules/repo/test-timeouts.js +4 -6
- package/dist/modules/repo/test-timeouts.js.map +1 -1
- package/dist/modules/repo/walker-read-failure.d.ts.map +1 -1
- package/dist/modules/repo/walker-read-failure.js +2 -1
- package/dist/modules/repo/walker-read-failure.js.map +1 -1
- package/dist/modules/ui/accessibility.d.ts +2 -0
- package/dist/modules/ui/accessibility.d.ts.map +1 -1
- package/dist/modules/ui/accessibility.js +53 -0
- package/dist/modules/ui/accessibility.js.map +1 -1
- package/dist/modules/ui/cascade.d.ts.map +1 -1
- package/dist/modules/ui/cascade.js +4 -3
- package/dist/modules/ui/cascade.js.map +1 -1
- package/dist/modules/ui/guards.d.ts +2 -2
- package/dist/modules/ui/guards.d.ts.map +1 -1
- package/dist/modules/ui/guards.js.map +1 -1
- package/dist/modules/ui/truncation.d.ts.map +1 -1
- package/dist/modules/ui/truncation.js +3 -3
- package/dist/modules/ui/truncation.js.map +1 -1
- package/dist/node/reports/reports.d.ts.map +1 -1
- package/dist/node/reports/reports.js +3 -1
- package/dist/node/reports/reports.js.map +1 -1
- package/dist/node/suite/register.d.ts.map +1 -1
- package/dist/node/suite/register.js +3 -3
- package/dist/node/suite/register.js.map +1 -1
- package/dist/node/tooling/cloud-checks.d.ts.map +1 -1
- package/dist/node/tooling/cloud-checks.js.map +1 -1
- package/dist/seed/seed-writer.d.ts +12 -30
- package/dist/seed/seed-writer.d.ts.map +1 -1
- package/dist/seed/seed-writer.js +3 -20
- package/dist/seed/seed-writer.js.map +1 -1
- package/dist/support/facts.d.ts +2 -0
- package/dist/support/facts.d.ts.map +1 -1
- package/dist/support/facts.js +9 -0
- package/dist/support/facts.js.map +1 -1
- package/dist/support/timeouts.d.ts +7 -0
- package/dist/support/timeouts.d.ts.map +1 -0
- package/dist/support/timeouts.js +7 -0
- package/dist/support/timeouts.js.map +1 -0
- package/dist/zod-shape/zod-shape.d.ts +26 -6
- package/dist/zod-shape/zod-shape.d.ts.map +1 -1
- package/dist/zod-shape/zod-shape.js +24 -12
- package/dist/zod-shape/zod-shape.js.map +1 -1
- package/package.json +2 -2
|
@@ -54,6 +54,7 @@ export interface AdminActionSurfaceFacts {
|
|
|
54
54
|
adminCheckers: readonly string[];
|
|
55
55
|
checkerReaders: readonly Reviewed[];
|
|
56
56
|
adminDeclarations: CallableDeclarationFacts;
|
|
57
|
+
clientDeclarations: CallableDeclarationFacts;
|
|
57
58
|
claimKeys: readonly string[];
|
|
58
59
|
adminHooks: readonly string[];
|
|
59
60
|
adminAreaRoots: readonly string[];
|
|
@@ -72,7 +73,7 @@ interface ClientAdminUse {
|
|
|
72
73
|
symbol: string;
|
|
73
74
|
detail: string;
|
|
74
75
|
}
|
|
75
|
-
export declare function clientAdminUses(file: FileView, facts: Pick<AdminActionSurfaceFacts, 'claimKeys' | 'adminHooks'>, declarationModuleOf: (spec: string) => string | null): ClientAdminUse[];
|
|
76
|
+
export declare function clientAdminUses(file: FileView, facts: Pick<AdminActionSurfaceFacts, 'claimKeys' | 'adminHooks'>, declarationModuleOf: (spec: string) => string | null, areaModuleOf?: (spec: string) => string | null): ClientAdminUse[];
|
|
76
77
|
export declare const adminActionSurfaceGuard: GenericGuardDefinition<AdminActionSurfaceFacts>;
|
|
77
78
|
export {};
|
|
78
79
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/modules/backend/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAA0C,KAAK,OAAO,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/modules/backend/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import { ownerOnly, reviewedAllowlist } from '../../shapes/shapes.js';
|
|
3
3
|
import { calleeName, forEachNode, lineOfNode } from '../../support/ast.js';
|
|
4
|
-
import { isText, namesProblem, objectProblem, pathProblem, reviewedProblems, takesNoFacts, textProblem, } from '../../support/facts.js';
|
|
4
|
+
import { importAliasesProblem, isText, namesProblem, objectProblem, pathProblem, reviewedProblems, takesNoFacts, textProblem, } from '../../support/facts.js';
|
|
5
5
|
import { MODULE_LOADS, moduleImports } from '../../support/imports.js';
|
|
6
6
|
import { aliasList, resolveSpecifier } from '../../support/resolve-specifier.js';
|
|
7
7
|
import { escapeRegExp, isUnder } from '../../support/text.js';
|
|
@@ -419,7 +419,7 @@ export function adminOnlyCallables(file, adminAuth) {
|
|
|
419
419
|
})
|
|
420
420
|
.map((callable) => callable.name);
|
|
421
421
|
}
|
|
422
|
-
export function clientAdminUses(file, facts, declarationModuleOf) {
|
|
422
|
+
export function clientAdminUses(file, facts, declarationModuleOf, areaModuleOf = () => null) {
|
|
423
423
|
const out = [];
|
|
424
424
|
const keys = new RegExp(`\\b(${facts.claimKeys.map(escapeRegExp).join('|')})\\b`);
|
|
425
425
|
for (const hit of adminClaimMatcher(facts.claimKeys)(file))
|
|
@@ -442,6 +442,17 @@ export function clientAdminUses(file, facts, declarationModuleOf) {
|
|
|
442
442
|
});
|
|
443
443
|
continue;
|
|
444
444
|
}
|
|
445
|
+
const area = site.typeOnly ? null : areaModuleOf(site.spec);
|
|
446
|
+
if (area) {
|
|
447
|
+
const names = site.named.filter((n) => !n.typeOnly).map((n) => n.imported);
|
|
448
|
+
for (const symbol of site.named.length ? names : ['*'])
|
|
449
|
+
out.push({
|
|
450
|
+
index,
|
|
451
|
+
symbol,
|
|
452
|
+
detail: `imports ${symbol} from the admin area ${area}`,
|
|
453
|
+
});
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
445
456
|
for (const name of site.named)
|
|
446
457
|
if (hooks.has(name.imported))
|
|
447
458
|
out.push({
|
|
@@ -478,10 +489,11 @@ export const adminActionSurfaceGuard = {
|
|
|
478
489
|
namesProblem(facts?.adminCheckers, 'adminCheckers', problems);
|
|
479
490
|
reviewedProblems(facts?.checkerReaders, 'checkerReaders', problems);
|
|
480
491
|
declarationFactProblems(facts?.adminDeclarations, 'adminDeclarations', problems);
|
|
492
|
+
declarationFactProblems(facts?.clientDeclarations, 'clientDeclarations', problems);
|
|
481
493
|
namesProblem(facts?.claimKeys, 'claimKeys', problems);
|
|
482
494
|
namesProblem(facts?.adminHooks, 'adminHooks', problems, { nonEmpty: false });
|
|
483
495
|
adminAreaProblems(facts, problems);
|
|
484
|
-
|
|
496
|
+
importAliasesProblem(facts?.importAliases, 'importAliases', problems);
|
|
485
497
|
serverZoneProblems(facts?.appServerZone, 'appServerZone', problems);
|
|
486
498
|
return problems;
|
|
487
499
|
},
|
|
@@ -494,10 +506,12 @@ export const adminActionSurfaceGuard = {
|
|
|
494
506
|
description: `The admin-only callables are every callable whose ${facts.adminAuth.call} calls all carry ` +
|
|
495
507
|
`${facts.adminAuth.option}, read from the Functions source each run. Inside a callable module, admin standing ` +
|
|
496
508
|
`is checked only through that auth call: ${facts.adminCheckers.join(', ')} is called only by the reviewed ` +
|
|
497
|
-
`readers. ${facts.adminDeclarations.modules.join(', ')} declares
|
|
498
|
-
`
|
|
499
|
-
`
|
|
500
|
-
|
|
509
|
+
`readers. ${facts.adminDeclarations.modules.join(', ')} declares only admin-only callables, and every admin-only ` +
|
|
510
|
+
`callable the client declares (${facts.clientDeclarations.modules.join(', ')}) is declared there; one with no ` +
|
|
511
|
+
`client declaration has no client caller. Outside the admin area (${facts.adminAreaRoots.join(', ')}) and the ` +
|
|
512
|
+
`admin-actions affordance (${facts.affordanceOwner}), client code never reads the admin claim, imports an admin ` +
|
|
513
|
+
'declaration, imports a module of the admin area, or imports an admin hook: an admin action there goes through ' +
|
|
514
|
+
'the affordance, and any other admin-standing read is a ' +
|
|
501
515
|
'reviewed entry ({ path, symbol?, why }). A reviewed reader or entry that no longer matches is stale.',
|
|
502
516
|
samples: {
|
|
503
517
|
flags: [
|
|
@@ -554,6 +568,14 @@ export const adminActionSurfaceGuard = {
|
|
|
554
568
|
});
|
|
555
569
|
const { declared, findings: declarationFindings } = readDeclarations(context, facts.adminDeclarations);
|
|
556
570
|
findings.push(...declarationFindings);
|
|
571
|
+
const clientRead = readDeclarations(context, {
|
|
572
|
+
...facts.clientDeclarations,
|
|
573
|
+
modules: facts.clientDeclarations.modules.filter((m) => !declarationModules.has(m)),
|
|
574
|
+
});
|
|
575
|
+
findings.push(...clientRead.findings);
|
|
576
|
+
const clientDeclared = new Set([...declared, ...clientRead.declared]
|
|
577
|
+
.map((d) => d.callable)
|
|
578
|
+
.filter((c) => c !== null));
|
|
557
579
|
const declaredNames = new Set();
|
|
558
580
|
for (const d of declared) {
|
|
559
581
|
if (d.callable === null)
|
|
@@ -567,10 +589,10 @@ export const adminActionSurfaceGuard = {
|
|
|
567
589
|
});
|
|
568
590
|
}
|
|
569
591
|
for (const [name, where] of adminCallables)
|
|
570
|
-
if (!declaredNames.has(name))
|
|
592
|
+
if (clientDeclared.has(name) && !declaredNames.has(name))
|
|
571
593
|
findings.push({
|
|
572
594
|
...where,
|
|
573
|
-
detail: `${name} is admin-only, but ${facts.adminDeclarations.modules.join(', ')}
|
|
595
|
+
detail: `${name} is admin-only, but the client declares it outside ${facts.adminDeclarations.modules.join(', ')}`,
|
|
574
596
|
});
|
|
575
597
|
for (const root of facts.adminAreaRoots)
|
|
576
598
|
if (!context.reader.exists(root))
|
|
@@ -590,9 +612,15 @@ export const adminActionSurfaceGuard = {
|
|
|
590
612
|
continue;
|
|
591
613
|
if (facts.adminAreaRoots.some((root) => isUnder(file.path, root)))
|
|
592
614
|
continue;
|
|
615
|
+
const resolve = (spec) => resolveSpecifier(context.reader, file.path, spec, aliases);
|
|
593
616
|
const uses = clientAdminUses(file, facts, (spec) => {
|
|
594
|
-
const resolved =
|
|
617
|
+
const resolved = resolve(spec);
|
|
595
618
|
return declarationModules.has(resolved) ? resolved : null;
|
|
619
|
+
}, (spec) => {
|
|
620
|
+
const resolved = resolve(spec);
|
|
621
|
+
return facts.adminAreaRoots.some((root) => isUnder(resolved, root))
|
|
622
|
+
? resolved
|
|
623
|
+
: null;
|
|
596
624
|
});
|
|
597
625
|
if (file.path === facts.affordanceOwner) {
|
|
598
626
|
ownerHolds ||= uses.length > 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/modules/backend/auth.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding, Guard, GuardContext } from '../../guard.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport type { FileView } from '../../reader/view.js';\nimport { ownerOnly, reviewedAllowlist, type Hit, type Matcher } from '../../shapes/shapes.js';\nimport { calleeName, forEachNode, lineOfNode } from '../../support/ast.js';\nimport {\n isText,\n namesProblem,\n objectProblem,\n pathProblem,\n reviewedProblems,\n takesNoFacts,\n textProblem,\n} from '../../support/facts.js';\nimport { MODULE_LOADS, moduleImports } from '../../support/imports.js';\nimport { aliasList, resolveSpecifier } from '../../support/resolve-specifier.js';\nimport { escapeRegExp, isUnder } from '../../support/text.js';\nimport {\n declarationFactProblems,\n readDeclarations,\n type CallableDeclarationFacts,\n} from '../frontend-actions/declarations.js';\nimport {\n inServerZone,\n serverZoneContext,\n serverZoneProblems,\n staleServerFolders,\n type ServerZone,\n} from './shared.js';\n\nconst FUNCTIONS_CODE: Scope = { roots: ['functions'], kinds: ['code'], tests: false };\n\nexport interface AdminClaimFacts {\n claimKeys: readonly string[];\n readers: readonly Reviewed[];\n appServerZone: ServerZone;\n}\n\nconst CLAIM_RECEIVER = String.raw`(?:[\\w$]*[Tt]oken|[\\w$]*[Cc]laims|decoded[\\w$]*)`;\n\nexport function adminClaimMatcher(claimKeys: readonly string[]): Matcher {\n const keys = claimKeys.map(escapeRegExp).join('|');\n const patterns = [\n new RegExp(String.raw`\\b${CLAIM_RECEIVER}\\s*(?:\\?\\.|\\.)\\s*(?:${keys})\\b`, 'g'),\n new RegExp(String.raw`\\b${CLAIM_RECEIVER}\\s*(?:\\?\\.)?\\s*\\[\\s*(['\"\\`])(?:${keys})\\1\\s*\\]`, 'g'),\n new RegExp(\n String.raw`\\{[^{}\\n]*\\b(?:${keys})\\b[^{}\\n]*\\}\\s*=\\s*[^;\\n]*${CLAIM_RECEIVER}\\b`,\n 'g',\n ),\n ];\n return (file) => {\n const hits: Hit[] = [];\n for (const re of patterns) {\n const g = new RegExp(re.source, re.flags);\n for (let m = g.exec(file.code); m; m = g.exec(file.code))\n hits.push({ index: m.index, detail: m[0].trim().slice(0, 80) });\n }\n return hits.sort((a, b) => a.index - b.index);\n };\n}\n\nexport const adminClaimGuard: GenericGuardDefinition<AdminClaimFacts> = {\n id: 'adminClaimRead',\n absentWhen: 'the app has no admin claim',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.claimKeys, 'claimKeys', problems);\n reviewedProblems(facts?.readers, 'readers', problems, { nonEmpty: true });\n serverZoneProblems(facts?.appServerZone, 'appServerZone', problems);\n return problems;\n },\n build(facts) {\n const guard = reviewedAllowlist({\n title: 'the admin claim is read only by its resolver',\n description:\n `No server module reads an admin claim (${facts.claimKeys.join(', ')}) off a token or claims payload — by member ` +\n 'access, bracket access, or destructuring — outside the reviewed readers. The claim is metadata and stays true ' +\n 'for up to an hour after a demotion, and anything signed from it outlives the revocation by its own lifetime. ' +\n \"Resolve admin standing through the resolver's authoritative read, failing closed on a read failure. Writing the \" +\n 'claim is not a read. A reviewed reader that no longer reads the claim is stale.',\n scope: {\n roots: ['functions', 'app'],\n optionalRoots: ['functions'],\n kinds: ['code'],\n tests: false,\n },\n match: adminClaimMatcher(facts.claimKeys),\n allowlist: facts.readers,\n samples: {\n flags: [\n `if (request.auth.token.${facts.claimKeys[0]} === true) return all;`,\n `const a = decoded?.['${facts.claimKeys[0]}'];`,\n `const { uid, ${facts.claimKeys[0]} = false } = ctx.token;`,\n ],\n passes: [\n `await auth.setCustomUserClaims(uid, { ${facts.claimKeys[0]}: true });\\nif (args.${facts.claimKeys[0]}) run();`,\n ],\n },\n });\n return [\n {\n ...guard,\n async run(context: GuardContext) {\n return [\n ...staleServerFolders(context, facts.appServerZone),\n ...(await guard.run(serverZoneContext(context, facts.appServerZone))),\n ];\n },\n },\n ];\n },\n};\n\nexport interface RequestOriginFacts {\n reader: string;\n}\n\nconst ORIGIN_READ = /\\brawRequest\\b|x-forwarded-for|\\breq\\s*\\.\\s*ip\\b/gi;\n\nexport const requestOriginGuard: GenericGuardDefinition<RequestOriginFacts> = {\n id: 'requestOrigin',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.reader, 'reader', problems);\n return problems;\n },\n build(facts) {\n return [\n ownerOnly({\n title: \"a request's origin is read in one place\",\n description: `A request's origin is read only in ${facts.reader}, which must still hold the read.`,\n scope: FUNCTIONS_CODE,\n match: (file) => {\n const re = new RegExp(ORIGIN_READ.source, ORIGIN_READ.flags);\n const hits: Hit[] = [];\n for (let m = re.exec(file.code); m; m = re.exec(file.code))\n hits.push({ index: m.index, detail: m[0] });\n return hits;\n },\n owners: [facts.reader],\n samples: {\n flags: [\n 'const ip = request.rawRequest?.ip ?? null;',\n \"const hops = headers['x-forwarded-for'];\",\n 'const caller = req.ip;',\n 'const { rawRequest } = request;',\n ],\n passes: ['const facts = { ip: context.ip };\\n// rawRequest is read only by the reader'],\n },\n }),\n ];\n },\n};\n\nexport type NoBlockingFunctionFacts = Record<string, never>;\n\nconst BLOCKING_MODULE = /^firebase-functions\\/(?:v2\\/)?identity$/;\nconst BLOCKING_BUILDERS = new Set(['beforeCreate', 'beforeSignIn', 'beforeEmail', 'beforeSms']);\n\nexport function blockingFunctionSites(file: FileView): Array<{ node: ts.Node; detail: string }> {\n const out: Array<{ node: ts.Node; detail: string }> = [];\n for (const { spec, node } of moduleImports(file.sourceFile, MODULE_LOADS))\n if (BLOCKING_MODULE.test(spec)) out.push({ node, detail: `imports ${spec}` });\n forEachNode(file.sourceFile, (node) => {\n if (\n ts.isCallExpression(node) &&\n ts.isPropertyAccessExpression(node.expression) &&\n BLOCKING_BUILDERS.has(node.expression.name.text)\n ) {\n out.push({ node, detail: `registers ${node.expression.name.text}` });\n }\n });\n return out;\n}\n\nexport const noBlockingFunctionGuard: GenericGuardDefinition<NoBlockingFunctionFacts> = {\n id: 'noAuthBlockingFunction',\n absentWhen: false,\n factProblems: takesNoFacts,\n build() {\n return [\n {\n title: 'no sign-in waits on a blocking function',\n description:\n 'No Functions source registers an Identity Platform blocking function (the identity module, or a v1 ' +\n 'beforeCreate / beforeSignIn / beforeEmail / beforeSms builder). Identity Platform refuses a sign-up or ' +\n 'sign-in whose blocking function has not answered within seconds, and a cold instance can take longer than ' +\n 'that to start, so a blocking function refuses members at random. Do the work after the fact instead.',\n run(context) {\n return context.files(FUNCTIONS_CODE).flatMap((file) =>\n blockingFunctionSites(file).map(({ node, detail }) => ({\n file: file.path,\n line: lineOfNode(file, node),\n detail,\n })),\n );\n },\n },\n ];\n },\n};\n\nexport interface AppCheckFacts {\n consumingFolders: readonly string[];\n adminAuth: { call: string; option: string };\n consumptionExempt: ReadonlyArray<{ callable: string; why: string }>;\n clientDeclarations: CallableDeclarationFacts;\n noClientDeclaration: ReadonlyArray<{ callable: string; why: string }>;\n}\n\ninterface Callable {\n name: string;\n node: ts.Node;\n options: ts.ObjectLiteralExpression | null;\n}\n\nconst isOnCall = (node: ts.Node): node is ts.CallExpression =>\n ts.isCallExpression(node) &&\n ts.isIdentifier(node.expression) &&\n node.expression.text === 'onCall';\n\nconst declaresTrue = (options: ts.ObjectLiteralExpression | null, key: string) =>\n !!options?.properties.some(\n (p) =>\n ts.isPropertyAssignment(p) &&\n p.name.getText().replace(/^['\"]|['\"]$/g, '') === key &&\n p.initializer.kind === ts.SyntaxKind.TrueKeyword,\n );\n\nexport function callablesOf(file: FileView): Callable[] {\n const sf = file.sourceFile;\n const optionsOf = (call: ts.CallExpression) =>\n call.arguments[0] && ts.isObjectLiteralExpression(call.arguments[0]) ? call.arguments[0] : null;\n const factories = new Map<string, ts.CallExpression>();\n const named = new Set<ts.CallExpression>();\n const out: Callable[] = [];\n forEachNode(sf, (node) => {\n if (ts.isFunctionDeclaration(node) && node.name && node.body) {\n forEachNode(node.body, (n) => {\n if (ts.isReturnStatement(n) && n.expression && isOnCall(n.expression))\n factories.set(node.name!.text, n.expression);\n });\n }\n });\n forEachNode(sf, (node) => {\n if (\n !ts.isVariableDeclaration(node) ||\n !ts.isIdentifier(node.name) ||\n !node.initializer ||\n !ts.isCallExpression(node.initializer)\n )\n return;\n const init: ts.CallExpression = node.initializer;\n if (isOnCall(init as ts.Node)) {\n named.add(init);\n out.push({ name: node.name.text, node: init, options: optionsOf(init) });\n } else if (ts.isIdentifier(init.expression) && factories.has(init.expression.text)) {\n const made = factories.get(init.expression.text)!;\n named.add(made);\n out.push({ name: node.name.text, node: init, options: optionsOf(made) });\n }\n });\n forEachNode(sf, (node) => {\n if (isOnCall(node) && !named.has(node))\n out.push({\n name: `(onCall at line ${lineOfNode(file, node)})`,\n node,\n options: optionsOf(node),\n });\n });\n return out;\n}\n\nexport function asksForAdmin(file: FileView, adminAuth: AppCheckFacts['adminAuth']): boolean {\n let found = false;\n forEachNode(file.sourceFile, (node) => {\n if (found || !ts.isCallExpression(node) || calleeName(node) !== adminAuth.call) return;\n found = node.arguments.some(\n (arg) =>\n ts.isObjectLiteralExpression(arg) &&\n arg.properties.some(\n (p) => p.name?.getText().replace(/^['\"]|['\"]$/g, '') === adminAuth.option,\n ),\n );\n });\n return found;\n}\n\nexport const appCheckGuard: GenericGuardDefinition<AppCheckFacts> = {\n id: 'appCheck',\n absentWhen: 'the app has no callable functions',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.consumingFolders, 'consumingFolders', problems, { nonEmpty: false });\n textProblem(facts?.adminAuth?.call, 'adminAuth.call', problems);\n textProblem(facts?.adminAuth?.option, 'adminAuth.option', problems);\n reviewedProblems(facts?.consumptionExempt, 'consumptionExempt', problems, { key: 'callable' });\n declarationFactProblems(facts?.clientDeclarations, 'clientDeclarations', problems);\n reviewedProblems(facts?.noClientDeclaration, 'noClientDeclaration', problems, {\n key: 'callable',\n });\n return problems;\n },\n build(facts) {\n const posture: Guard = {\n title: 'every callable declares its App Check posture',\n description:\n 'Every `onCall` opens with a literal options object (one this check cannot read fails, never passes) that ' +\n 'declares `enforceAppCheck: true`: attestation sits beneath auth and neither substitutes for the other. A ' +\n `callable in a consuming folder (${facts.consumingFolders.join(', ') || 'none declared'}), and every callable in a ` +\n `file whose ${facts.adminAuth.call} asks for ${facts.adminAuth.option}, also declares \\`consumeAppCheckToken: true\\`, ` +\n 'so its attestation token is spent instead of reusable for its whole lifetime. A callable that keeps the cached ' +\n 'token is a reviewed exemption with its why; an exemption whose callable is gone or now consumes is stale.',\n run(context) {\n const findings: Finding[] = [];\n const exempt = new Map(facts.consumptionExempt.map((e) => [e.callable, e]));\n const exemptSeen = new Set<string>();\n const foldersWithCallables = new Set<string>();\n let callables = 0;\n for (const file of context.files(FUNCTIONS_CODE)) {\n const list = callablesOf(file);\n if (!list.length) continue;\n callables += list.length;\n const folder = facts.consumingFolders.find((f) => isUnder(file.path, f));\n if (folder) foldersWithCallables.add(folder);\n const mustConsume = !!folder || asksForAdmin(file, facts.adminAuth);\n for (const callable of list) {\n const line = lineOfNode(file, callable.node);\n if (!callable.options) {\n findings.push({\n file: file.path,\n line,\n detail: `${callable.name}: the onCall options are not an object literal, so the posture cannot be read`,\n });\n continue;\n }\n if (!declaresTrue(callable.options, 'enforceAppCheck'))\n findings.push({\n file: file.path,\n line,\n detail: `${callable.name}: no enforceAppCheck: true`,\n });\n const consumes = declaresTrue(callable.options, 'consumeAppCheckToken');\n if (exempt.has(callable.name)) {\n exemptSeen.add(callable.name);\n if (consumes)\n findings.push({\n file: file.path,\n line,\n detail: `stale exemption: ${callable.name} now consumes its token`,\n });\n else if (!mustConsume)\n findings.push({\n file: file.path,\n line,\n detail: `stale exemption: ${callable.name} is not a consuming callable`,\n });\n } else if (mustConsume && !consumes) {\n findings.push({\n file: file.path,\n line,\n detail: `${callable.name}: no consumeAppCheckToken: true`,\n });\n }\n }\n }\n if (!callables)\n findings.push({\n file: '(functions)',\n detail: 'no onCall found, so the guard checks nothing',\n });\n for (const folder of facts.consumingFolders)\n if (!foldersWithCallables.has(folder))\n findings.push({ file: folder, detail: 'stale consuming folder: it holds no callable' });\n for (const name of exempt.keys())\n if (!exemptSeen.has(name))\n findings.push({\n file: '(consumptionExempt)',\n detail: `stale exemption: no callable is named ${name}`,\n });\n return findings;\n },\n };\n const client: Guard = {\n title: \"a consuming callable's client declaration presents a limited-use token\",\n description:\n 'Every callable whose options declare `consumeAppCheckToken: true` has a client declaration in ' +\n `${facts.clientDeclarations.modules.join(', ')} carrying \\`limitedUseAppCheck: true\\`, so the token the server ` +\n 'spends is a single-use one rather than the cached token every other call reuses. A declaration carrying it names ' +\n 'a callable that consumes: one that names no callable, or a callable that keeps the cached token (an exempt one ' +\n 'included), mints a token per call for nothing. A consuming callable no client calls is a reviewed entry with ' +\n 'its why; an entry that is no longer a consuming callable, or that a declaration now names, is stale.',\n run(context) {\n const { declared, findings } = readDeclarations(context, facts.clientDeclarations);\n const servers = new Map<string, { consumes: boolean; file: string; line: number }>();\n for (const file of context.files(FUNCTIONS_CODE)) {\n for (const callable of callablesOf(file)) {\n servers.set(callable.name, {\n consumes: declaresTrue(callable.options, 'consumeAppCheckToken'),\n file: file.path,\n line: lineOfNode(file, callable.node),\n });\n }\n }\n if (!servers.size)\n findings.push({\n file: '(functions)',\n detail: 'no onCall found, so the guard checks nothing',\n });\n const byName = new Map(\n declared.filter((d) => d.callable !== null).map((d) => [d.callable!, d]),\n );\n const exempt = new Set(facts.consumptionExempt.map((e) => e.callable));\n const undeclared = new Set(facts.noClientDeclaration.map((e) => e.callable));\n for (const [name, server] of servers) {\n if (!server.consumes) continue;\n const declaration = byName.get(name);\n if (!declaration) {\n if (!undeclared.has(name))\n findings.push({\n file: server.file,\n line: server.line,\n detail: `${name} consumes its token, but no client declaration names it`,\n });\n } else if (!declaration.limitedUse) {\n findings.push({\n file: declaration.file,\n line: declaration.line,\n detail: `${declaration.hook} declares ${name}, which consumes its token, without limitedUseAppCheck: true`,\n });\n }\n }\n for (const declaration of declared) {\n if (!declaration.limitedUse || declaration.callable === null) continue;\n const server = servers.get(declaration.callable);\n const where = { file: declaration.file, line: declaration.line };\n if (!server)\n findings.push({\n ...where,\n detail: `${declaration.hook} declares ${declaration.callable} limited-use, but no callable of that name exists`,\n });\n else if (exempt.has(declaration.callable))\n findings.push({\n ...where,\n detail: `${declaration.hook} declares ${declaration.callable} limited-use, but it is exempt from consumption`,\n });\n else if (!server.consumes)\n findings.push({\n ...where,\n detail: `${declaration.hook} declares ${declaration.callable} limited-use, but it does not consume its token`,\n });\n }\n for (const name of undeclared) {\n if (byName.has(name))\n findings.push({\n file: '(noClientDeclaration)',\n detail: `stale entry: a client declaration names ${name} now`,\n });\n else if (!servers.get(name)?.consumes)\n findings.push({\n file: '(noClientDeclaration)',\n detail: `stale entry: ${name} is not a consuming callable`,\n });\n }\n return findings;\n },\n };\n return [posture, client];\n },\n};\n\nexport interface AdminActionSurfaceFacts {\n adminAuth: { call: string; option: string };\n adminCheckers: readonly string[];\n checkerReaders: readonly Reviewed[];\n adminDeclarations: CallableDeclarationFacts;\n claimKeys: readonly string[];\n adminHooks: readonly string[];\n adminAreaRoots: readonly string[];\n affordanceOwner: string;\n reviewed: ReadonlyArray<{ path: string; symbol?: string; why: string }>;\n importAliases: Readonly<Record<string, string>>;\n appServerZone: ServerZone;\n}\n\nconst APP_CLIENT_CODE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\n\nfunction authCallsIn(root: ts.Node, adminAuth: AdminActionSurfaceFacts['adminAuth']) {\n const calls: Array<{ admin: boolean }> = [];\n forEachNode(root, (node) => {\n if (!ts.isCallExpression(node) || calleeName(node) !== adminAuth.call) return;\n calls.push({\n admin: node.arguments.some(\n (arg) =>\n ts.isObjectLiteralExpression(arg) &&\n arg.properties.some(\n (p) =>\n p.name?.getText().replace(/^['\"]|['\"]$/g, '') === adminAuth.option &&\n !(ts.isPropertyAssignment(p) && isOffLiteral(p.initializer)),\n ),\n ),\n });\n });\n return calls;\n}\n\nconst isOffLiteral = (value: ts.Expression): boolean =>\n value.kind === ts.SyntaxKind.FalseKeyword ||\n value.kind === ts.SyntaxKind.NullKeyword ||\n (ts.isIdentifier(value) && value.text === 'undefined');\n\nexport function adminOnlyCallables(\n file: FileView,\n adminAuth: AdminActionSurfaceFacts['adminAuth'],\n): string[] {\n const moduleCalls = authCallsIn(file.sourceFile, adminAuth);\n return callablesOf(file)\n .filter((callable) => {\n const own = authCallsIn(callable.node, adminAuth);\n const calls = own.length ? own : moduleCalls;\n return calls.length > 0 && calls.every((c) => c.admin);\n })\n .map((callable) => callable.name);\n}\n\ninterface ClientAdminUse {\n index: number;\n symbol: string;\n detail: string;\n}\n\nexport function clientAdminUses(\n file: FileView,\n facts: Pick<AdminActionSurfaceFacts, 'claimKeys' | 'adminHooks'>,\n declarationModuleOf: (spec: string) => string | null,\n): ClientAdminUse[] {\n const out: ClientAdminUse[] = [];\n const keys = new RegExp(`\\\\b(${facts.claimKeys.map(escapeRegExp).join('|')})\\\\b`);\n for (const hit of adminClaimMatcher(facts.claimKeys)(file))\n out.push({\n index: hit.index,\n symbol: keys.exec(hit.detail ?? '')?.[1] ?? '',\n detail: `reads the admin claim (${hit.detail})`,\n });\n const hooks = new Set(facts.adminHooks);\n for (const site of moduleImports(file.sourceFile, MODULE_LOADS)) {\n const index = site.node.getStart(file.sourceFile);\n const module = declarationModuleOf(site.spec);\n if (module) {\n const names = site.named.map((n) => n.imported);\n for (const symbol of names.length ? names : ['*'])\n out.push({\n index,\n symbol,\n detail: `imports ${symbol} from the admin declarations ${module}`,\n });\n continue;\n }\n for (const name of site.named)\n if (hooks.has(name.imported))\n out.push({\n index,\n symbol: name.imported,\n detail: `imports the admin hook ${name.imported}`,\n });\n }\n return out.sort((a, b) => a.index - b.index);\n}\n\nfunction adminAreaProblems(facts: AdminActionSurfaceFacts | undefined, problems: string[]): void {\n if (!Array.isArray(facts?.adminAreaRoots) || !facts.adminAreaRoots.length)\n problems.push('adminAreaRoots is missing');\n else facts.adminAreaRoots.forEach((r, i) => pathProblem(r, `adminAreaRoots[${i}]`, problems));\n pathProblem(facts?.affordanceOwner, 'affordanceOwner', problems);\n reviewedProblems(facts?.reviewed, 'reviewed', problems, {\n id: (e) =>\n typeof e.path === 'string' ? `${e.path}${isText(e.symbol) ? ` ${e.symbol}` : ''}` : undefined,\n extra(entry, label) {\n if (entry.symbol !== undefined && !isText(entry.symbol))\n problems.push(`${label}'s symbol is empty`);\n },\n });\n}\n\nexport const adminActionSurfaceGuard: GenericGuardDefinition<AdminActionSurfaceFacts> = {\n id: 'adminActionSurface',\n absentWhen: 'the app has no admin actions',\n factProblems(facts) {\n const problems: string[] = [];\n if (objectProblem(facts?.adminAuth, 'adminAuth', problems)) {\n textProblem(facts.adminAuth.call, 'adminAuth.call', problems);\n textProblem(facts.adminAuth.option, 'adminAuth.option', problems);\n }\n namesProblem(facts?.adminCheckers, 'adminCheckers', problems);\n reviewedProblems(facts?.checkerReaders, 'checkerReaders', problems);\n declarationFactProblems(facts?.adminDeclarations, 'adminDeclarations', problems);\n namesProblem(facts?.claimKeys, 'claimKeys', problems);\n namesProblem(facts?.adminHooks, 'adminHooks', problems, { nonEmpty: false });\n adminAreaProblems(facts, problems);\n objectProblem(facts?.importAliases, 'importAliases', problems);\n serverZoneProblems(facts?.appServerZone, 'appServerZone', problems);\n return problems;\n },\n build(facts) {\n const declarationModules = new Set(facts.adminDeclarations.modules);\n const probePath = `${facts.affordanceOwner.slice(0, facts.affordanceOwner.lastIndexOf('/') + 1)}probe.tsx`;\n return [\n {\n title: 'admin actions outside the admin area go through the admin-actions affordance',\n description:\n `The admin-only callables are every callable whose ${facts.adminAuth.call} calls all carry ` +\n `${facts.adminAuth.option}, read from the Functions source each run. Inside a callable module, admin standing ` +\n `is checked only through that auth call: ${facts.adminCheckers.join(', ')} is called only by the reviewed ` +\n `readers. ${facts.adminDeclarations.modules.join(', ')} declares exactly the admin-only callables, no more and ` +\n `no fewer. Outside the admin area (${facts.adminAreaRoots.join(', ')}) and the admin-actions affordance ` +\n `(${facts.affordanceOwner}), client code never reads the admin claim, imports an admin declaration, or imports ` +\n 'an admin hook: an admin action there goes through the affordance, and any other admin-standing read is a ' +\n 'reviewed entry ({ path, symbol?, why }). A reviewed reader or entry that no longer matches is stale.',\n samples: {\n flags: [\n { path: probePath, text: `if (claims?.${facts.claimKeys[0]}) show();` },\n ...facts.adminHooks\n .slice(0, 1)\n .map((hook) => ({ path: probePath, text: `import { ${hook} } from './hooks';` })),\n ],\n passes: [\n { path: probePath, text: `const label = '${facts.claimKeys[0]}';` },\n { path: probePath, text: \"import { useRows } from './hooks';\" },\n ],\n probe: (view) => clientAdminUses(view, facts, () => null),\n },\n run(context) {\n const findings: Finding[] = [];\n const adminCallables = new Map<string, { file: string; line: number }>();\n const readers = new Map(facts.checkerReaders.map((r) => [r.path, false]));\n const checkers = new Set(facts.adminCheckers);\n for (const file of context.files(FUNCTIONS_CODE)) {\n const callables = callablesOf(file);\n if (!callables.length) continue;\n for (const name of adminOnlyCallables(file, facts.adminAuth)) {\n const callable = callables.find((c) => c.name === name)!;\n adminCallables.set(name, { file: file.path, line: lineOfNode(file, callable.node) });\n }\n forEachNode(file.sourceFile, (node) => {\n if (!ts.isCallExpression(node)) return;\n const name = calleeName(node);\n if (!name || !checkers.has(name)) return;\n if (readers.has(file.path)) readers.set(file.path, true);\n else\n findings.push({\n file: file.path,\n line: lineOfNode(file, node),\n detail: `a callable module checks admin standing through ${name} instead of its ${facts.adminAuth.call}`,\n });\n });\n }\n for (const [path, used] of readers)\n if (!used)\n findings.push({\n file: path,\n detail: 'stale reader: it no longer calls an admin checker in a callable module',\n });\n if (!adminCallables.size)\n findings.push({\n file: '(functions)',\n detail: `no callable asks ${facts.adminAuth.call} for ${facts.adminAuth.option}, so no admin-only callable was found`,\n });\n\n const { declared, findings: declarationFindings } = readDeclarations(\n context,\n facts.adminDeclarations,\n );\n findings.push(...declarationFindings);\n const declaredNames = new Set<string>();\n for (const d of declared) {\n if (d.callable === null) continue;\n declaredNames.add(d.callable);\n if (!adminCallables.has(d.callable))\n findings.push({\n file: d.file,\n line: d.line,\n detail: `${d.hook} declares ${d.callable}, which is not an admin-only callable`,\n });\n }\n for (const [name, where] of adminCallables)\n if (!declaredNames.has(name))\n findings.push({\n ...where,\n detail: `${name} is admin-only, but ${facts.adminDeclarations.modules.join(', ')} does not declare it`,\n });\n\n for (const root of facts.adminAreaRoots)\n if (!context.reader.exists(root))\n findings.push({ file: root, detail: 'stale admin-area root: it no longer exists' });\n const ownerExists = context.reader.exists(facts.affordanceOwner);\n if (!ownerExists)\n findings.push({\n file: facts.affordanceOwner,\n detail: 'the admin-actions affordance no longer exists',\n });\n const aliases = aliasList(facts.importAliases);\n const reviewedKey = (e: { path: string; symbol?: string }) =>\n `${e.path}${e.symbol ? ` ${e.symbol}` : ''}`;\n const reviewedSeen = new Set<string>();\n let ownerHolds = false;\n for (const file of context.files(APP_CLIENT_CODE)) {\n if (inServerZone(file, facts.appServerZone)) continue;\n if (facts.adminAreaRoots.some((root) => isUnder(file.path, root))) continue;\n const uses = clientAdminUses(file, facts, (spec) => {\n const resolved = resolveSpecifier(context.reader, file.path, spec, aliases);\n return declarationModules.has(resolved) ? resolved : null;\n });\n if (file.path === facts.affordanceOwner) {\n ownerHolds ||= uses.length > 0;\n continue;\n }\n for (const use of uses) {\n const entry = facts.reviewed.find(\n (e) => e.path === file.path && (e.symbol === undefined || e.symbol === use.symbol),\n );\n if (entry) reviewedSeen.add(reviewedKey(entry));\n else\n findings.push({\n file: file.path,\n line: file.lineOf(use.index),\n detail: `outside the admin area: ${use.detail}`,\n });\n }\n }\n if (ownerExists && !ownerHolds)\n findings.push({\n file: facts.affordanceOwner,\n detail:\n 'stale affordance owner: it reads no admin standing and imports no admin declaration or hook',\n });\n for (const entry of facts.reviewed)\n if (!reviewedSeen.has(reviewedKey(entry)))\n findings.push({\n file: entry.path,\n detail: `stale entry: it no longer reads admin standing${entry.symbol ? ` through ${entry.symbol}` : ''}`,\n });\n return findings;\n },\n },\n ];\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/modules/backend/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAM5B,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAA0B,MAAM,wBAAwB,CAAC;AAC9F,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EACL,oBAAoB,EACpB,MAAM,EACN,YAAY,EACZ,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EACL,uBAAuB,EACvB,gBAAgB,GAEjB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GAEnB,MAAM,aAAa,CAAC;AAErB,MAAM,cAAc,GAAU,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAQtF,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAA,kDAAkD,CAAC;AAEpF,MAAM,UAAU,iBAAiB,CAAC,SAA4B;IAC5D,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG;QACf,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,KAAK,cAAc,uBAAuB,IAAI,KAAK,EAAE,GAAG,CAAC;QAC9E,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,KAAK,cAAc,kCAAkC,IAAI,UAAU,EAAE,GAAG,CAAC;QAC9F,IAAI,MAAM,CACR,MAAM,CAAC,GAAG,CAAA,kBAAkB,IAAI,8BAA8B,cAAc,IAAI,EAChF,GAAG,CACJ;KACF,CAAC;IACF,OAAO,CAAC,IAAI,EAAE,EAAE;QACd,MAAM,IAAI,GAAU,EAAE,CAAC;QACvB,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;YAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;gBACtD,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAA4C;IACtE,EAAE,EAAE,gBAAgB;IACpB,UAAU,EAAE,4BAA4B;IACxC,YAAY,CAAC,KAAK;QAChB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QACtD,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC;QACpE,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,KAAK,CAAC,KAAK;QACT,MAAM,KAAK,GAAG,iBAAiB,CAAC;YAC9B,KAAK,EAAE,8CAA8C;YACrD,WAAW,EACT,0CAA0C,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,8CAA8C;gBAClH,gHAAgH;gBAChH,+GAA+G;gBAC/G,kHAAkH;gBAClH,iFAAiF;YACnF,KAAK,EAAE;gBACL,KAAK,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC;gBAC3B,aAAa,EAAE,CAAC,WAAW,CAAC;gBAC5B,KAAK,EAAE,CAAC,MAAM,CAAC;gBACf,KAAK,EAAE,KAAK;aACb;YACD,KAAK,EAAE,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC;YACzC,SAAS,EAAE,KAAK,CAAC,OAAO;YACxB,OAAO,EAAE;gBACP,KAAK,EAAE;oBACL,0BAA0B,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,wBAAwB;oBACpE,wBAAwB,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;oBAC/C,gBAAgB,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,yBAAyB;iBAC5D;gBACD,MAAM,EAAE;oBACN,yCAAyC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,wBAAwB,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU;iBAChH;aACF;SACF,CAAC,CAAC;QACH,OAAO;YACL;gBACE,GAAG,KAAK;gBACR,KAAK,CAAC,GAAG,CAAC,OAAqB;oBAC7B,OAAO;wBACL,GAAG,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC;wBACnD,GAAG,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;qBACtE,CAAC;gBACJ,CAAC;aACF;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAMF,MAAM,WAAW,GAAG,oDAAoD,CAAC;AAEzE,MAAM,CAAC,MAAM,kBAAkB,GAA+C;IAC5E,EAAE,EAAE,eAAe;IACnB,UAAU,EAAE,KAAK;IACjB,YAAY,CAAC,KAAK;QAChB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC/C,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,KAAK,CAAC,KAAK;QACT,OAAO;YACL,SAAS,CAAC;gBACR,KAAK,EAAE,yCAAyC;gBAChD,WAAW,EAAE,sCAAsC,KAAK,CAAC,MAAM,mCAAmC;gBAClG,KAAK,EAAE,cAAc;gBACrB,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE;oBACd,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;oBAC7D,MAAM,IAAI,GAAU,EAAE,CAAC;oBACvB,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;wBACxD,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC9C,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;gBACtB,OAAO,EAAE;oBACP,KAAK,EAAE;wBACL,4CAA4C;wBAC5C,0CAA0C;wBAC1C,wBAAwB;wBACxB,iCAAiC;qBAClC;oBACD,MAAM,EAAE,CAAC,6EAA6E,CAAC;iBACxF;aACF,CAAC;SACH,CAAC;IACJ,CAAC;CACF,CAAC;AAIF,MAAM,eAAe,GAAG,yCAAyC,CAAC;AAClE,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC;AAEhG,MAAM,UAAU,qBAAqB,CAAC,IAAc;IAClD,MAAM,GAAG,GAA6C,EAAE,CAAC;IACzD,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC;QACvE,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,IAAI,EAAE,EAAE,CAAC,CAAC;IAChF,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE;QACpC,IACE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;YACzB,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,CAAC;YAC9C,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAChD,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvE,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAoD;IACtF,EAAE,EAAE,wBAAwB;IAC5B,UAAU,EAAE,KAAK;IACjB,YAAY,EAAE,YAAY;IAC1B,KAAK;QACH,OAAO;YACL;gBACE,KAAK,EAAE,yCAAyC;gBAChD,WAAW,EACT,qGAAqG;oBACrG,yGAAyG;oBACzG,4GAA4G;oBAC5G,sGAAsG;gBACxG,GAAG,CAAC,OAAO;oBACT,OAAO,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACpD,qBAAqB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;wBACrD,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC;wBAC5B,MAAM;qBACP,CAAC,CAAC,CACJ,CAAC;gBACJ,CAAC;aACF;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAgBF,MAAM,QAAQ,GAAG,CAAC,IAAa,EAA6B,EAAE,CAC5D,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;IACzB,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,QAAQ,CAAC;AAEpC,MAAM,YAAY,GAAG,CAAC,OAA0C,EAAE,GAAW,EAAE,EAAE,CAC/E,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,CACxB,CAAC,CAAC,EAAE,EAAE,CACJ,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,KAAK,GAAG;IACpD,CAAC,CAAC,WAAW,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW,CACnD,CAAC;AAEJ,MAAM,UAAU,WAAW,CAAC,IAAc;IACxC,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;IAC3B,MAAM,SAAS,GAAG,CAAC,IAAuB,EAAE,EAAE,CAC5C,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClG,MAAM,SAAS,GAAG,IAAI,GAAG,EAA6B,CAAC;IACvD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC3C,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;QACvB,IAAI,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7D,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;gBAC3B,IAAI,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;oBACnE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAK,CAAC,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;YACjD,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IACH,WAAW,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;QACvB,IACE,CAAC,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC;YAC/B,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YAC3B,CAAC,IAAI,CAAC,WAAW;YACjB,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC;YAEtC,OAAO;QACT,MAAM,IAAI,GAAsB,IAAI,CAAC,WAAW,CAAC;QACjD,IAAI,QAAQ,CAAC,IAAe,CAAC,EAAE,CAAC;YAC9B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;aAAM,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACnF,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC;YAClD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC,CAAC,CAAC;IACH,WAAW,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;QACvB,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YACpC,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,mBAAmB,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG;gBAClD,IAAI;gBACJ,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC;aACzB,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAc,EAAE,SAAqC;IAChF,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE;QACpC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,IAAI;YAAE,OAAO;QACvF,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CACzB,CAAC,GAAG,EAAE,EAAE,CACN,EAAE,CAAC,yBAAyB,CAAC,GAAG,CAAC;YACjC,GAAG,CAAC,UAAU,CAAC,IAAI,CACjB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,KAAK,SAAS,CAAC,MAAM,CAC1E,CACJ,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAA0C;IAClE,EAAE,EAAE,UAAU;IACd,UAAU,EAAE,mCAAmC;IAC/C,YAAY,CAAC,KAAK;QAChB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,YAAY,CAAC,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACzF,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;QAChE,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QACpE,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/F,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,QAAQ,CAAC,CAAC;QACnF,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,QAAQ,EAAE;YAC5E,GAAG,EAAE,UAAU;SAChB,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,KAAK,CAAC,KAAK;QACT,MAAM,OAAO,GAAU;YACrB,KAAK,EAAE,+CAA+C;YACtD,WAAW,EACT,2GAA2G;gBAC3G,2GAA2G;gBAC3G,mCAAmC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,eAAe,6BAA6B;gBACpH,cAAc,KAAK,CAAC,SAAS,CAAC,IAAI,aAAa,KAAK,CAAC,SAAS,CAAC,MAAM,kDAAkD;gBACvH,iHAAiH;gBACjH,2GAA2G;YAC7G,GAAG,CAAC,OAAO;gBACT,MAAM,QAAQ,GAAc,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5E,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;gBACrC,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAU,CAAC;gBAC/C,IAAI,SAAS,GAAG,CAAC,CAAC;gBAClB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;oBACjD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;oBAC/B,IAAI,CAAC,IAAI,CAAC,MAAM;wBAAE,SAAS;oBAC3B,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC;oBACzB,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;oBACzE,IAAI,MAAM;wBAAE,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBAC7C,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,IAAI,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;oBACpE,KAAK,MAAM,QAAQ,IAAI,IAAI,EAAE,CAAC;wBAC5B,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;wBAC7C,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;4BACtB,QAAQ,CAAC,IAAI,CAAC;gCACZ,IAAI,EAAE,IAAI,CAAC,IAAI;gCACf,IAAI;gCACJ,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,+EAA+E;6BACxG,CAAC,CAAC;4BACH,SAAS;wBACX,CAAC;wBACD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;4BACpD,QAAQ,CAAC,IAAI,CAAC;gCACZ,IAAI,EAAE,IAAI,CAAC,IAAI;gCACf,IAAI;gCACJ,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,4BAA4B;6BACrD,CAAC,CAAC;wBACL,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;wBACxE,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;4BAC9B,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;4BAC9B,IAAI,QAAQ;gCACV,QAAQ,CAAC,IAAI,CAAC;oCACZ,IAAI,EAAE,IAAI,CAAC,IAAI;oCACf,IAAI;oCACJ,MAAM,EAAE,oBAAoB,QAAQ,CAAC,IAAI,yBAAyB;iCACnE,CAAC,CAAC;iCACA,IAAI,CAAC,WAAW;gCACnB,QAAQ,CAAC,IAAI,CAAC;oCACZ,IAAI,EAAE,IAAI,CAAC,IAAI;oCACf,IAAI;oCACJ,MAAM,EAAE,oBAAoB,QAAQ,CAAC,IAAI,8BAA8B;iCACxE,CAAC,CAAC;wBACP,CAAC;6BAAM,IAAI,WAAW,IAAI,CAAC,QAAQ,EAAE,CAAC;4BACpC,QAAQ,CAAC,IAAI,CAAC;gCACZ,IAAI,EAAE,IAAI,CAAC,IAAI;gCACf,IAAI;gCACJ,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,iCAAiC;6BAC1D,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,IAAI,CAAC,SAAS;oBACZ,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,aAAa;wBACnB,MAAM,EAAE,8CAA8C;qBACvD,CAAC,CAAC;gBACL,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,gBAAgB;oBACzC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC;wBACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,8CAA8C,EAAE,CAAC,CAAC;gBAC5F,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE;oBAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;wBACvB,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,qBAAqB;4BAC3B,MAAM,EAAE,yCAAyC,IAAI,EAAE;yBACxD,CAAC,CAAC;gBACP,OAAO,QAAQ,CAAC;YAClB,CAAC;SACF,CAAC;QACF,MAAM,MAAM,GAAU;YACpB,KAAK,EAAE,wEAAwE;YAC/E,WAAW,EACT,gGAAgG;gBAChG,GAAG,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,kEAAkE;gBAChH,mHAAmH;gBACnH,iHAAiH;gBACjH,+GAA+G;gBAC/G,sGAAsG;YACxG,GAAG,CAAC,OAAO;gBACT,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;gBACnF,MAAM,OAAO,GAAG,IAAI,GAAG,EAA6D,CAAC;gBACrF,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;oBACjD,KAAK,MAAM,QAAQ,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;wBACzC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE;4BACzB,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;4BAChE,IAAI,EAAE,IAAI,CAAC,IAAI;4BACf,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;yBACtC,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBACD,IAAI,CAAC,OAAO,CAAC,IAAI;oBACf,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,aAAa;wBACnB,MAAM,EAAE,8CAA8C;qBACvD,CAAC,CAAC;gBACL,MAAM,MAAM,GAAG,IAAI,GAAG,CACpB,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAS,EAAE,CAAC,CAAC,CAAC,CACzE,CAAC;gBACF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACvE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC7E,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;oBACrC,IAAI,CAAC,MAAM,CAAC,QAAQ;wBAAE,SAAS;oBAC/B,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACrC,IAAI,CAAC,WAAW,EAAE,CAAC;wBACjB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;4BACvB,QAAQ,CAAC,IAAI,CAAC;gCACZ,IAAI,EAAE,MAAM,CAAC,IAAI;gCACjB,IAAI,EAAE,MAAM,CAAC,IAAI;gCACjB,MAAM,EAAE,GAAG,IAAI,yDAAyD;6BACzE,CAAC,CAAC;oBACP,CAAC;yBAAM,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC;wBACnC,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,WAAW,CAAC,IAAI;4BACtB,IAAI,EAAE,WAAW,CAAC,IAAI;4BACtB,MAAM,EAAE,GAAG,WAAW,CAAC,IAAI,aAAa,IAAI,8DAA8D;yBAC3G,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBACD,KAAK,MAAM,WAAW,IAAI,QAAQ,EAAE,CAAC;oBACnC,IAAI,CAAC,WAAW,CAAC,UAAU,IAAI,WAAW,CAAC,QAAQ,KAAK,IAAI;wBAAE,SAAS;oBACvE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;oBACjD,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;oBACjE,IAAI,CAAC,MAAM;wBACT,QAAQ,CAAC,IAAI,CAAC;4BACZ,GAAG,KAAK;4BACR,MAAM,EAAE,GAAG,WAAW,CAAC,IAAI,aAAa,WAAW,CAAC,QAAQ,mDAAmD;yBAChH,CAAC,CAAC;yBACA,IAAI,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC;wBACvC,QAAQ,CAAC,IAAI,CAAC;4BACZ,GAAG,KAAK;4BACR,MAAM,EAAE,GAAG,WAAW,CAAC,IAAI,aAAa,WAAW,CAAC,QAAQ,iDAAiD;yBAC9G,CAAC,CAAC;yBACA,IAAI,CAAC,MAAM,CAAC,QAAQ;wBACvB,QAAQ,CAAC,IAAI,CAAC;4BACZ,GAAG,KAAK;4BACR,MAAM,EAAE,GAAG,WAAW,CAAC,IAAI,aAAa,WAAW,CAAC,QAAQ,iDAAiD;yBAC9G,CAAC,CAAC;gBACP,CAAC;gBACD,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;oBAC9B,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;wBAClB,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,uBAAuB;4BAC7B,MAAM,EAAE,2CAA2C,IAAI,MAAM;yBAC9D,CAAC,CAAC;yBACA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ;wBACnC,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,uBAAuB;4BAC7B,MAAM,EAAE,gBAAgB,IAAI,8BAA8B;yBAC3D,CAAC,CAAC;gBACP,CAAC;gBACD,OAAO,QAAQ,CAAC;YAClB,CAAC;SACF,CAAC;QACF,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3B,CAAC;CACF,CAAC;AAiBF,MAAM,eAAe,GAAU,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAEjF,SAAS,WAAW,CAAC,IAAa,EAAE,SAA+C;IACjF,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,WAAW,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;QACzB,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,IAAI;YAAE,OAAO;QAC9E,KAAK,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CACxB,CAAC,GAAG,EAAE,EAAE,CACN,EAAE,CAAC,yBAAyB,CAAC,GAAG,CAAC;gBACjC,GAAG,CAAC,UAAU,CAAC,IAAI,CACjB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,KAAK,SAAS,CAAC,MAAM;oBAClE,CAAC,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAC/D,CACJ;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAW,EAAE,CACrD,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,YAAY;IACzC,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW;IACxC,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;AAEzD,MAAM,UAAU,kBAAkB,CAChC,IAAc,EACd,SAA+C;IAE/C,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAC5D,OAAO,WAAW,CAAC,IAAI,CAAC;SACrB,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QACnB,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;QAC7C,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACzD,CAAC,CAAC;SACD,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAQD,MAAM,UAAU,eAAe,CAC7B,IAAc,EACd,KAAgE,EAChE,mBAAoD,EACpD,eAAgD,GAAG,EAAE,CAAC,IAAI;IAE1D,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClF,KAAK,MAAM,GAAG,IAAI,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;QACxD,GAAG,CAAC,IAAI,CAAC;YACP,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE;YAC9C,MAAM,EAAE,0BAA0B,GAAG,CAAC,MAAM,GAAG;SAChD,CAAC,CAAC;IACL,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,CAAC;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAChD,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;gBAC/C,GAAG,CAAC,IAAI,CAAC;oBACP,KAAK;oBACL,MAAM;oBACN,MAAM,EAAE,WAAW,MAAM,gCAAgC,MAAM,EAAE;iBAClE,CAAC,CAAC;YACL,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC3E,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;gBACpD,GAAG,CAAC,IAAI,CAAC;oBACP,KAAK;oBACL,MAAM;oBACN,MAAM,EAAE,WAAW,MAAM,wBAAwB,IAAI,EAAE;iBACxD,CAAC,CAAC;YACL,SAAS;QACX,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK;YAC3B,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAC1B,GAAG,CAAC,IAAI,CAAC;oBACP,KAAK;oBACL,MAAM,EAAE,IAAI,CAAC,QAAQ;oBACrB,MAAM,EAAE,0BAA0B,IAAI,CAAC,QAAQ,EAAE;iBAClD,CAAC,CAAC;IACT,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,iBAAiB,CAAC,KAA0C,EAAE,QAAkB;IACvF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM;QACvE,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;;QACxC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,kBAAkB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9F,WAAW,CAAC,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IACjE,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE;QACtD,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CACR,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS;QAC/F,KAAK,CAAC,KAAK,EAAE,KAAK;YAChB,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;gBACrD,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,oBAAoB,CAAC,CAAC;QAChD,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAoD;IACtF,EAAE,EAAE,oBAAoB;IACxB,UAAU,EAAE,8BAA8B;IAC1C,YAAY,CAAC,KAAK;QAChB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC3D,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;YAC9D,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QACpE,CAAC;QACD,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC;QAC9D,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;QACpE,uBAAuB,CAAC,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,QAAQ,CAAC,CAAC;QACjF,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,QAAQ,CAAC,CAAC;QACnF,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QACtD,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7E,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACnC,oBAAoB,CAAC,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC;QACtE,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC;QACpE,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,KAAK,CAAC,KAAK;QACT,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACpE,MAAM,SAAS,GAAG,GAAG,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC;QAC3G,OAAO;YACL;gBACE,KAAK,EAAE,8EAA8E;gBACrF,WAAW,EACT,qDAAqD,KAAK,CAAC,SAAS,CAAC,IAAI,mBAAmB;oBAC5F,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,sFAAsF;oBAC/G,2CAA2C,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,kCAAkC;oBAC3G,YAAY,KAAK,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,4DAA4D;oBAClH,iCAAiC,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC;oBAC/G,oEAAoE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY;oBAC/G,6BAA6B,KAAK,CAAC,eAAe,+DAA+D;oBACjH,gHAAgH;oBAChH,yDAAyD;oBACzD,sGAAsG;gBACxG,OAAO,EAAE;oBACP,KAAK,EAAE;wBACL,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE;wBACvE,GAAG,KAAK,CAAC,UAAU;6BAChB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;6BACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,IAAI,oBAAoB,EAAE,CAAC,CAAC;qBACpF;oBACD,MAAM,EAAE;wBACN,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE;wBACnE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,oCAAoC,EAAE;qBAChE;oBACD,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC;iBAC1D;gBACD,GAAG,CAAC,OAAO;oBACT,MAAM,QAAQ,GAAc,EAAE,CAAC;oBAC/B,MAAM,cAAc,GAAG,IAAI,GAAG,EAA0C,CAAC;oBACzE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;oBAC1E,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;oBAC9C,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;wBACjD,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;wBACpC,IAAI,CAAC,SAAS,CAAC,MAAM;4BAAE,SAAS;wBAChC,KAAK,MAAM,IAAI,IAAI,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;4BAC7D,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAE,CAAC;4BACzD,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;wBACvF,CAAC;wBACD,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE;4BACpC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;gCAAE,OAAO;4BACvC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;4BAC9B,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;gCAAE,OAAO;4BACzC,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;gCAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;;gCAEvD,QAAQ,CAAC,IAAI,CAAC;oCACZ,IAAI,EAAE,IAAI,CAAC,IAAI;oCACf,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC;oCAC5B,MAAM,EAAE,mDAAmD,IAAI,mBAAmB,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE;iCACzG,CAAC,CAAC;wBACP,CAAC,CAAC,CAAC;oBACL,CAAC;oBACD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,OAAO;wBAChC,IAAI,CAAC,IAAI;4BACP,QAAQ,CAAC,IAAI,CAAC;gCACZ,IAAI,EAAE,IAAI;gCACV,MAAM,EAAE,wEAAwE;6BACjF,CAAC,CAAC;oBACP,IAAI,CAAC,cAAc,CAAC,IAAI;wBACtB,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,aAAa;4BACnB,MAAM,EAAE,oBAAoB,KAAK,CAAC,SAAS,CAAC,IAAI,QAAQ,KAAK,CAAC,SAAS,CAAC,MAAM,uCAAuC;yBACtH,CAAC,CAAC;oBAEL,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,mBAAmB,EAAE,GAAG,gBAAgB,CAClE,OAAO,EACP,KAAK,CAAC,iBAAiB,CACxB,CAAC;oBACF,QAAQ,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,CAAC;oBACtC,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,EAAE;wBAC3C,GAAG,KAAK,CAAC,kBAAkB;wBAC3B,OAAO,EAAE,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;qBACpF,CAAC,CAAC;oBACH,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;oBACtC,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,CAAC,GAAG,QAAQ,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC;yBAClC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;yBACtB,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAC1C,CAAC;oBACF,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;oBACxC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;wBACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI;4BAAE,SAAS;wBAClC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;wBAC9B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;4BACjC,QAAQ,CAAC,IAAI,CAAC;gCACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gCACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gCACZ,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,QAAQ,uCAAuC;6BAChF,CAAC,CAAC;oBACP,CAAC;oBACD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,cAAc;wBACxC,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;4BACtD,QAAQ,CAAC,IAAI,CAAC;gCACZ,GAAG,KAAK;gCACR,MAAM,EAAE,GAAG,IAAI,sDAAsD,KAAK,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;6BAClH,CAAC,CAAC;oBAEP,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,cAAc;wBACrC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;4BAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,4CAA4C,EAAE,CAAC,CAAC;oBACxF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;oBACjE,IAAI,CAAC,WAAW;wBACd,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,KAAK,CAAC,eAAe;4BAC3B,MAAM,EAAE,+CAA+C;yBACxD,CAAC,CAAC;oBACL,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;oBAC/C,MAAM,WAAW,GAAG,CAAC,CAAoC,EAAE,EAAE,CAC3D,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBAC/C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;oBACvC,IAAI,UAAU,GAAG,KAAK,CAAC;oBACvB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC;wBAClD,IAAI,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC;4BAAE,SAAS;wBACtD,IAAI,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;4BAAE,SAAS;wBAC5E,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE,CAC/B,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;wBAC7D,MAAM,IAAI,GAAG,eAAe,CAC1B,IAAI,EACJ,KAAK,EACL,CAAC,IAAI,EAAE,EAAE;4BACP,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;4BAC/B,OAAO,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;wBAC5D,CAAC,EACD,CAAC,IAAI,EAAE,EAAE;4BACP,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;4BAC/B,OAAO,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gCACjE,CAAC,CAAC,QAAQ;gCACV,CAAC,CAAC,IAAI,CAAC;wBACX,CAAC,CACF,CAAC;wBACF,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,eAAe,EAAE,CAAC;4BACxC,UAAU,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;4BAC/B,SAAS;wBACX,CAAC;wBACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;4BACvB,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,CACnF,CAAC;4BACF,IAAI,KAAK;gCAAE,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;;gCAE9C,QAAQ,CAAC,IAAI,CAAC;oCACZ,IAAI,EAAE,IAAI,CAAC,IAAI;oCACf,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;oCAC5B,MAAM,EAAE,2BAA2B,GAAG,CAAC,MAAM,EAAE;iCAChD,CAAC,CAAC;wBACP,CAAC;oBACH,CAAC;oBACD,IAAI,WAAW,IAAI,CAAC,UAAU;wBAC5B,QAAQ,CAAC,IAAI,CAAC;4BACZ,IAAI,EAAE,KAAK,CAAC,eAAe;4BAC3B,MAAM,EACJ,6FAA6F;yBAChG,CAAC,CAAC;oBACL,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ;wBAChC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;4BACvC,QAAQ,CAAC,IAAI,CAAC;gCACZ,IAAI,EAAE,KAAK,CAAC,IAAI;gCAChB,MAAM,EAAE,iDAAiD,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;6BAC1G,CAAC,CAAC;oBACP,OAAO,QAAQ,CAAC;gBAClB,CAAC;aACF;SACF,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding, Guard, GuardContext } from '../../guard.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport type { FileView } from '../../reader/view.js';\nimport { ownerOnly, reviewedAllowlist, type Hit, type Matcher } from '../../shapes/shapes.js';\nimport { calleeName, forEachNode, lineOfNode } from '../../support/ast.js';\nimport {\n importAliasesProblem,\n isText,\n namesProblem,\n objectProblem,\n pathProblem,\n reviewedProblems,\n takesNoFacts,\n textProblem,\n} from '../../support/facts.js';\nimport { MODULE_LOADS, moduleImports } from '../../support/imports.js';\nimport { aliasList, resolveSpecifier } from '../../support/resolve-specifier.js';\nimport { escapeRegExp, isUnder } from '../../support/text.js';\nimport {\n declarationFactProblems,\n readDeclarations,\n type CallableDeclarationFacts,\n} from '../frontend-actions/declarations.js';\nimport {\n inServerZone,\n serverZoneContext,\n serverZoneProblems,\n staleServerFolders,\n type ServerZone,\n} from './shared.js';\n\nconst FUNCTIONS_CODE: Scope = { roots: ['functions'], kinds: ['code'], tests: false };\n\nexport interface AdminClaimFacts {\n claimKeys: readonly string[];\n readers: readonly Reviewed[];\n appServerZone: ServerZone;\n}\n\nconst CLAIM_RECEIVER = String.raw`(?:[\\w$]*[Tt]oken|[\\w$]*[Cc]laims|decoded[\\w$]*)`;\n\nexport function adminClaimMatcher(claimKeys: readonly string[]): Matcher {\n const keys = claimKeys.map(escapeRegExp).join('|');\n const patterns = [\n new RegExp(String.raw`\\b${CLAIM_RECEIVER}\\s*(?:\\?\\.|\\.)\\s*(?:${keys})\\b`, 'g'),\n new RegExp(String.raw`\\b${CLAIM_RECEIVER}\\s*(?:\\?\\.)?\\s*\\[\\s*(['\"\\`])(?:${keys})\\1\\s*\\]`, 'g'),\n new RegExp(\n String.raw`\\{[^{}\\n]*\\b(?:${keys})\\b[^{}\\n]*\\}\\s*=\\s*[^;\\n]*${CLAIM_RECEIVER}\\b`,\n 'g',\n ),\n ];\n return (file) => {\n const hits: Hit[] = [];\n for (const re of patterns) {\n const g = new RegExp(re.source, re.flags);\n for (let m = g.exec(file.code); m; m = g.exec(file.code))\n hits.push({ index: m.index, detail: m[0].trim().slice(0, 80) });\n }\n return hits.sort((a, b) => a.index - b.index);\n };\n}\n\nexport const adminClaimGuard: GenericGuardDefinition<AdminClaimFacts> = {\n id: 'adminClaimRead',\n absentWhen: 'the app has no admin claim',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.claimKeys, 'claimKeys', problems);\n reviewedProblems(facts?.readers, 'readers', problems, { nonEmpty: true });\n serverZoneProblems(facts?.appServerZone, 'appServerZone', problems);\n return problems;\n },\n build(facts) {\n const guard = reviewedAllowlist({\n title: 'the admin claim is read only by its resolver',\n description:\n `No server module reads an admin claim (${facts.claimKeys.join(', ')}) off a token or claims payload — by member ` +\n 'access, bracket access, or destructuring — outside the reviewed readers. The claim is metadata and stays true ' +\n 'for up to an hour after a demotion, and anything signed from it outlives the revocation by its own lifetime. ' +\n \"Resolve admin standing through the resolver's authoritative read, failing closed on a read failure. Writing the \" +\n 'claim is not a read. A reviewed reader that no longer reads the claim is stale.',\n scope: {\n roots: ['functions', 'app'],\n optionalRoots: ['functions'],\n kinds: ['code'],\n tests: false,\n },\n match: adminClaimMatcher(facts.claimKeys),\n allowlist: facts.readers,\n samples: {\n flags: [\n `if (request.auth.token.${facts.claimKeys[0]} === true) return all;`,\n `const a = decoded?.['${facts.claimKeys[0]}'];`,\n `const { uid, ${facts.claimKeys[0]} = false } = ctx.token;`,\n ],\n passes: [\n `await auth.setCustomUserClaims(uid, { ${facts.claimKeys[0]}: true });\\nif (args.${facts.claimKeys[0]}) run();`,\n ],\n },\n });\n return [\n {\n ...guard,\n async run(context: GuardContext) {\n return [\n ...staleServerFolders(context, facts.appServerZone),\n ...(await guard.run(serverZoneContext(context, facts.appServerZone))),\n ];\n },\n },\n ];\n },\n};\n\nexport interface RequestOriginFacts {\n reader: string;\n}\n\nconst ORIGIN_READ = /\\brawRequest\\b|x-forwarded-for|\\breq\\s*\\.\\s*ip\\b/gi;\n\nexport const requestOriginGuard: GenericGuardDefinition<RequestOriginFacts> = {\n id: 'requestOrigin',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.reader, 'reader', problems);\n return problems;\n },\n build(facts) {\n return [\n ownerOnly({\n title: \"a request's origin is read in one place\",\n description: `A request's origin is read only in ${facts.reader}, which must still hold the read.`,\n scope: FUNCTIONS_CODE,\n match: (file) => {\n const re = new RegExp(ORIGIN_READ.source, ORIGIN_READ.flags);\n const hits: Hit[] = [];\n for (let m = re.exec(file.code); m; m = re.exec(file.code))\n hits.push({ index: m.index, detail: m[0] });\n return hits;\n },\n owners: [facts.reader],\n samples: {\n flags: [\n 'const ip = request.rawRequest?.ip ?? null;',\n \"const hops = headers['x-forwarded-for'];\",\n 'const caller = req.ip;',\n 'const { rawRequest } = request;',\n ],\n passes: ['const facts = { ip: context.ip };\\n// rawRequest is read only by the reader'],\n },\n }),\n ];\n },\n};\n\nexport type NoBlockingFunctionFacts = Record<string, never>;\n\nconst BLOCKING_MODULE = /^firebase-functions\\/(?:v2\\/)?identity$/;\nconst BLOCKING_BUILDERS = new Set(['beforeCreate', 'beforeSignIn', 'beforeEmail', 'beforeSms']);\n\nexport function blockingFunctionSites(file: FileView): Array<{ node: ts.Node; detail: string }> {\n const out: Array<{ node: ts.Node; detail: string }> = [];\n for (const { spec, node } of moduleImports(file.sourceFile, MODULE_LOADS))\n if (BLOCKING_MODULE.test(spec)) out.push({ node, detail: `imports ${spec}` });\n forEachNode(file.sourceFile, (node) => {\n if (\n ts.isCallExpression(node) &&\n ts.isPropertyAccessExpression(node.expression) &&\n BLOCKING_BUILDERS.has(node.expression.name.text)\n ) {\n out.push({ node, detail: `registers ${node.expression.name.text}` });\n }\n });\n return out;\n}\n\nexport const noBlockingFunctionGuard: GenericGuardDefinition<NoBlockingFunctionFacts> = {\n id: 'noAuthBlockingFunction',\n absentWhen: false,\n factProblems: takesNoFacts,\n build() {\n return [\n {\n title: 'no sign-in waits on a blocking function',\n description:\n 'No Functions source registers an Identity Platform blocking function (the identity module, or a v1 ' +\n 'beforeCreate / beforeSignIn / beforeEmail / beforeSms builder). Identity Platform refuses a sign-up or ' +\n 'sign-in whose blocking function has not answered within seconds, and a cold instance can take longer than ' +\n 'that to start, so a blocking function refuses members at random. Do the work after the fact instead.',\n run(context) {\n return context.files(FUNCTIONS_CODE).flatMap((file) =>\n blockingFunctionSites(file).map(({ node, detail }) => ({\n file: file.path,\n line: lineOfNode(file, node),\n detail,\n })),\n );\n },\n },\n ];\n },\n};\n\nexport interface AppCheckFacts {\n consumingFolders: readonly string[];\n adminAuth: { call: string; option: string };\n consumptionExempt: ReadonlyArray<{ callable: string; why: string }>;\n clientDeclarations: CallableDeclarationFacts;\n noClientDeclaration: ReadonlyArray<{ callable: string; why: string }>;\n}\n\ninterface Callable {\n name: string;\n node: ts.Node;\n options: ts.ObjectLiteralExpression | null;\n}\n\nconst isOnCall = (node: ts.Node): node is ts.CallExpression =>\n ts.isCallExpression(node) &&\n ts.isIdentifier(node.expression) &&\n node.expression.text === 'onCall';\n\nconst declaresTrue = (options: ts.ObjectLiteralExpression | null, key: string) =>\n !!options?.properties.some(\n (p) =>\n ts.isPropertyAssignment(p) &&\n p.name.getText().replace(/^['\"]|['\"]$/g, '') === key &&\n p.initializer.kind === ts.SyntaxKind.TrueKeyword,\n );\n\nexport function callablesOf(file: FileView): Callable[] {\n const sf = file.sourceFile;\n const optionsOf = (call: ts.CallExpression) =>\n call.arguments[0] && ts.isObjectLiteralExpression(call.arguments[0]) ? call.arguments[0] : null;\n const factories = new Map<string, ts.CallExpression>();\n const named = new Set<ts.CallExpression>();\n const out: Callable[] = [];\n forEachNode(sf, (node) => {\n if (ts.isFunctionDeclaration(node) && node.name && node.body) {\n forEachNode(node.body, (n) => {\n if (ts.isReturnStatement(n) && n.expression && isOnCall(n.expression))\n factories.set(node.name!.text, n.expression);\n });\n }\n });\n forEachNode(sf, (node) => {\n if (\n !ts.isVariableDeclaration(node) ||\n !ts.isIdentifier(node.name) ||\n !node.initializer ||\n !ts.isCallExpression(node.initializer)\n )\n return;\n const init: ts.CallExpression = node.initializer;\n if (isOnCall(init as ts.Node)) {\n named.add(init);\n out.push({ name: node.name.text, node: init, options: optionsOf(init) });\n } else if (ts.isIdentifier(init.expression) && factories.has(init.expression.text)) {\n const made = factories.get(init.expression.text)!;\n named.add(made);\n out.push({ name: node.name.text, node: init, options: optionsOf(made) });\n }\n });\n forEachNode(sf, (node) => {\n if (isOnCall(node) && !named.has(node))\n out.push({\n name: `(onCall at line ${lineOfNode(file, node)})`,\n node,\n options: optionsOf(node),\n });\n });\n return out;\n}\n\nexport function asksForAdmin(file: FileView, adminAuth: AppCheckFacts['adminAuth']): boolean {\n let found = false;\n forEachNode(file.sourceFile, (node) => {\n if (found || !ts.isCallExpression(node) || calleeName(node) !== adminAuth.call) return;\n found = node.arguments.some(\n (arg) =>\n ts.isObjectLiteralExpression(arg) &&\n arg.properties.some(\n (p) => p.name?.getText().replace(/^['\"]|['\"]$/g, '') === adminAuth.option,\n ),\n );\n });\n return found;\n}\n\nexport const appCheckGuard: GenericGuardDefinition<AppCheckFacts> = {\n id: 'appCheck',\n absentWhen: 'the app has no callable functions',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.consumingFolders, 'consumingFolders', problems, { nonEmpty: false });\n textProblem(facts?.adminAuth?.call, 'adminAuth.call', problems);\n textProblem(facts?.adminAuth?.option, 'adminAuth.option', problems);\n reviewedProblems(facts?.consumptionExempt, 'consumptionExempt', problems, { key: 'callable' });\n declarationFactProblems(facts?.clientDeclarations, 'clientDeclarations', problems);\n reviewedProblems(facts?.noClientDeclaration, 'noClientDeclaration', problems, {\n key: 'callable',\n });\n return problems;\n },\n build(facts) {\n const posture: Guard = {\n title: 'every callable declares its App Check posture',\n description:\n 'Every `onCall` opens with a literal options object (one this check cannot read fails, never passes) that ' +\n 'declares `enforceAppCheck: true`: attestation sits beneath auth and neither substitutes for the other. A ' +\n `callable in a consuming folder (${facts.consumingFolders.join(', ') || 'none declared'}), and every callable in a ` +\n `file whose ${facts.adminAuth.call} asks for ${facts.adminAuth.option}, also declares \\`consumeAppCheckToken: true\\`, ` +\n 'so its attestation token is spent instead of reusable for its whole lifetime. A callable that keeps the cached ' +\n 'token is a reviewed exemption with its why; an exemption whose callable is gone or now consumes is stale.',\n run(context) {\n const findings: Finding[] = [];\n const exempt = new Map(facts.consumptionExempt.map((e) => [e.callable, e]));\n const exemptSeen = new Set<string>();\n const foldersWithCallables = new Set<string>();\n let callables = 0;\n for (const file of context.files(FUNCTIONS_CODE)) {\n const list = callablesOf(file);\n if (!list.length) continue;\n callables += list.length;\n const folder = facts.consumingFolders.find((f) => isUnder(file.path, f));\n if (folder) foldersWithCallables.add(folder);\n const mustConsume = !!folder || asksForAdmin(file, facts.adminAuth);\n for (const callable of list) {\n const line = lineOfNode(file, callable.node);\n if (!callable.options) {\n findings.push({\n file: file.path,\n line,\n detail: `${callable.name}: the onCall options are not an object literal, so the posture cannot be read`,\n });\n continue;\n }\n if (!declaresTrue(callable.options, 'enforceAppCheck'))\n findings.push({\n file: file.path,\n line,\n detail: `${callable.name}: no enforceAppCheck: true`,\n });\n const consumes = declaresTrue(callable.options, 'consumeAppCheckToken');\n if (exempt.has(callable.name)) {\n exemptSeen.add(callable.name);\n if (consumes)\n findings.push({\n file: file.path,\n line,\n detail: `stale exemption: ${callable.name} now consumes its token`,\n });\n else if (!mustConsume)\n findings.push({\n file: file.path,\n line,\n detail: `stale exemption: ${callable.name} is not a consuming callable`,\n });\n } else if (mustConsume && !consumes) {\n findings.push({\n file: file.path,\n line,\n detail: `${callable.name}: no consumeAppCheckToken: true`,\n });\n }\n }\n }\n if (!callables)\n findings.push({\n file: '(functions)',\n detail: 'no onCall found, so the guard checks nothing',\n });\n for (const folder of facts.consumingFolders)\n if (!foldersWithCallables.has(folder))\n findings.push({ file: folder, detail: 'stale consuming folder: it holds no callable' });\n for (const name of exempt.keys())\n if (!exemptSeen.has(name))\n findings.push({\n file: '(consumptionExempt)',\n detail: `stale exemption: no callable is named ${name}`,\n });\n return findings;\n },\n };\n const client: Guard = {\n title: \"a consuming callable's client declaration presents a limited-use token\",\n description:\n 'Every callable whose options declare `consumeAppCheckToken: true` has a client declaration in ' +\n `${facts.clientDeclarations.modules.join(', ')} carrying \\`limitedUseAppCheck: true\\`, so the token the server ` +\n 'spends is a single-use one rather than the cached token every other call reuses. A declaration carrying it names ' +\n 'a callable that consumes: one that names no callable, or a callable that keeps the cached token (an exempt one ' +\n 'included), mints a token per call for nothing. A consuming callable no client calls is a reviewed entry with ' +\n 'its why; an entry that is no longer a consuming callable, or that a declaration now names, is stale.',\n run(context) {\n const { declared, findings } = readDeclarations(context, facts.clientDeclarations);\n const servers = new Map<string, { consumes: boolean; file: string; line: number }>();\n for (const file of context.files(FUNCTIONS_CODE)) {\n for (const callable of callablesOf(file)) {\n servers.set(callable.name, {\n consumes: declaresTrue(callable.options, 'consumeAppCheckToken'),\n file: file.path,\n line: lineOfNode(file, callable.node),\n });\n }\n }\n if (!servers.size)\n findings.push({\n file: '(functions)',\n detail: 'no onCall found, so the guard checks nothing',\n });\n const byName = new Map(\n declared.filter((d) => d.callable !== null).map((d) => [d.callable!, d]),\n );\n const exempt = new Set(facts.consumptionExempt.map((e) => e.callable));\n const undeclared = new Set(facts.noClientDeclaration.map((e) => e.callable));\n for (const [name, server] of servers) {\n if (!server.consumes) continue;\n const declaration = byName.get(name);\n if (!declaration) {\n if (!undeclared.has(name))\n findings.push({\n file: server.file,\n line: server.line,\n detail: `${name} consumes its token, but no client declaration names it`,\n });\n } else if (!declaration.limitedUse) {\n findings.push({\n file: declaration.file,\n line: declaration.line,\n detail: `${declaration.hook} declares ${name}, which consumes its token, without limitedUseAppCheck: true`,\n });\n }\n }\n for (const declaration of declared) {\n if (!declaration.limitedUse || declaration.callable === null) continue;\n const server = servers.get(declaration.callable);\n const where = { file: declaration.file, line: declaration.line };\n if (!server)\n findings.push({\n ...where,\n detail: `${declaration.hook} declares ${declaration.callable} limited-use, but no callable of that name exists`,\n });\n else if (exempt.has(declaration.callable))\n findings.push({\n ...where,\n detail: `${declaration.hook} declares ${declaration.callable} limited-use, but it is exempt from consumption`,\n });\n else if (!server.consumes)\n findings.push({\n ...where,\n detail: `${declaration.hook} declares ${declaration.callable} limited-use, but it does not consume its token`,\n });\n }\n for (const name of undeclared) {\n if (byName.has(name))\n findings.push({\n file: '(noClientDeclaration)',\n detail: `stale entry: a client declaration names ${name} now`,\n });\n else if (!servers.get(name)?.consumes)\n findings.push({\n file: '(noClientDeclaration)',\n detail: `stale entry: ${name} is not a consuming callable`,\n });\n }\n return findings;\n },\n };\n return [posture, client];\n },\n};\n\nexport interface AdminActionSurfaceFacts {\n adminAuth: { call: string; option: string };\n adminCheckers: readonly string[];\n checkerReaders: readonly Reviewed[];\n adminDeclarations: CallableDeclarationFacts;\n clientDeclarations: CallableDeclarationFacts;\n claimKeys: readonly string[];\n adminHooks: readonly string[];\n adminAreaRoots: readonly string[];\n affordanceOwner: string;\n reviewed: ReadonlyArray<{ path: string; symbol?: string; why: string }>;\n importAliases: Readonly<Record<string, string>>;\n appServerZone: ServerZone;\n}\n\nconst APP_CLIENT_CODE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\n\nfunction authCallsIn(root: ts.Node, adminAuth: AdminActionSurfaceFacts['adminAuth']) {\n const calls: Array<{ admin: boolean }> = [];\n forEachNode(root, (node) => {\n if (!ts.isCallExpression(node) || calleeName(node) !== adminAuth.call) return;\n calls.push({\n admin: node.arguments.some(\n (arg) =>\n ts.isObjectLiteralExpression(arg) &&\n arg.properties.some(\n (p) =>\n p.name?.getText().replace(/^['\"]|['\"]$/g, '') === adminAuth.option &&\n !(ts.isPropertyAssignment(p) && isOffLiteral(p.initializer)),\n ),\n ),\n });\n });\n return calls;\n}\n\nconst isOffLiteral = (value: ts.Expression): boolean =>\n value.kind === ts.SyntaxKind.FalseKeyword ||\n value.kind === ts.SyntaxKind.NullKeyword ||\n (ts.isIdentifier(value) && value.text === 'undefined');\n\nexport function adminOnlyCallables(\n file: FileView,\n adminAuth: AdminActionSurfaceFacts['adminAuth'],\n): string[] {\n const moduleCalls = authCallsIn(file.sourceFile, adminAuth);\n return callablesOf(file)\n .filter((callable) => {\n const own = authCallsIn(callable.node, adminAuth);\n const calls = own.length ? own : moduleCalls;\n return calls.length > 0 && calls.every((c) => c.admin);\n })\n .map((callable) => callable.name);\n}\n\ninterface ClientAdminUse {\n index: number;\n symbol: string;\n detail: string;\n}\n\nexport function clientAdminUses(\n file: FileView,\n facts: Pick<AdminActionSurfaceFacts, 'claimKeys' | 'adminHooks'>,\n declarationModuleOf: (spec: string) => string | null,\n areaModuleOf: (spec: string) => string | null = () => null,\n): ClientAdminUse[] {\n const out: ClientAdminUse[] = [];\n const keys = new RegExp(`\\\\b(${facts.claimKeys.map(escapeRegExp).join('|')})\\\\b`);\n for (const hit of adminClaimMatcher(facts.claimKeys)(file))\n out.push({\n index: hit.index,\n symbol: keys.exec(hit.detail ?? '')?.[1] ?? '',\n detail: `reads the admin claim (${hit.detail})`,\n });\n const hooks = new Set(facts.adminHooks);\n for (const site of moduleImports(file.sourceFile, MODULE_LOADS)) {\n const index = site.node.getStart(file.sourceFile);\n const module = declarationModuleOf(site.spec);\n if (module) {\n const names = site.named.map((n) => n.imported);\n for (const symbol of names.length ? names : ['*'])\n out.push({\n index,\n symbol,\n detail: `imports ${symbol} from the admin declarations ${module}`,\n });\n continue;\n }\n const area = site.typeOnly ? null : areaModuleOf(site.spec);\n if (area) {\n const names = site.named.filter((n) => !n.typeOnly).map((n) => n.imported);\n for (const symbol of site.named.length ? names : ['*'])\n out.push({\n index,\n symbol,\n detail: `imports ${symbol} from the admin area ${area}`,\n });\n continue;\n }\n for (const name of site.named)\n if (hooks.has(name.imported))\n out.push({\n index,\n symbol: name.imported,\n detail: `imports the admin hook ${name.imported}`,\n });\n }\n return out.sort((a, b) => a.index - b.index);\n}\n\nfunction adminAreaProblems(facts: AdminActionSurfaceFacts | undefined, problems: string[]): void {\n if (!Array.isArray(facts?.adminAreaRoots) || !facts.adminAreaRoots.length)\n problems.push('adminAreaRoots is missing');\n else facts.adminAreaRoots.forEach((r, i) => pathProblem(r, `adminAreaRoots[${i}]`, problems));\n pathProblem(facts?.affordanceOwner, 'affordanceOwner', problems);\n reviewedProblems(facts?.reviewed, 'reviewed', problems, {\n id: (e) =>\n typeof e.path === 'string' ? `${e.path}${isText(e.symbol) ? ` ${e.symbol}` : ''}` : undefined,\n extra(entry, label) {\n if (entry.symbol !== undefined && !isText(entry.symbol))\n problems.push(`${label}'s symbol is empty`);\n },\n });\n}\n\nexport const adminActionSurfaceGuard: GenericGuardDefinition<AdminActionSurfaceFacts> = {\n id: 'adminActionSurface',\n absentWhen: 'the app has no admin actions',\n factProblems(facts) {\n const problems: string[] = [];\n if (objectProblem(facts?.adminAuth, 'adminAuth', problems)) {\n textProblem(facts.adminAuth.call, 'adminAuth.call', problems);\n textProblem(facts.adminAuth.option, 'adminAuth.option', problems);\n }\n namesProblem(facts?.adminCheckers, 'adminCheckers', problems);\n reviewedProblems(facts?.checkerReaders, 'checkerReaders', problems);\n declarationFactProblems(facts?.adminDeclarations, 'adminDeclarations', problems);\n declarationFactProblems(facts?.clientDeclarations, 'clientDeclarations', problems);\n namesProblem(facts?.claimKeys, 'claimKeys', problems);\n namesProblem(facts?.adminHooks, 'adminHooks', problems, { nonEmpty: false });\n adminAreaProblems(facts, problems);\n importAliasesProblem(facts?.importAliases, 'importAliases', problems);\n serverZoneProblems(facts?.appServerZone, 'appServerZone', problems);\n return problems;\n },\n build(facts) {\n const declarationModules = new Set(facts.adminDeclarations.modules);\n const probePath = `${facts.affordanceOwner.slice(0, facts.affordanceOwner.lastIndexOf('/') + 1)}probe.tsx`;\n return [\n {\n title: 'admin actions outside the admin area go through the admin-actions affordance',\n description:\n `The admin-only callables are every callable whose ${facts.adminAuth.call} calls all carry ` +\n `${facts.adminAuth.option}, read from the Functions source each run. Inside a callable module, admin standing ` +\n `is checked only through that auth call: ${facts.adminCheckers.join(', ')} is called only by the reviewed ` +\n `readers. ${facts.adminDeclarations.modules.join(', ')} declares only admin-only callables, and every admin-only ` +\n `callable the client declares (${facts.clientDeclarations.modules.join(', ')}) is declared there; one with no ` +\n `client declaration has no client caller. Outside the admin area (${facts.adminAreaRoots.join(', ')}) and the ` +\n `admin-actions affordance (${facts.affordanceOwner}), client code never reads the admin claim, imports an admin ` +\n 'declaration, imports a module of the admin area, or imports an admin hook: an admin action there goes through ' +\n 'the affordance, and any other admin-standing read is a ' +\n 'reviewed entry ({ path, symbol?, why }). A reviewed reader or entry that no longer matches is stale.',\n samples: {\n flags: [\n { path: probePath, text: `if (claims?.${facts.claimKeys[0]}) show();` },\n ...facts.adminHooks\n .slice(0, 1)\n .map((hook) => ({ path: probePath, text: `import { ${hook} } from './hooks';` })),\n ],\n passes: [\n { path: probePath, text: `const label = '${facts.claimKeys[0]}';` },\n { path: probePath, text: \"import { useRows } from './hooks';\" },\n ],\n probe: (view) => clientAdminUses(view, facts, () => null),\n },\n run(context) {\n const findings: Finding[] = [];\n const adminCallables = new Map<string, { file: string; line: number }>();\n const readers = new Map(facts.checkerReaders.map((r) => [r.path, false]));\n const checkers = new Set(facts.adminCheckers);\n for (const file of context.files(FUNCTIONS_CODE)) {\n const callables = callablesOf(file);\n if (!callables.length) continue;\n for (const name of adminOnlyCallables(file, facts.adminAuth)) {\n const callable = callables.find((c) => c.name === name)!;\n adminCallables.set(name, { file: file.path, line: lineOfNode(file, callable.node) });\n }\n forEachNode(file.sourceFile, (node) => {\n if (!ts.isCallExpression(node)) return;\n const name = calleeName(node);\n if (!name || !checkers.has(name)) return;\n if (readers.has(file.path)) readers.set(file.path, true);\n else\n findings.push({\n file: file.path,\n line: lineOfNode(file, node),\n detail: `a callable module checks admin standing through ${name} instead of its ${facts.adminAuth.call}`,\n });\n });\n }\n for (const [path, used] of readers)\n if (!used)\n findings.push({\n file: path,\n detail: 'stale reader: it no longer calls an admin checker in a callable module',\n });\n if (!adminCallables.size)\n findings.push({\n file: '(functions)',\n detail: `no callable asks ${facts.adminAuth.call} for ${facts.adminAuth.option}, so no admin-only callable was found`,\n });\n\n const { declared, findings: declarationFindings } = readDeclarations(\n context,\n facts.adminDeclarations,\n );\n findings.push(...declarationFindings);\n const clientRead = readDeclarations(context, {\n ...facts.clientDeclarations,\n modules: facts.clientDeclarations.modules.filter((m) => !declarationModules.has(m)),\n });\n findings.push(...clientRead.findings);\n const clientDeclared = new Set(\n [...declared, ...clientRead.declared]\n .map((d) => d.callable)\n .filter((c): c is string => c !== null),\n );\n const declaredNames = new Set<string>();\n for (const d of declared) {\n if (d.callable === null) continue;\n declaredNames.add(d.callable);\n if (!adminCallables.has(d.callable))\n findings.push({\n file: d.file,\n line: d.line,\n detail: `${d.hook} declares ${d.callable}, which is not an admin-only callable`,\n });\n }\n for (const [name, where] of adminCallables)\n if (clientDeclared.has(name) && !declaredNames.has(name))\n findings.push({\n ...where,\n detail: `${name} is admin-only, but the client declares it outside ${facts.adminDeclarations.modules.join(', ')}`,\n });\n\n for (const root of facts.adminAreaRoots)\n if (!context.reader.exists(root))\n findings.push({ file: root, detail: 'stale admin-area root: it no longer exists' });\n const ownerExists = context.reader.exists(facts.affordanceOwner);\n if (!ownerExists)\n findings.push({\n file: facts.affordanceOwner,\n detail: 'the admin-actions affordance no longer exists',\n });\n const aliases = aliasList(facts.importAliases);\n const reviewedKey = (e: { path: string; symbol?: string }) =>\n `${e.path}${e.symbol ? ` ${e.symbol}` : ''}`;\n const reviewedSeen = new Set<string>();\n let ownerHolds = false;\n for (const file of context.files(APP_CLIENT_CODE)) {\n if (inServerZone(file, facts.appServerZone)) continue;\n if (facts.adminAreaRoots.some((root) => isUnder(file.path, root))) continue;\n const resolve = (spec: string) =>\n resolveSpecifier(context.reader, file.path, spec, aliases);\n const uses = clientAdminUses(\n file,\n facts,\n (spec) => {\n const resolved = resolve(spec);\n return declarationModules.has(resolved) ? resolved : null;\n },\n (spec) => {\n const resolved = resolve(spec);\n return facts.adminAreaRoots.some((root) => isUnder(resolved, root))\n ? resolved\n : null;\n },\n );\n if (file.path === facts.affordanceOwner) {\n ownerHolds ||= uses.length > 0;\n continue;\n }\n for (const use of uses) {\n const entry = facts.reviewed.find(\n (e) => e.path === file.path && (e.symbol === undefined || e.symbol === use.symbol),\n );\n if (entry) reviewedSeen.add(reviewedKey(entry));\n else\n findings.push({\n file: file.path,\n line: file.lineOf(use.index),\n detail: `outside the admin area: ${use.detail}`,\n });\n }\n }\n if (ownerExists && !ownerHolds)\n findings.push({\n file: facts.affordanceOwner,\n detail:\n 'stale affordance owner: it reads no admin standing and imports no admin declaration or hook',\n });\n for (const entry of facts.reviewed)\n if (!reviewedSeen.has(reviewedKey(entry)))\n findings.push({\n file: entry.path,\n detail: `stale entry: it no longer reads admin standing${entry.symbol ? ` through ${entry.symbol}` : ''}`,\n });\n return findings;\n },\n },\n ];\n },\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"functions-build.d.ts","sourceRoot":"","sources":["../../../src/modules/backend/functions-build.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAGzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAc,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"functions-build.d.ts","sourceRoot":"","sources":["../../../src/modules/backend/functions-build.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,10 +2,11 @@ import { posix } from 'node:path';
|
|
|
2
2
|
import ts from 'typescript';
|
|
3
3
|
import { ROOT_ROLES } from '../../node/layout.js';
|
|
4
4
|
import { calleeName, forEachNode, lineOfNode } from '../../support/ast.js';
|
|
5
|
-
import { namesProblem, reviewedProblems, textProblem } from '../../support/facts.js';
|
|
5
|
+
import { namesProblem, reviewedProblems, textProblem, isList } from '../../support/facts.js';
|
|
6
6
|
import { moduleImports, namesModule } from '../../support/imports.js';
|
|
7
7
|
import { resolveRelative } from '../../support/paths.js';
|
|
8
8
|
import { calleePath } from './shared.js';
|
|
9
|
+
import { REPOSITORY_GUARD_TIMEOUT_MS } from '../../support/timeouts.js';
|
|
9
10
|
const FUNCTIONS_CODE = { roots: ['functions'], kinds: ['code'], tests: false };
|
|
10
11
|
const CODE_EXTENSION = /\.(?:[cm]?[jt]sx?)$/;
|
|
11
12
|
function functionsRoot(context) {
|
|
@@ -273,7 +274,7 @@ export const lazyLoaderGuard = {
|
|
|
273
274
|
textProblem(facts?.loader, 'loader', problems);
|
|
274
275
|
if (facts?.roots !== undefined) {
|
|
275
276
|
namesProblem(facts.roots, 'roots', problems);
|
|
276
|
-
if (
|
|
277
|
+
if (isList(facts.roots)) {
|
|
277
278
|
for (const root of facts.roots)
|
|
278
279
|
if (!ROOT_ROLES.includes(root))
|
|
279
280
|
problems.push(`roots names ${String(root)}, which is not a root role`);
|
|
@@ -423,7 +424,7 @@ export const lightFunctionGuard = {
|
|
|
423
424
|
namesProblem(facts?.lightFunctions, 'lightFunctions', problems);
|
|
424
425
|
reviewedProblems(facts?.heavyPackages, 'heavyPackages', problems, { key: 'specifier' });
|
|
425
426
|
for (const p of facts?.heavyPackages ?? [])
|
|
426
|
-
if (!
|
|
427
|
+
if (!isList(p?.lightSubpaths))
|
|
427
428
|
problems.push(`heavy package ${String(p?.specifier)} needs lightSubpaths (declare [] when none)`);
|
|
428
429
|
reviewedProblems(facts?.heavyFiles, 'heavyFiles', problems);
|
|
429
430
|
if (!facts?.heavyPackages?.length && !facts?.heavyFiles?.length)
|
|
@@ -440,7 +441,7 @@ export const lightFunctionGuard = {
|
|
|
440
441
|
'cold start. Cut the edge — load the heavy module through the module-level lazy loader at its true usage site — ' +
|
|
441
442
|
'instead of relaxing the list. Every relative import must resolve, every light function must be exported by ' +
|
|
442
443
|
'the entry module, and every heavy file must exist.',
|
|
443
|
-
timeoutMs:
|
|
444
|
+
timeoutMs: REPOSITORY_GUARD_TIMEOUT_MS,
|
|
444
445
|
run(context) {
|
|
445
446
|
const findings = [];
|
|
446
447
|
const files = context.files(FUNCTIONS_CODE);
|
|
@@ -588,7 +589,7 @@ export const codebaseManifestGuard = {
|
|
|
588
589
|
}
|
|
589
590
|
const seen = new Map();
|
|
590
591
|
for (const [codebase, list] of Object.entries(manifest.codebases)) {
|
|
591
|
-
if (!
|
|
592
|
+
if (!isList(list)) {
|
|
592
593
|
findings.push({
|
|
593
594
|
file: facts.manifest,
|
|
594
595
|
detail: `codebase ${codebase} is not a list of exports`,
|
|
@@ -620,7 +621,7 @@ export const codebaseManifestGuard = {
|
|
|
620
621
|
});
|
|
621
622
|
if (!deploy)
|
|
622
623
|
return findings;
|
|
623
|
-
const entries =
|
|
624
|
+
const entries = isList(deploy.functions)
|
|
624
625
|
? deploy.functions
|
|
625
626
|
: null;
|
|
626
627
|
if (!entries)
|