@ttt-productions/repo-guards 0.1.36 → 0.1.38
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/functions-build.d.ts +1 -0
- package/dist/modules/backend/functions-build.d.ts.map +1 -1
- package/dist/modules/backend/functions-build.js +24 -0
- package/dist/modules/backend/functions-build.js.map +1 -1
- package/dist/modules/firestore/client-guards.d.ts.map +1 -1
- package/dist/modules/firestore/client-guards.js +22 -4
- package/dist/modules/firestore/client-guards.js.map +1 -1
- package/dist/node/tooling/cloud-checks.d.ts +9 -0
- package/dist/node/tooling/cloud-checks.d.ts.map +1 -1
- package/dist/node/tooling/cloud-checks.js +45 -8
- package/dist/node/tooling/cloud-checks.js.map +1 -1
- package/dist/node/tooling/functions-deploy-passes.d.ts +26 -0
- package/dist/node/tooling/functions-deploy-passes.d.ts.map +1 -0
- package/dist/node/tooling/functions-deploy-passes.js +96 -0
- package/dist/node/tooling/functions-deploy-passes.js.map +1 -0
- package/dist/node/tooling/index.d.ts +3 -2
- package/dist/node/tooling/index.d.ts.map +1 -1
- package/dist/node/tooling/index.js +3 -2
- package/dist/node/tooling/index.js.map +1 -1
- package/dist/node/tooling/quiet-gate.d.ts +4 -1
- package/dist/node/tooling/quiet-gate.d.ts.map +1 -1
- package/dist/node/tooling/quiet-gate.js +28 -2
- package/dist/node/tooling/quiet-gate.js.map +1 -1
- package/package.json +1 -1
|
@@ -65,6 +65,7 @@ export declare function exportsOf(file: FileView): {
|
|
|
65
65
|
unreadable: ts.Node[];
|
|
66
66
|
};
|
|
67
67
|
export declare const lightFunctionGuard: GenericGuardDefinition<LightFunctionFacts>;
|
|
68
|
+
export declare const MAX_FUNCTIONS_PER_CODEBASE = 55;
|
|
68
69
|
export interface CodebaseManifestFacts {
|
|
69
70
|
manifest: string;
|
|
70
71
|
entryIndex: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"functions-build.d.ts","sourceRoot":"","sources":["../../../src/modules/backend/functions-build.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"functions-build.d.ts","sourceRoot":"","sources":["../../../src/modules/backend/functions-build.ts"],"names":[],"mappings":"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"}
|
|
@@ -527,6 +527,9 @@ export const lightFunctionGuard = {
|
|
|
527
527
|
];
|
|
528
528
|
},
|
|
529
529
|
};
|
|
530
|
+
// Google allows 60 Cloud Functions mutations per minute per project and region, and a deploy
|
|
531
|
+
// changes every function of the codebase it targets; 55 leaves room for that pass's deletions.
|
|
532
|
+
export const MAX_FUNCTIONS_PER_CODEBASE = 55;
|
|
530
533
|
function readJson(context, path, findings) {
|
|
531
534
|
if (!context.reader.exists(path)) {
|
|
532
535
|
findings.push({ file: path, detail: 'the file no longer exists' });
|
|
@@ -659,6 +662,27 @@ export const codebaseManifestGuard = {
|
|
|
659
662
|
return findings;
|
|
660
663
|
},
|
|
661
664
|
},
|
|
665
|
+
{
|
|
666
|
+
title: `no Functions codebase holds more than ${MAX_FUNCTIONS_PER_CODEBASE} functions`,
|
|
667
|
+
description: `Each codebase in ${facts.manifest} deploys as one pass that changes every function it holds, ` +
|
|
668
|
+
`so a codebase over ${MAX_FUNCTIONS_PER_CODEBASE} functions outruns the platform's per-minute ` +
|
|
669
|
+
'mutation budget and its creates are dropped. A codebase that grows past the cap is split.',
|
|
670
|
+
run(context) {
|
|
671
|
+
const findings = [];
|
|
672
|
+
const manifest = readJson(context, facts.manifest, findings);
|
|
673
|
+
if (!manifest || typeof manifest.codebases !== 'object' || !manifest.codebases)
|
|
674
|
+
return findings;
|
|
675
|
+
for (const [codebase, list] of Object.entries(manifest.codebases)) {
|
|
676
|
+
if (!isList(list) || list.length <= MAX_FUNCTIONS_PER_CODEBASE)
|
|
677
|
+
continue;
|
|
678
|
+
findings.push({
|
|
679
|
+
file: facts.manifest,
|
|
680
|
+
detail: `codebase ${codebase} holds ${list.length} functions; split it so each codebase holds at most ${MAX_FUNCTIONS_PER_CODEBASE}`,
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
return findings;
|
|
684
|
+
},
|
|
685
|
+
},
|
|
662
686
|
];
|
|
663
687
|
},
|
|
664
688
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"functions-build.js","sourceRoot":"","sources":["../../../src/modules/backend/functions-build.ts"],"names":[],"mappings":"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","sourcesContent":["import { posix } from 'node:path';\nimport ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding, GuardContext } from '../../guard.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { FileView } from '../../reader/view.js';\nimport { ROOT_ROLES, type Reviewed, type RootRole } from '../../node/layout.js';\nimport { calleeName, forEachNode, lineOfNode } from '../../support/ast.js';\nimport { namesProblem, reviewedProblems, textProblem, isList } from '../../support/facts.js';\nimport { moduleImports, namesModule } from '../../support/imports.js';\nimport { resolveRelative } from '../../support/paths.js';\nimport { calleePath } from './shared.js';\nimport { REPOSITORY_GUARD_TIMEOUT_MS } from '../../support/timeouts.js';\n\nconst FUNCTIONS_CODE: Scope = { roots: ['functions'], kinds: ['code'], tests: false };\n\nconst CODE_EXTENSION = /\\.(?:[cm]?[jt]sx?)$/;\n\nfunction functionsRoot(context: GuardContext): string {\n const root = context.reader.layout.roots.functions;\n if (!root)\n throw new Error(\n 'repo-guards: a Functions guard runs and the layout declares no functions root',\n );\n return root.path;\n}\n\nconst moduleIdOf = (root: string, file: string) =>\n posix.relative(root, file).replace(CODE_EXTENSION, '');\n\nexport interface RateLimitFacts {\n owner: string;\n presetMap: string;\n surfaceMap: string;\n sharedPresets: string;\n chargeCall: string;\n prefixField: string;\n}\n\nconst isMapAccess = (node: ts.Node, map: string): node is ts.PropertyAccessExpression =>\n ts.isPropertyAccessExpression(node) &&\n ts.isIdentifier(node.expression) &&\n node.expression.text === map;\n\nexport function inlineLimiterConfigs(\n file: FileView,\n facts: Pick<RateLimitFacts, 'presetMap' | 'chargeCall'>,\n): Array<{ node: ts.Node; detail: string }> {\n const sf = file.sourceFile;\n const out: Array<{ node: ts.Node; detail: string }> = [];\n forEachNode(sf, (node) => {\n if (ts.isSpreadAssignment(node) && isMapAccess(node.expression, facts.presetMap)) {\n out.push({ node, detail: `spreads ${node.expression.getText(sf)} into a new config` });\n }\n if (\n ts.isCallExpression(node) &&\n calleeName(node) === facts.chargeCall &&\n node.arguments.some((a) => ts.isObjectLiteralExpression(a))\n ) {\n out.push({ node, detail: `passes an inline config to ${facts.chargeCall}` });\n }\n });\n return out;\n}\n\nexport function presetsNamed(file: FileView, presetMap: string): string[] {\n const out = new Set<string>();\n forEachNode(file.sourceFile, (node) => {\n if (isMapAccess(node, presetMap)) out.add(node.name.text);\n });\n return [...out];\n}\n\nexport function limiterDeclarations(owner: FileView, facts: RateLimitFacts) {\n const prefixes: string[] = [];\n const surfaces = new Map<string, string[]>();\n const shared = new Set<string>();\n let presetMapFound = false;\n let surfaceMapFound = false;\n let sharedFound = false;\n const strings = (node: ts.Expression): string[] =>\n ts.isArrayLiteralExpression(node)\n ? node.elements.filter(ts.isStringLiteralLike).map((e) => e.text)\n : [];\n const bare = (e: ts.Expression) => {\n let out = e;\n while (ts.isAsExpression(out) || ts.isSatisfiesExpression(out)) out = out.expression;\n return out;\n };\n forEachNode(owner.sourceFile, (node) => {\n if (!ts.isVariableDeclaration(node) || !ts.isIdentifier(node.name) || !node.initializer) return;\n const init = bare(node.initializer);\n if (node.name.text === facts.presetMap) {\n presetMapFound = true;\n forEachNode(init, (inner) => {\n if (\n ts.isPropertyAssignment(inner) &&\n inner.name.getText() === facts.prefixField &&\n ts.isStringLiteralLike(inner.initializer)\n ) {\n prefixes.push(inner.initializer.text);\n }\n });\n }\n if (node.name.text === facts.sharedPresets) {\n sharedFound = true;\n strings(init).forEach((name) => shared.add(name));\n }\n if (node.name.text === facts.surfaceMap && ts.isObjectLiteralExpression(init)) {\n surfaceMapFound = true;\n for (const p of init.properties) {\n if (\n ts.isPropertyAssignment(p) &&\n (ts.isIdentifier(p.name) || ts.isStringLiteralLike(p.name))\n )\n surfaces.set(p.name.text, strings(bare(p.initializer)));\n }\n }\n });\n return { prefixes, surfaces, shared, presetMapFound, surfaceMapFound, sharedFound };\n}\n\nexport function offendingCharges(\n charges: ReadonlyArray<{ module: string; presets: readonly string[] }>,\n surfaces: ReadonlyMap<string, readonly string[]>,\n shared: ReadonlySet<string>,\n): string[] {\n const listed = new Set([...surfaces.values()].flat());\n const out: string[] = [];\n for (const { module, presets } of charges) {\n for (const preset of presets) {\n const owners = surfaces.get(preset);\n const allowed = owners ? owners.includes(module) : shared.has(preset) && !listed.has(module);\n if (!allowed) out.push(`${module} charges ${preset}`);\n }\n }\n return out;\n}\n\nexport const rateLimitGuard: GenericGuardDefinition<RateLimitFacts> = {\n id: 'rateLimitSurfaces',\n absentWhen: 'the app runs no rate limiter',\n factProblems(facts) {\n const problems: string[] = [];\n for (const key of [\n 'owner',\n 'presetMap',\n 'surfaceMap',\n 'sharedPresets',\n 'chargeCall',\n 'prefixField',\n ] as const)\n textProblem(facts?.[key], key, problems);\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'every rate-limit charge names its own preset',\n description:\n `Every limiter charge passes a named ${facts.presetMap} preset — never an inline config to ${facts.chargeCall}, and ` +\n `never a preset spread into a new one — and every preset owns a distinct ${facts.prefixField}. A dedicated preset ` +\n `is charged only by the modules ${facts.surfaceMap} lists for it, and a listed module charges only its own presets; ` +\n `any other module charges only the ${facts.sharedPresets}. Otherwise two surfaces share one sliding window sized ` +\n `for neither. Every module the map lists must exist and charge its preset. Declare a new preset in ${facts.owner}.`,\n run(context) {\n const root = functionsRoot(context);\n const findings: Finding[] = [];\n const charges: Array<{ module: string; presets: string[] }> = [];\n let ownerFile: FileView | undefined;\n for (const file of context.files(FUNCTIONS_CODE)) {\n if (file.path === facts.owner) {\n ownerFile = file;\n continue;\n }\n for (const { node, detail } of inlineLimiterConfigs(file, facts))\n findings.push({ file: file.path, line: lineOfNode(file, node), detail });\n const presets = presetsNamed(file, facts.presetMap);\n if (presets.length) charges.push({ module: moduleIdOf(root, file.path), presets });\n }\n if (!ownerFile)\n return [\n ...findings,\n {\n file: facts.owner,\n detail: 'the limiter owner is gone or outside the Functions tree',\n },\n ];\n const declared = limiterDeclarations(ownerFile, facts);\n if (!declared.presetMapFound || !declared.prefixes.length)\n findings.push({\n file: facts.owner,\n detail: `no ${facts.presetMap} with a ${facts.prefixField} found`,\n });\n if (!declared.surfaceMapFound)\n findings.push({ file: facts.owner, detail: `no ${facts.surfaceMap} object found` });\n if (!declared.sharedFound)\n findings.push({ file: facts.owner, detail: `no ${facts.sharedPresets} list found` });\n const dup = declared.prefixes.filter((p, i) => declared.prefixes.indexOf(p) !== i);\n for (const p of new Set(dup))\n findings.push({\n file: facts.owner,\n detail: `two presets share the ${facts.prefixField} ${p}`,\n });\n for (const offense of offendingCharges(charges, declared.surfaces, declared.shared))\n findings.push({ file: facts.owner, detail: offense });\n const charged = new Map(charges.map((c) => [c.module, c.presets]));\n for (const [preset, modules] of declared.surfaces) {\n for (const module of modules)\n if (!charged.get(module)?.includes(preset))\n findings.push({\n file: facts.owner,\n detail: `${preset} lists ${module}, which does not charge it`,\n });\n }\n return findings;\n },\n },\n ];\n },\n};\n\nexport interface LazyLoaderFacts {\n loader: string;\n roots?: readonly RootRole[];\n otherLoaders?: ReadonlyArray<{ name: string; why: string }>;\n testRunnerConfigs: readonly string[];\n testExceptions: readonly Reviewed[];\n}\n\nconst isDynamicImport = (node: ts.Node): node is ts.CallExpression =>\n ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword;\n\nexport function strayDynamicImports(\n file: FileView,\n names: string | readonly string[],\n): { loaders: number; used: Set<string>; stray: ts.Node[] } {\n const accepted = typeof names === 'string' ? [names] : names;\n const sf = file.sourceFile;\n const stray: ts.Node[] = [];\n const used = new Set<string>();\n let loaders = 0;\n forEachNode(sf, (node) => {\n if (!isDynamicImport(node)) return;\n const name = moduleLevelLoaderName(node, accepted);\n if (name !== null) {\n used.add(name);\n if (name === accepted[0]) loaders += 1;\n } else stray.push(node);\n });\n return { loaders, used, stray };\n}\n\nfunction moduleLevelLoaderName(\n node: ts.CallExpression,\n accepted: readonly string[],\n): string | null {\n if (node.arguments.length !== 1 || !ts.isStringLiteralLike(node.arguments[0]!)) return null;\n let body: ts.Node = node;\n const access = node.parent;\n const projected =\n !!access &&\n ts.isPropertyAccessExpression(access) &&\n access.expression === node &&\n access.name.text === 'then' &&\n ts.isCallExpression(access.parent) &&\n access.parent.expression === access &&\n access.parent.arguments.length === 1;\n if (projected) body = access.parent;\n const arrow = body.parent;\n if (!arrow || !ts.isArrowFunction(arrow) || arrow.body !== body || arrow.parameters.length !== 0)\n return null;\n const call = arrow.parent;\n if (\n !call ||\n !ts.isCallExpression(call) ||\n !ts.isIdentifier(call.expression) ||\n call.arguments[0] !== arrow\n )\n return null;\n const name = call.expression.text;\n if (!accepted.includes(name)) return null;\n const isMain = name === accepted[0];\n if (isMain && (projected || call.arguments.length !== 1)) return null;\n const declaration = call.parent;\n if (!declaration || !ts.isVariableDeclaration(declaration) || declaration.initializer !== call)\n return null;\n if ((declaration.parent.flags & ts.NodeFlags.Const) === 0) return null;\n const statement = declaration.parent.parent;\n if (!statement || !ts.isVariableStatement(statement) || statement.parent !== node.getSourceFile())\n return null;\n return name;\n}\n\nconst COMBINATORS = new Set(['Promise.all', 'Promise.allSettled', 'Promise.race', 'Promise.any']);\n\nexport function overlappingTestImports(file: FileView): Array<{ node: ts.Node; detail: string }> {\n const sf = file.sourceFile;\n const out: Array<{ node: ts.Node; detail: string }> = [];\n const visit = (node: ts.Node, inCombinator: boolean) => {\n let combinator = inCombinator;\n if (ts.isPropertyAccessExpression(node) && node.name.text === 'concurrent')\n out.push({ node, detail: `${node.getText(sf)} runs tests concurrently` });\n if (\n ts.isPropertyAssignment(node) &&\n ts.isIdentifier(node.name) &&\n node.name.text === 'concurrent'\n )\n out.push({ node, detail: 'a concurrent test option' });\n if (ts.isCallExpression(node) && COMBINATORS.has(calleePath(node) ?? '')) combinator = true;\n if (inCombinator && isDynamicImport(node))\n out.push({\n node,\n detail: `${node.getText(sf)} overlaps the other imports of a Promise combinator`,\n });\n ts.forEachChild(node, (child) => visit(child, combinator));\n };\n visit(sf, false);\n return out;\n}\n\nexport const lazyLoaderGuard: GenericGuardDefinition<LazyLoaderFacts> = {\n id: 'lazyLoader',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.loader, 'loader', problems);\n if (facts?.roots !== undefined) {\n namesProblem(facts.roots, 'roots', problems);\n if (isList(facts.roots)) {\n for (const root of facts.roots)\n if (!ROOT_ROLES.includes(root))\n problems.push(`roots names ${String(root)}, which is not a root role`);\n }\n }\n if (facts?.otherLoaders !== undefined)\n reviewedProblems(facts.otherLoaders, 'otherLoaders', problems, { key: 'name' });\n namesProblem(facts?.testRunnerConfigs, 'testRunnerConfigs', problems);\n reviewedProblems(facts?.testExceptions, 'testExceptions', problems);\n return problems;\n },\n build(facts) {\n const roots = facts.roots ?? ['functions'];\n const others = (facts.otherLoaders ?? []).map((other) => other.name);\n return [\n {\n title: 'no code can overlap two dynamic imports of one module',\n description:\n `Every dynamic import in production code is a module-level \\`const load… = ${facts.loader}(() => import('…'))\\` ` +\n '(or a static import when laziness buys nothing): its first call starts the one import and every concurrent call ' +\n 'awaits it. A bare `import()` lets two concurrent calls overlap, and the test runner hands the second the REAL ' +\n 'module for a mocked one. Tests never overlap their own imports — no concurrent tests, no concurrent runner ' +\n 'config, no `import()` inside a Promise combinator; a test that does so on purpose is a reviewed exception with ' +\n 'its why, stale once it no longer does.',\n run(context) {\n const findings: Finding[] = [];\n let loaders = 0;\n const used = new Set<string>();\n for (const file of context.files({ roots, kinds: ['code'], tests: false })) {\n const result = strayDynamicImports(file, [facts.loader, ...others]);\n loaders += result.loaders;\n for (const name of result.used) used.add(name);\n for (const node of result.stray) {\n findings.push({\n file: file.path,\n line: lineOfNode(file, node),\n detail: `${node.getText(file.sourceFile).slice(0, 80)} is not a module-level ${facts.loader} loader`,\n });\n }\n }\n if (!loaders)\n findings.push({\n file: `(${roots.join(', ')})`,\n detail: `no ${facts.loader} loader found, so the guard checks nothing`,\n });\n for (const name of others)\n if (!used.has(name))\n findings.push({\n file: '(otherLoaders)',\n detail: `stale other loader: ${name} wraps no import`,\n });\n const exceptions = new Set(facts.testExceptions.map((e) => e.path));\n const overlapping = new Set<string>();\n for (const file of context.files({ roots, kinds: ['code'], tests: 'only' })) {\n const hits = overlappingTestImports(file);\n if (hits.length) overlapping.add(file.path);\n if (exceptions.has(file.path)) continue;\n for (const { node, detail } of hits)\n findings.push({ file: file.path, line: lineOfNode(file, node), detail });\n }\n for (const path of exceptions)\n if (!overlapping.has(path))\n findings.push({\n file: path,\n detail: 'stale test exception: the file overlaps no import',\n });\n for (const config of facts.testRunnerConfigs) {\n if (!context.reader.exists(config))\n findings.push({ file: config, detail: 'the test runner config no longer exists' });\n else {\n const view = context.file(config);\n const m = /\\bconcurrent\\s*:/.exec(view.code);\n if (m)\n findings.push({\n file: config,\n line: view.lineOf(m.index),\n detail: 'the runner config makes tests concurrent',\n });\n }\n }\n return findings;\n },\n },\n ];\n },\n};\n\nexport interface LightFunctionFacts {\n entryIndex: string;\n lightFunctions: readonly string[];\n heavyPackages: ReadonlyArray<{\n specifier: string;\n lightSubpaths: readonly string[];\n why: string;\n }>;\n heavyFiles: readonly Reviewed[];\n}\n\nexport function staticEdges(file: FileView): string[] {\n return moduleImports(file.sourceFile, ['import', 'export'])\n .filter((site) => site.topLevel && !site.typeOnly)\n .map((site) => site.spec);\n}\n\nexport function resolveModule(\n fromPath: string,\n spec: string,\n known: ReadonlySet<string>,\n): string | null {\n const base = resolveRelative(fromPath, spec)?.path;\n if (base === undefined) return null;\n const stem = base.replace(/\\.[cm]?jsx?$/, '');\n const candidates = [\n base,\n `${stem}.ts`,\n `${stem}.tsx`,\n `${stem}.mts`,\n `${stem}.cts`,\n `${base}.ts`,\n `${base}.tsx`,\n `${base}/index.ts`,\n `${base}/index.tsx`,\n ];\n return candidates.find((c) => known.has(c)) ?? null;\n}\n\nexport function exportsOf(file: FileView): {\n names: Map<string, string | null>;\n unreadable: ts.Node[];\n} {\n const names = new Map<string, string | null>();\n const unreadable: ts.Node[] = [];\n const exported = (node: ts.Node) =>\n ts.canHaveModifiers(node) &&\n !!ts.getModifiers(node)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);\n for (const stmt of file.sourceFile.statements) {\n if (ts.isExportDeclaration(stmt)) {\n const from =\n stmt.moduleSpecifier && ts.isStringLiteral(stmt.moduleSpecifier)\n ? stmt.moduleSpecifier.text\n : null;\n if (stmt.exportClause && ts.isNamedExports(stmt.exportClause))\n for (const e of stmt.exportClause.elements) names.set(e.name.text, from);\n else unreadable.push(stmt);\n } else if (ts.isVariableStatement(stmt) && exported(stmt)) {\n for (const d of stmt.declarationList.declarations)\n if (ts.isIdentifier(d.name)) names.set(d.name.text, null);\n } else if (\n (ts.isFunctionDeclaration(stmt) || ts.isClassDeclaration(stmt)) &&\n exported(stmt) &&\n stmt.name\n ) {\n names.set(stmt.name.text, null);\n }\n }\n return { names, unreadable };\n}\n\nexport const lightFunctionGuard: GenericGuardDefinition<LightFunctionFacts> = {\n id: 'lightFunctions',\n absentWhen: 'the app designates no light functions',\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.entryIndex, 'entryIndex', problems);\n namesProblem(facts?.lightFunctions, 'lightFunctions', problems);\n reviewedProblems(facts?.heavyPackages, 'heavyPackages', problems, { key: 'specifier' });\n for (const p of facts?.heavyPackages ?? [])\n if (!isList(p?.lightSubpaths))\n problems.push(\n `heavy package ${String(p?.specifier)} needs lightSubpaths (declare [] when none)`,\n );\n reviewedProblems(facts?.heavyFiles, 'heavyFiles', problems);\n if (!facts?.heavyPackages?.length && !facts?.heavyFiles?.length)\n problems.push(\n 'neither heavyPackages nor heavyFiles names anything, so the guard checks nothing',\n );\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'light functions never statically reach a heavy module',\n description:\n `The light functions (${facts.lightFunctions.join(', ')}) are hot interactive paths whose static import closure ` +\n \"is small by design: walking the static import graph from each one's module (dynamic `import()` and type-only \" +\n 'imports are not edges) never reaches a heavy package or a heavy Functions module, which would load on every ' +\n 'cold start. Cut the edge — load the heavy module through the module-level lazy loader at its true usage site — ' +\n 'instead of relaxing the list. Every relative import must resolve, every light function must be exported by ' +\n 'the entry module, and every heavy file must exist.',\n timeoutMs: REPOSITORY_GUARD_TIMEOUT_MS,\n run(context) {\n const findings: Finding[] = [];\n const files = context.files(FUNCTIONS_CODE);\n const known = new Set(files.map((f) => f.path));\n const graph = new Map<string, { internal: string[]; external: string[] }>();\n for (const file of files) {\n const internal: string[] = [];\n const external: string[] = [];\n for (const spec of staticEdges(file)) {\n if (!spec.startsWith('.')) external.push(spec);\n else {\n const target = resolveModule(file.path, spec, known);\n if (target) internal.push(target);\n else\n findings.push({\n file: file.path,\n detail: `cannot resolve ${spec}, so the closure through it is unread`,\n });\n }\n }\n graph.set(file.path, { internal, external });\n }\n for (const { path } of facts.heavyFiles)\n if (!known.has(path))\n findings.push({\n file: path,\n detail: 'stale heavy file: it is not a Functions module',\n });\n if (!known.has(facts.entryIndex))\n return [\n ...findings,\n {\n file: facts.entryIndex,\n detail: 'the entry module is gone or outside the Functions tree',\n },\n ];\n const { names } = exportsOf(files.find((f) => f.path === facts.entryIndex)!);\n for (const fn of facts.lightFunctions) {\n const from = names.get(fn);\n const start = from ? resolveModule(facts.entryIndex, from, known) : null;\n if (!start) {\n findings.push({\n file: facts.entryIndex,\n detail: `light function ${fn} is not re-exported from a Functions module`,\n });\n continue;\n }\n const seen = new Set([start]);\n const externals = new Set<string>();\n const stack = [start];\n while (stack.length) {\n const node = graph.get(stack.pop()!);\n if (!node) continue;\n node.external.forEach((e) => externals.add(e));\n for (const next of node.internal) {\n if (seen.has(next)) continue;\n seen.add(next);\n stack.push(next);\n }\n }\n for (const spec of externals) {\n const heavy = facts.heavyPackages.find(\n (p) => namesModule(spec, p.specifier) && !p.lightSubpaths.includes(spec),\n );\n if (heavy)\n findings.push({\n file: start,\n detail: `light function ${fn} statically reaches ${spec}`,\n });\n }\n for (const { path } of facts.heavyFiles)\n if (seen.has(path))\n findings.push({\n file: start,\n detail: `light function ${fn} statically reaches ${path}`,\n });\n }\n return findings;\n },\n },\n ];\n },\n};\n\nexport interface CodebaseManifestFacts {\n manifest: string;\n entryIndex: string;\n deployConfig: string;\n sourceTemplate: string;\n predeployTemplate: readonly string[];\n}\n\nfunction readJson(context: GuardContext, path: string, findings: Finding[]): unknown {\n if (!context.reader.exists(path)) {\n findings.push({ file: path, detail: 'the file no longer exists' });\n return undefined;\n }\n try {\n return JSON.parse(context.file(path).text);\n } catch (err) {\n findings.push({ file: path, detail: `cannot be read as JSON (${(err as Error).message})` });\n return undefined;\n }\n}\n\nexport const codebaseManifestGuard: GenericGuardDefinition<CodebaseManifestFacts> = {\n id: 'codebaseManifest',\n absentWhen: 'the app deploys its Functions as one codebase',\n factProblems(facts) {\n const problems: string[] = [];\n for (const key of ['manifest', 'entryIndex', 'deployConfig', 'sourceTemplate'] as const)\n textProblem(facts?.[key], key, problems);\n if (typeof facts?.sourceTemplate === 'string' && !facts.sourceTemplate.includes('{codebase}'))\n problems.push('sourceTemplate names no {codebase}');\n namesProblem(facts?.predeployTemplate, 'predeployTemplate', problems, { nonEmpty: false });\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'the codebase manifest deploys every function exactly once',\n description:\n `${facts.manifest} maps every export of ${facts.entryIndex} to exactly one Functions codebase — none missing, none ` +\n `stale, none in two — and ${facts.deployConfig} declares exactly the manifest's codebases, each from its source ` +\n 'folder with its predeploy build. A function in no codebase never deploys; one in two deploys twice; a codebase ' +\n 'the deploy config does not declare is never built. The entry module re-exports by name, never `export *`.',\n run(context) {\n const findings: Finding[] = [];\n const manifest = readJson(context, facts.manifest, findings) as\n { codebases?: Record<string, unknown> } | undefined;\n const deploy = readJson(context, facts.deployConfig, findings) as\n { functions?: unknown } | undefined;\n if (!context.reader.exists(facts.entryIndex))\n return [\n ...findings,\n { file: facts.entryIndex, detail: 'the entry module no longer exists' },\n ];\n const index = context.file(facts.entryIndex);\n const { names, unreadable } = exportsOf(index);\n for (const node of unreadable)\n findings.push({\n file: index.path,\n line: lineOfNode(index, node),\n detail: 'export * hides which functions the module deploys',\n });\n if (!names.size)\n findings.push({\n file: index.path,\n detail: 'no export found, so the guard checks nothing',\n });\n if (!manifest || typeof manifest.codebases !== 'object' || !manifest.codebases) {\n if (manifest) findings.push({ file: facts.manifest, detail: 'no codebases object' });\n return findings;\n }\n const seen = new Map<string, string>();\n for (const [codebase, list] of Object.entries(manifest.codebases)) {\n if (!isList(list)) {\n findings.push({\n file: facts.manifest,\n detail: `codebase ${codebase} is not a list of exports`,\n });\n continue;\n }\n for (const name of list as unknown[]) {\n if (typeof name !== 'string') continue;\n if (seen.has(name))\n findings.push({\n file: facts.manifest,\n detail: `${name} is in two codebases (${seen.get(name)} and ${codebase})`,\n });\n seen.set(name, codebase);\n }\n }\n for (const name of names.keys())\n if (!seen.has(name))\n findings.push({\n file: facts.manifest,\n detail: `${name} is exported but in no codebase`,\n });\n for (const name of seen.keys())\n if (!names.has(name))\n findings.push({\n file: facts.manifest,\n detail: `stale entry ${name}: the entry module does not export it`,\n });\n if (!deploy) return findings;\n const entries = isList(deploy.functions)\n ? (deploy.functions as Array<Record<string, unknown>>)\n : null;\n if (!entries)\n return [\n ...findings,\n { file: facts.deployConfig, detail: 'functions is not a list of codebase entries' },\n ];\n const declared = entries.map((e) => String(e.codebase));\n const codebases = Object.keys(manifest.codebases);\n for (const cb of codebases)\n if (!declared.includes(cb))\n findings.push({ file: facts.deployConfig, detail: `codebase ${cb} is not declared` });\n for (const cb of declared)\n if (!codebases.includes(cb))\n findings.push({\n file: facts.deployConfig,\n detail: `codebase ${cb} is not in the manifest`,\n });\n for (const entry of entries) {\n const cb = String(entry.codebase);\n const source = facts.sourceTemplate.split('{codebase}').join(cb);\n if (entry.source !== source)\n findings.push({\n file: facts.deployConfig,\n detail: `codebase ${cb} deploys from ${String(entry.source)}, not ${source}`,\n });\n const predeploy = facts.predeployTemplate.map((t) => t.split('{codebase}').join(cb));\n if (JSON.stringify(entry.predeploy ?? []) !== JSON.stringify(predeploy)) {\n findings.push({\n file: facts.deployConfig,\n detail: `codebase ${cb}'s predeploy is not ${JSON.stringify(predeploy)}`,\n });\n }\n }\n return findings;\n },\n },\n ];\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"functions-build.js","sourceRoot":"","sources":["../../../src/modules/backend/functions-build.ts"],"names":[],"mappings":"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","sourcesContent":["import { posix } from 'node:path';\nimport ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Finding, GuardContext } from '../../guard.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { FileView } from '../../reader/view.js';\nimport { ROOT_ROLES, type Reviewed, type RootRole } from '../../node/layout.js';\nimport { calleeName, forEachNode, lineOfNode } from '../../support/ast.js';\nimport { namesProblem, reviewedProblems, textProblem, isList } from '../../support/facts.js';\nimport { moduleImports, namesModule } from '../../support/imports.js';\nimport { resolveRelative } from '../../support/paths.js';\nimport { calleePath } from './shared.js';\nimport { REPOSITORY_GUARD_TIMEOUT_MS } from '../../support/timeouts.js';\n\nconst FUNCTIONS_CODE: Scope = { roots: ['functions'], kinds: ['code'], tests: false };\n\nconst CODE_EXTENSION = /\\.(?:[cm]?[jt]sx?)$/;\n\nfunction functionsRoot(context: GuardContext): string {\n const root = context.reader.layout.roots.functions;\n if (!root)\n throw new Error(\n 'repo-guards: a Functions guard runs and the layout declares no functions root',\n );\n return root.path;\n}\n\nconst moduleIdOf = (root: string, file: string) =>\n posix.relative(root, file).replace(CODE_EXTENSION, '');\n\nexport interface RateLimitFacts {\n owner: string;\n presetMap: string;\n surfaceMap: string;\n sharedPresets: string;\n chargeCall: string;\n prefixField: string;\n}\n\nconst isMapAccess = (node: ts.Node, map: string): node is ts.PropertyAccessExpression =>\n ts.isPropertyAccessExpression(node) &&\n ts.isIdentifier(node.expression) &&\n node.expression.text === map;\n\nexport function inlineLimiterConfigs(\n file: FileView,\n facts: Pick<RateLimitFacts, 'presetMap' | 'chargeCall'>,\n): Array<{ node: ts.Node; detail: string }> {\n const sf = file.sourceFile;\n const out: Array<{ node: ts.Node; detail: string }> = [];\n forEachNode(sf, (node) => {\n if (ts.isSpreadAssignment(node) && isMapAccess(node.expression, facts.presetMap)) {\n out.push({ node, detail: `spreads ${node.expression.getText(sf)} into a new config` });\n }\n if (\n ts.isCallExpression(node) &&\n calleeName(node) === facts.chargeCall &&\n node.arguments.some((a) => ts.isObjectLiteralExpression(a))\n ) {\n out.push({ node, detail: `passes an inline config to ${facts.chargeCall}` });\n }\n });\n return out;\n}\n\nexport function presetsNamed(file: FileView, presetMap: string): string[] {\n const out = new Set<string>();\n forEachNode(file.sourceFile, (node) => {\n if (isMapAccess(node, presetMap)) out.add(node.name.text);\n });\n return [...out];\n}\n\nexport function limiterDeclarations(owner: FileView, facts: RateLimitFacts) {\n const prefixes: string[] = [];\n const surfaces = new Map<string, string[]>();\n const shared = new Set<string>();\n let presetMapFound = false;\n let surfaceMapFound = false;\n let sharedFound = false;\n const strings = (node: ts.Expression): string[] =>\n ts.isArrayLiteralExpression(node)\n ? node.elements.filter(ts.isStringLiteralLike).map((e) => e.text)\n : [];\n const bare = (e: ts.Expression) => {\n let out = e;\n while (ts.isAsExpression(out) || ts.isSatisfiesExpression(out)) out = out.expression;\n return out;\n };\n forEachNode(owner.sourceFile, (node) => {\n if (!ts.isVariableDeclaration(node) || !ts.isIdentifier(node.name) || !node.initializer) return;\n const init = bare(node.initializer);\n if (node.name.text === facts.presetMap) {\n presetMapFound = true;\n forEachNode(init, (inner) => {\n if (\n ts.isPropertyAssignment(inner) &&\n inner.name.getText() === facts.prefixField &&\n ts.isStringLiteralLike(inner.initializer)\n ) {\n prefixes.push(inner.initializer.text);\n }\n });\n }\n if (node.name.text === facts.sharedPresets) {\n sharedFound = true;\n strings(init).forEach((name) => shared.add(name));\n }\n if (node.name.text === facts.surfaceMap && ts.isObjectLiteralExpression(init)) {\n surfaceMapFound = true;\n for (const p of init.properties) {\n if (\n ts.isPropertyAssignment(p) &&\n (ts.isIdentifier(p.name) || ts.isStringLiteralLike(p.name))\n )\n surfaces.set(p.name.text, strings(bare(p.initializer)));\n }\n }\n });\n return { prefixes, surfaces, shared, presetMapFound, surfaceMapFound, sharedFound };\n}\n\nexport function offendingCharges(\n charges: ReadonlyArray<{ module: string; presets: readonly string[] }>,\n surfaces: ReadonlyMap<string, readonly string[]>,\n shared: ReadonlySet<string>,\n): string[] {\n const listed = new Set([...surfaces.values()].flat());\n const out: string[] = [];\n for (const { module, presets } of charges) {\n for (const preset of presets) {\n const owners = surfaces.get(preset);\n const allowed = owners ? owners.includes(module) : shared.has(preset) && !listed.has(module);\n if (!allowed) out.push(`${module} charges ${preset}`);\n }\n }\n return out;\n}\n\nexport const rateLimitGuard: GenericGuardDefinition<RateLimitFacts> = {\n id: 'rateLimitSurfaces',\n absentWhen: 'the app runs no rate limiter',\n factProblems(facts) {\n const problems: string[] = [];\n for (const key of [\n 'owner',\n 'presetMap',\n 'surfaceMap',\n 'sharedPresets',\n 'chargeCall',\n 'prefixField',\n ] as const)\n textProblem(facts?.[key], key, problems);\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'every rate-limit charge names its own preset',\n description:\n `Every limiter charge passes a named ${facts.presetMap} preset — never an inline config to ${facts.chargeCall}, and ` +\n `never a preset spread into a new one — and every preset owns a distinct ${facts.prefixField}. A dedicated preset ` +\n `is charged only by the modules ${facts.surfaceMap} lists for it, and a listed module charges only its own presets; ` +\n `any other module charges only the ${facts.sharedPresets}. Otherwise two surfaces share one sliding window sized ` +\n `for neither. Every module the map lists must exist and charge its preset. Declare a new preset in ${facts.owner}.`,\n run(context) {\n const root = functionsRoot(context);\n const findings: Finding[] = [];\n const charges: Array<{ module: string; presets: string[] }> = [];\n let ownerFile: FileView | undefined;\n for (const file of context.files(FUNCTIONS_CODE)) {\n if (file.path === facts.owner) {\n ownerFile = file;\n continue;\n }\n for (const { node, detail } of inlineLimiterConfigs(file, facts))\n findings.push({ file: file.path, line: lineOfNode(file, node), detail });\n const presets = presetsNamed(file, facts.presetMap);\n if (presets.length) charges.push({ module: moduleIdOf(root, file.path), presets });\n }\n if (!ownerFile)\n return [\n ...findings,\n {\n file: facts.owner,\n detail: 'the limiter owner is gone or outside the Functions tree',\n },\n ];\n const declared = limiterDeclarations(ownerFile, facts);\n if (!declared.presetMapFound || !declared.prefixes.length)\n findings.push({\n file: facts.owner,\n detail: `no ${facts.presetMap} with a ${facts.prefixField} found`,\n });\n if (!declared.surfaceMapFound)\n findings.push({ file: facts.owner, detail: `no ${facts.surfaceMap} object found` });\n if (!declared.sharedFound)\n findings.push({ file: facts.owner, detail: `no ${facts.sharedPresets} list found` });\n const dup = declared.prefixes.filter((p, i) => declared.prefixes.indexOf(p) !== i);\n for (const p of new Set(dup))\n findings.push({\n file: facts.owner,\n detail: `two presets share the ${facts.prefixField} ${p}`,\n });\n for (const offense of offendingCharges(charges, declared.surfaces, declared.shared))\n findings.push({ file: facts.owner, detail: offense });\n const charged = new Map(charges.map((c) => [c.module, c.presets]));\n for (const [preset, modules] of declared.surfaces) {\n for (const module of modules)\n if (!charged.get(module)?.includes(preset))\n findings.push({\n file: facts.owner,\n detail: `${preset} lists ${module}, which does not charge it`,\n });\n }\n return findings;\n },\n },\n ];\n },\n};\n\nexport interface LazyLoaderFacts {\n loader: string;\n roots?: readonly RootRole[];\n otherLoaders?: ReadonlyArray<{ name: string; why: string }>;\n testRunnerConfigs: readonly string[];\n testExceptions: readonly Reviewed[];\n}\n\nconst isDynamicImport = (node: ts.Node): node is ts.CallExpression =>\n ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword;\n\nexport function strayDynamicImports(\n file: FileView,\n names: string | readonly string[],\n): { loaders: number; used: Set<string>; stray: ts.Node[] } {\n const accepted = typeof names === 'string' ? [names] : names;\n const sf = file.sourceFile;\n const stray: ts.Node[] = [];\n const used = new Set<string>();\n let loaders = 0;\n forEachNode(sf, (node) => {\n if (!isDynamicImport(node)) return;\n const name = moduleLevelLoaderName(node, accepted);\n if (name !== null) {\n used.add(name);\n if (name === accepted[0]) loaders += 1;\n } else stray.push(node);\n });\n return { loaders, used, stray };\n}\n\nfunction moduleLevelLoaderName(\n node: ts.CallExpression,\n accepted: readonly string[],\n): string | null {\n if (node.arguments.length !== 1 || !ts.isStringLiteralLike(node.arguments[0]!)) return null;\n let body: ts.Node = node;\n const access = node.parent;\n const projected =\n !!access &&\n ts.isPropertyAccessExpression(access) &&\n access.expression === node &&\n access.name.text === 'then' &&\n ts.isCallExpression(access.parent) &&\n access.parent.expression === access &&\n access.parent.arguments.length === 1;\n if (projected) body = access.parent;\n const arrow = body.parent;\n if (!arrow || !ts.isArrowFunction(arrow) || arrow.body !== body || arrow.parameters.length !== 0)\n return null;\n const call = arrow.parent;\n if (\n !call ||\n !ts.isCallExpression(call) ||\n !ts.isIdentifier(call.expression) ||\n call.arguments[0] !== arrow\n )\n return null;\n const name = call.expression.text;\n if (!accepted.includes(name)) return null;\n const isMain = name === accepted[0];\n if (isMain && (projected || call.arguments.length !== 1)) return null;\n const declaration = call.parent;\n if (!declaration || !ts.isVariableDeclaration(declaration) || declaration.initializer !== call)\n return null;\n if ((declaration.parent.flags & ts.NodeFlags.Const) === 0) return null;\n const statement = declaration.parent.parent;\n if (!statement || !ts.isVariableStatement(statement) || statement.parent !== node.getSourceFile())\n return null;\n return name;\n}\n\nconst COMBINATORS = new Set(['Promise.all', 'Promise.allSettled', 'Promise.race', 'Promise.any']);\n\nexport function overlappingTestImports(file: FileView): Array<{ node: ts.Node; detail: string }> {\n const sf = file.sourceFile;\n const out: Array<{ node: ts.Node; detail: string }> = [];\n const visit = (node: ts.Node, inCombinator: boolean) => {\n let combinator = inCombinator;\n if (ts.isPropertyAccessExpression(node) && node.name.text === 'concurrent')\n out.push({ node, detail: `${node.getText(sf)} runs tests concurrently` });\n if (\n ts.isPropertyAssignment(node) &&\n ts.isIdentifier(node.name) &&\n node.name.text === 'concurrent'\n )\n out.push({ node, detail: 'a concurrent test option' });\n if (ts.isCallExpression(node) && COMBINATORS.has(calleePath(node) ?? '')) combinator = true;\n if (inCombinator && isDynamicImport(node))\n out.push({\n node,\n detail: `${node.getText(sf)} overlaps the other imports of a Promise combinator`,\n });\n ts.forEachChild(node, (child) => visit(child, combinator));\n };\n visit(sf, false);\n return out;\n}\n\nexport const lazyLoaderGuard: GenericGuardDefinition<LazyLoaderFacts> = {\n id: 'lazyLoader',\n absentWhen: false,\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.loader, 'loader', problems);\n if (facts?.roots !== undefined) {\n namesProblem(facts.roots, 'roots', problems);\n if (isList(facts.roots)) {\n for (const root of facts.roots)\n if (!ROOT_ROLES.includes(root))\n problems.push(`roots names ${String(root)}, which is not a root role`);\n }\n }\n if (facts?.otherLoaders !== undefined)\n reviewedProblems(facts.otherLoaders, 'otherLoaders', problems, { key: 'name' });\n namesProblem(facts?.testRunnerConfigs, 'testRunnerConfigs', problems);\n reviewedProblems(facts?.testExceptions, 'testExceptions', problems);\n return problems;\n },\n build(facts) {\n const roots = facts.roots ?? ['functions'];\n const others = (facts.otherLoaders ?? []).map((other) => other.name);\n return [\n {\n title: 'no code can overlap two dynamic imports of one module',\n description:\n `Every dynamic import in production code is a module-level \\`const load… = ${facts.loader}(() => import('…'))\\` ` +\n '(or a static import when laziness buys nothing): its first call starts the one import and every concurrent call ' +\n 'awaits it. A bare `import()` lets two concurrent calls overlap, and the test runner hands the second the REAL ' +\n 'module for a mocked one. Tests never overlap their own imports — no concurrent tests, no concurrent runner ' +\n 'config, no `import()` inside a Promise combinator; a test that does so on purpose is a reviewed exception with ' +\n 'its why, stale once it no longer does.',\n run(context) {\n const findings: Finding[] = [];\n let loaders = 0;\n const used = new Set<string>();\n for (const file of context.files({ roots, kinds: ['code'], tests: false })) {\n const result = strayDynamicImports(file, [facts.loader, ...others]);\n loaders += result.loaders;\n for (const name of result.used) used.add(name);\n for (const node of result.stray) {\n findings.push({\n file: file.path,\n line: lineOfNode(file, node),\n detail: `${node.getText(file.sourceFile).slice(0, 80)} is not a module-level ${facts.loader} loader`,\n });\n }\n }\n if (!loaders)\n findings.push({\n file: `(${roots.join(', ')})`,\n detail: `no ${facts.loader} loader found, so the guard checks nothing`,\n });\n for (const name of others)\n if (!used.has(name))\n findings.push({\n file: '(otherLoaders)',\n detail: `stale other loader: ${name} wraps no import`,\n });\n const exceptions = new Set(facts.testExceptions.map((e) => e.path));\n const overlapping = new Set<string>();\n for (const file of context.files({ roots, kinds: ['code'], tests: 'only' })) {\n const hits = overlappingTestImports(file);\n if (hits.length) overlapping.add(file.path);\n if (exceptions.has(file.path)) continue;\n for (const { node, detail } of hits)\n findings.push({ file: file.path, line: lineOfNode(file, node), detail });\n }\n for (const path of exceptions)\n if (!overlapping.has(path))\n findings.push({\n file: path,\n detail: 'stale test exception: the file overlaps no import',\n });\n for (const config of facts.testRunnerConfigs) {\n if (!context.reader.exists(config))\n findings.push({ file: config, detail: 'the test runner config no longer exists' });\n else {\n const view = context.file(config);\n const m = /\\bconcurrent\\s*:/.exec(view.code);\n if (m)\n findings.push({\n file: config,\n line: view.lineOf(m.index),\n detail: 'the runner config makes tests concurrent',\n });\n }\n }\n return findings;\n },\n },\n ];\n },\n};\n\nexport interface LightFunctionFacts {\n entryIndex: string;\n lightFunctions: readonly string[];\n heavyPackages: ReadonlyArray<{\n specifier: string;\n lightSubpaths: readonly string[];\n why: string;\n }>;\n heavyFiles: readonly Reviewed[];\n}\n\nexport function staticEdges(file: FileView): string[] {\n return moduleImports(file.sourceFile, ['import', 'export'])\n .filter((site) => site.topLevel && !site.typeOnly)\n .map((site) => site.spec);\n}\n\nexport function resolveModule(\n fromPath: string,\n spec: string,\n known: ReadonlySet<string>,\n): string | null {\n const base = resolveRelative(fromPath, spec)?.path;\n if (base === undefined) return null;\n const stem = base.replace(/\\.[cm]?jsx?$/, '');\n const candidates = [\n base,\n `${stem}.ts`,\n `${stem}.tsx`,\n `${stem}.mts`,\n `${stem}.cts`,\n `${base}.ts`,\n `${base}.tsx`,\n `${base}/index.ts`,\n `${base}/index.tsx`,\n ];\n return candidates.find((c) => known.has(c)) ?? null;\n}\n\nexport function exportsOf(file: FileView): {\n names: Map<string, string | null>;\n unreadable: ts.Node[];\n} {\n const names = new Map<string, string | null>();\n const unreadable: ts.Node[] = [];\n const exported = (node: ts.Node) =>\n ts.canHaveModifiers(node) &&\n !!ts.getModifiers(node)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);\n for (const stmt of file.sourceFile.statements) {\n if (ts.isExportDeclaration(stmt)) {\n const from =\n stmt.moduleSpecifier && ts.isStringLiteral(stmt.moduleSpecifier)\n ? stmt.moduleSpecifier.text\n : null;\n if (stmt.exportClause && ts.isNamedExports(stmt.exportClause))\n for (const e of stmt.exportClause.elements) names.set(e.name.text, from);\n else unreadable.push(stmt);\n } else if (ts.isVariableStatement(stmt) && exported(stmt)) {\n for (const d of stmt.declarationList.declarations)\n if (ts.isIdentifier(d.name)) names.set(d.name.text, null);\n } else if (\n (ts.isFunctionDeclaration(stmt) || ts.isClassDeclaration(stmt)) &&\n exported(stmt) &&\n stmt.name\n ) {\n names.set(stmt.name.text, null);\n }\n }\n return { names, unreadable };\n}\n\nexport const lightFunctionGuard: GenericGuardDefinition<LightFunctionFacts> = {\n id: 'lightFunctions',\n absentWhen: 'the app designates no light functions',\n factProblems(facts) {\n const problems: string[] = [];\n textProblem(facts?.entryIndex, 'entryIndex', problems);\n namesProblem(facts?.lightFunctions, 'lightFunctions', problems);\n reviewedProblems(facts?.heavyPackages, 'heavyPackages', problems, { key: 'specifier' });\n for (const p of facts?.heavyPackages ?? [])\n if (!isList(p?.lightSubpaths))\n problems.push(\n `heavy package ${String(p?.specifier)} needs lightSubpaths (declare [] when none)`,\n );\n reviewedProblems(facts?.heavyFiles, 'heavyFiles', problems);\n if (!facts?.heavyPackages?.length && !facts?.heavyFiles?.length)\n problems.push(\n 'neither heavyPackages nor heavyFiles names anything, so the guard checks nothing',\n );\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'light functions never statically reach a heavy module',\n description:\n `The light functions (${facts.lightFunctions.join(', ')}) are hot interactive paths whose static import closure ` +\n \"is small by design: walking the static import graph from each one's module (dynamic `import()` and type-only \" +\n 'imports are not edges) never reaches a heavy package or a heavy Functions module, which would load on every ' +\n 'cold start. Cut the edge — load the heavy module through the module-level lazy loader at its true usage site — ' +\n 'instead of relaxing the list. Every relative import must resolve, every light function must be exported by ' +\n 'the entry module, and every heavy file must exist.',\n timeoutMs: REPOSITORY_GUARD_TIMEOUT_MS,\n run(context) {\n const findings: Finding[] = [];\n const files = context.files(FUNCTIONS_CODE);\n const known = new Set(files.map((f) => f.path));\n const graph = new Map<string, { internal: string[]; external: string[] }>();\n for (const file of files) {\n const internal: string[] = [];\n const external: string[] = [];\n for (const spec of staticEdges(file)) {\n if (!spec.startsWith('.')) external.push(spec);\n else {\n const target = resolveModule(file.path, spec, known);\n if (target) internal.push(target);\n else\n findings.push({\n file: file.path,\n detail: `cannot resolve ${spec}, so the closure through it is unread`,\n });\n }\n }\n graph.set(file.path, { internal, external });\n }\n for (const { path } of facts.heavyFiles)\n if (!known.has(path))\n findings.push({\n file: path,\n detail: 'stale heavy file: it is not a Functions module',\n });\n if (!known.has(facts.entryIndex))\n return [\n ...findings,\n {\n file: facts.entryIndex,\n detail: 'the entry module is gone or outside the Functions tree',\n },\n ];\n const { names } = exportsOf(files.find((f) => f.path === facts.entryIndex)!);\n for (const fn of facts.lightFunctions) {\n const from = names.get(fn);\n const start = from ? resolveModule(facts.entryIndex, from, known) : null;\n if (!start) {\n findings.push({\n file: facts.entryIndex,\n detail: `light function ${fn} is not re-exported from a Functions module`,\n });\n continue;\n }\n const seen = new Set([start]);\n const externals = new Set<string>();\n const stack = [start];\n while (stack.length) {\n const node = graph.get(stack.pop()!);\n if (!node) continue;\n node.external.forEach((e) => externals.add(e));\n for (const next of node.internal) {\n if (seen.has(next)) continue;\n seen.add(next);\n stack.push(next);\n }\n }\n for (const spec of externals) {\n const heavy = facts.heavyPackages.find(\n (p) => namesModule(spec, p.specifier) && !p.lightSubpaths.includes(spec),\n );\n if (heavy)\n findings.push({\n file: start,\n detail: `light function ${fn} statically reaches ${spec}`,\n });\n }\n for (const { path } of facts.heavyFiles)\n if (seen.has(path))\n findings.push({\n file: start,\n detail: `light function ${fn} statically reaches ${path}`,\n });\n }\n return findings;\n },\n },\n ];\n },\n};\n\n// Google allows 60 Cloud Functions mutations per minute per project and region, and a deploy\n// changes every function of the codebase it targets; 55 leaves room for that pass's deletions.\nexport const MAX_FUNCTIONS_PER_CODEBASE = 55;\n\nexport interface CodebaseManifestFacts {\n manifest: string;\n entryIndex: string;\n deployConfig: string;\n sourceTemplate: string;\n predeployTemplate: readonly string[];\n}\n\nfunction readJson(context: GuardContext, path: string, findings: Finding[]): unknown {\n if (!context.reader.exists(path)) {\n findings.push({ file: path, detail: 'the file no longer exists' });\n return undefined;\n }\n try {\n return JSON.parse(context.file(path).text);\n } catch (err) {\n findings.push({ file: path, detail: `cannot be read as JSON (${(err as Error).message})` });\n return undefined;\n }\n}\n\nexport const codebaseManifestGuard: GenericGuardDefinition<CodebaseManifestFacts> = {\n id: 'codebaseManifest',\n absentWhen: 'the app deploys its Functions as one codebase',\n factProblems(facts) {\n const problems: string[] = [];\n for (const key of ['manifest', 'entryIndex', 'deployConfig', 'sourceTemplate'] as const)\n textProblem(facts?.[key], key, problems);\n if (typeof facts?.sourceTemplate === 'string' && !facts.sourceTemplate.includes('{codebase}'))\n problems.push('sourceTemplate names no {codebase}');\n namesProblem(facts?.predeployTemplate, 'predeployTemplate', problems, { nonEmpty: false });\n return problems;\n },\n build(facts) {\n return [\n {\n title: 'the codebase manifest deploys every function exactly once',\n description:\n `${facts.manifest} maps every export of ${facts.entryIndex} to exactly one Functions codebase — none missing, none ` +\n `stale, none in two — and ${facts.deployConfig} declares exactly the manifest's codebases, each from its source ` +\n 'folder with its predeploy build. A function in no codebase never deploys; one in two deploys twice; a codebase ' +\n 'the deploy config does not declare is never built. The entry module re-exports by name, never `export *`.',\n run(context) {\n const findings: Finding[] = [];\n const manifest = readJson(context, facts.manifest, findings) as\n { codebases?: Record<string, unknown> } | undefined;\n const deploy = readJson(context, facts.deployConfig, findings) as\n { functions?: unknown } | undefined;\n if (!context.reader.exists(facts.entryIndex))\n return [\n ...findings,\n { file: facts.entryIndex, detail: 'the entry module no longer exists' },\n ];\n const index = context.file(facts.entryIndex);\n const { names, unreadable } = exportsOf(index);\n for (const node of unreadable)\n findings.push({\n file: index.path,\n line: lineOfNode(index, node),\n detail: 'export * hides which functions the module deploys',\n });\n if (!names.size)\n findings.push({\n file: index.path,\n detail: 'no export found, so the guard checks nothing',\n });\n if (!manifest || typeof manifest.codebases !== 'object' || !manifest.codebases) {\n if (manifest) findings.push({ file: facts.manifest, detail: 'no codebases object' });\n return findings;\n }\n const seen = new Map<string, string>();\n for (const [codebase, list] of Object.entries(manifest.codebases)) {\n if (!isList(list)) {\n findings.push({\n file: facts.manifest,\n detail: `codebase ${codebase} is not a list of exports`,\n });\n continue;\n }\n for (const name of list as unknown[]) {\n if (typeof name !== 'string') continue;\n if (seen.has(name))\n findings.push({\n file: facts.manifest,\n detail: `${name} is in two codebases (${seen.get(name)} and ${codebase})`,\n });\n seen.set(name, codebase);\n }\n }\n for (const name of names.keys())\n if (!seen.has(name))\n findings.push({\n file: facts.manifest,\n detail: `${name} is exported but in no codebase`,\n });\n for (const name of seen.keys())\n if (!names.has(name))\n findings.push({\n file: facts.manifest,\n detail: `stale entry ${name}: the entry module does not export it`,\n });\n if (!deploy) return findings;\n const entries = isList(deploy.functions)\n ? (deploy.functions as Array<Record<string, unknown>>)\n : null;\n if (!entries)\n return [\n ...findings,\n { file: facts.deployConfig, detail: 'functions is not a list of codebase entries' },\n ];\n const declared = entries.map((e) => String(e.codebase));\n const codebases = Object.keys(manifest.codebases);\n for (const cb of codebases)\n if (!declared.includes(cb))\n findings.push({ file: facts.deployConfig, detail: `codebase ${cb} is not declared` });\n for (const cb of declared)\n if (!codebases.includes(cb))\n findings.push({\n file: facts.deployConfig,\n detail: `codebase ${cb} is not in the manifest`,\n });\n for (const entry of entries) {\n const cb = String(entry.codebase);\n const source = facts.sourceTemplate.split('{codebase}').join(cb);\n if (entry.source !== source)\n findings.push({\n file: facts.deployConfig,\n detail: `codebase ${cb} deploys from ${String(entry.source)}, not ${source}`,\n });\n const predeploy = facts.predeployTemplate.map((t) => t.split('{codebase}').join(cb));\n if (JSON.stringify(entry.predeploy ?? []) !== JSON.stringify(predeploy)) {\n findings.push({\n file: facts.deployConfig,\n detail: `codebase ${cb}'s predeploy is not ${JSON.stringify(predeploy)}`,\n });\n }\n }\n return findings;\n },\n },\n {\n title: `no Functions codebase holds more than ${MAX_FUNCTIONS_PER_CODEBASE} functions`,\n description:\n `Each codebase in ${facts.manifest} deploys as one pass that changes every function it holds, ` +\n `so a codebase over ${MAX_FUNCTIONS_PER_CODEBASE} functions outruns the platform's per-minute ` +\n 'mutation budget and its creates are dropped. A codebase that grows past the cap is split.',\n run(context) {\n const findings: Finding[] = [];\n const manifest = readJson(context, facts.manifest, findings) as\n { codebases?: Record<string, unknown> } | undefined;\n if (!manifest || typeof manifest.codebases !== 'object' || !manifest.codebases)\n return findings;\n for (const [codebase, list] of Object.entries(manifest.codebases)) {\n if (!isList(list) || list.length <= MAX_FUNCTIONS_PER_CODEBASE) continue;\n findings.push({\n file: facts.manifest,\n detail: `codebase ${codebase} holds ${list.length} functions; split it so each codebase holds at most ${MAX_FUNCTIONS_PER_CODEBASE}`,\n });\n }\n return findings;\n },\n },\n ];\n },\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-guards.d.ts","sourceRoot":"","sources":["../../../src/modules/firestore/client-guards.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAqB,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"client-guards.d.ts","sourceRoot":"","sources":["../../../src/modules/firestore/client-guards.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAqB,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAsBrE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CAkC1D;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;CAChC;AAED,eAAO,MAAM,qBAAqB,EAAE,sBAAsB,CAAC,qBAAqB,CA2C/E,CAAC;AAEF,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;CACjC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CAoB7D;AAED,eAAO,MAAM,yBAAyB,EAAE,sBAAsB,CAAC,yBAAyB,CA+CvF,CAAC;AAWF,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;CACjC;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,CAwB9D;AAED,eAAO,MAAM,0BAA0B,EAAE,sBAAsB,CAAC,0BAA0B,CAoCzF,CAAC"}
|
|
@@ -6,6 +6,18 @@ import { moduleImports } from '../../support/imports.js';
|
|
|
6
6
|
import { isUnder } from '../../support/text.js';
|
|
7
7
|
const FIRESTORE_SDK = /^firebase\/firestore(?:\/|$)/;
|
|
8
8
|
const APP_SOURCE = { roots: ['app'], kinds: ['code'], tests: false };
|
|
9
|
+
function propertyName(node) {
|
|
10
|
+
if (ts.isShorthandPropertyAssignment(node))
|
|
11
|
+
return node.name.text;
|
|
12
|
+
if (ts.isPropertyAssignment(node) || ts.isMethodDeclaration(node))
|
|
13
|
+
return ts.isIdentifier(node.name) || ts.isStringLiteral(node.name) ? node.name.text : null;
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
// An object holding `read` beside `subscribe` is an external store source (query-core's
|
|
17
|
+
// `LiveSessionSource`); no Firestore read hook takes a `read` option.
|
|
18
|
+
function isStoreSource(object) {
|
|
19
|
+
return object.properties.some((property) => propertyName(property) === 'read');
|
|
20
|
+
}
|
|
9
21
|
export function liveSubscriptionHits(file) {
|
|
10
22
|
const source = file.sourceFile;
|
|
11
23
|
const snapshotNames = new Set(['onSnapshot']);
|
|
@@ -23,11 +35,14 @@ export function liveSubscriptionHits(file) {
|
|
|
23
35
|
const at = (node, detail) => hits.push({ index: node.getStart(source), detail });
|
|
24
36
|
forEachNode(source, (node) => {
|
|
25
37
|
if (ts.isPropertyAssignment(node) && ts.isObjectLiteralExpression(node.parent)) {
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
if (propertyName(node) === 'subscribe' &&
|
|
39
|
+
node.initializer.kind !== ts.SyntaxKind.FalseKeyword &&
|
|
40
|
+
!isStoreSource(node.parent))
|
|
28
41
|
at(node, `subscribe: ${node.initializer.getText(source)}`);
|
|
29
42
|
}
|
|
30
|
-
else if (ts.isShorthandPropertyAssignment(node) &&
|
|
43
|
+
else if (ts.isShorthandPropertyAssignment(node) &&
|
|
44
|
+
node.name.text === 'subscribe' &&
|
|
45
|
+
!isStoreSource(node.parent)) {
|
|
31
46
|
at(node, '{ subscribe }');
|
|
32
47
|
}
|
|
33
48
|
else if (ts.isCallExpression(node)) {
|
|
@@ -55,7 +70,8 @@ export const liveSubscriptionGuard = {
|
|
|
55
70
|
description: 'A live read bills a document read on every change for as long as it is mounted, so it is a reviewed exception: ' +
|
|
56
71
|
'a file that declares live mode — a subscribe option set to anything but a literal false, the { subscribe } ' +
|
|
57
72
|
"shorthand, or an onSnapshot call under any name the file bound the Firestore SDK's to — is on the reviewed " +
|
|
58
|
-
'list with why it needs real-time delivery.
|
|
73
|
+
'list with why it needs real-time delivery. An object holding read beside subscribe is a store source (a ' +
|
|
74
|
+
'session feed), not a read option, and is not live mode. Fix: read once and keep it fresh through the cache, or add the ' +
|
|
59
75
|
'reviewed entry. An entry whose file no longer subscribes is stale.',
|
|
60
76
|
scope: APP_SOURCE,
|
|
61
77
|
match: liveSubscriptionHits,
|
|
@@ -73,6 +89,8 @@ export const liveSubscriptionGuard = {
|
|
|
73
89
|
'useFirestoreDoc({ docPath, queryKey, subscribe: false });',
|
|
74
90
|
'const unsubscribe = cache.subscribe((event) => handle(event));',
|
|
75
91
|
'return useSyncExternalStore(subscribe, readValue, getServerValue);',
|
|
92
|
+
'const LIVE_SESSION: LiveSessionSource = { read: liveUid, subscribe: subscribeSession };',
|
|
93
|
+
'<MutationSessionProvider liveSession={{ read, subscribe }} />;',
|
|
76
94
|
'// subscribe: true is a reviewed exception\nconst x = 1;',
|
|
77
95
|
],
|
|
78
96
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-guards.js","sourceRoot":"","sources":["../../../src/modules/firestore/client-guards.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport type { FileView } from '../../reader/view.js';\nimport { reviewedAllowlist, type Hit } from '../../shapes/shapes.js';\nimport { forEachNode } from '../../support/ast.js';\nimport { namesProblem, reviewedProblems } from '../../support/facts.js';\nimport { moduleImports } from '../../support/imports.js';\nimport { isUnder } from '../../support/text.js';\n\nconst FIRESTORE_SDK = /^firebase\\/firestore(?:\\/|$)/;\nconst APP_SOURCE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\n\nexport function liveSubscriptionHits(file: FileView): Hit[] {\n const source = file.sourceFile;\n const snapshotNames = new Set(['onSnapshot']);\n const namespaces = new Set<string>();\n for (const site of moduleImports(source, ['import'])) {\n if (!site.topLevel || !FIRESTORE_SDK.test(site.spec)) continue;\n if (site.namespace) namespaces.add(site.namespace);\n for (const name of site.named)\n if (name.imported === 'onSnapshot') snapshotNames.add(name.local);\n }\n const hits: Hit[] = [];\n const at = (node: ts.Node, detail: string) => hits.push({ index: node.getStart(source), detail });\n forEachNode(source, (node) => {\n if (ts.isPropertyAssignment(node) && ts.isObjectLiteralExpression(node.parent)) {\n const key =\n ts.isIdentifier(node.name) || ts.isStringLiteral(node.name) ? node.name.text : null;\n if (key === 'subscribe' && node.initializer.kind !== ts.SyntaxKind.FalseKeyword)\n at(node, `subscribe: ${node.initializer.getText(source)}`);\n } else if (ts.isShorthandPropertyAssignment(node) && node.name.text === 'subscribe') {\n at(node, '{ subscribe }');\n } else if (ts.isCallExpression(node)) {\n const callee = node.expression;\n if (ts.isIdentifier(callee) && snapshotNames.has(callee.text)) at(node, `${callee.text}(…)`);\n else if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'onSnapshot')\n at(node, `${callee.getText(source)}(…)`);\n }\n });\n return hits;\n}\n\nexport interface LiveSubscriptionFacts {\n allowlist: readonly Reviewed[];\n}\n\nexport const liveSubscriptionGuard: GenericGuardDefinition<LiveSubscriptionFacts> = {\n id: 'firestoreLiveSubscriptions',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.allowlist, 'allowlist', problems);\n return problems;\n },\n build(facts) {\n return [\n reviewedAllowlist({\n title: 'every live Firestore subscription is on the reviewed list',\n description:\n 'A live read bills a document read on every change for as long as it is mounted, so it is a reviewed exception: ' +\n 'a file that declares live mode — a subscribe option set to anything but a literal false, the { subscribe } ' +\n \"shorthand, or an onSnapshot call under any name the file bound the Firestore SDK's to — is on the reviewed \" +\n 'list with why it needs real-time delivery. Fix: read once and keep it fresh through the cache, or add the ' +\n 'reviewed entry. An entry whose file no longer subscribes is stale.',\n scope: APP_SOURCE,\n match: liveSubscriptionHits,\n allowlist: facts.allowlist,\n samples: {\n flags: [\n 'useFirestoreDoc({ docPath, queryKey, subscribe: true });',\n 'useBatchFirestoreDocs({ ids, subscribe: isLive });',\n 'useFirestoreCollection({ collectionPath, subscribe, enabled });',\n \"import { doc, onSnapshot as listen } from 'firebase/firestore';\\nconst stop = listen(doc(db, p), render);\",\n \"import * as fs from 'firebase/firestore';\\nconst stop = fs.onSnapshot(ref, handle);\",\n ],\n passes: [\n \"useBatchFirestoreDocs({ db, collectionPath, ids, transport: 'get' });\",\n 'useFirestoreDoc({ docPath, queryKey, subscribe: false });',\n 'const unsubscribe = cache.subscribe((event) => handle(event));',\n 'return useSyncExternalStore(subscribe, readValue, getServerValue);',\n '// subscribe: true is a reviewed exception\\nconst x = 1;',\n ],\n },\n }),\n ];\n },\n};\n\nexport interface FirestoreRuntimeInUiFacts {\n uiFolders: readonly string[];\n sanctioned: readonly Reviewed[];\n}\n\nexport function firestoreRuntimeImports(file: FileView): Hit[] {\n const source = file.sourceFile;\n const hits: Hit[] = [];\n for (const site of moduleImports(source, ['import', 'export', 'dynamic'])) {\n if (!FIRESTORE_SDK.test(site.spec)) continue;\n const at = site.node.getStart(source);\n if (site.kind === 'import') {\n const typeOnly =\n !site.sideEffect &&\n (site.typeOnly ||\n (!site.defaultName &&\n !site.namespace &&\n site.named.length > 0 &&\n site.named.every((n) => n.typeOnly)));\n if (!typeOnly) hits.push({ index: at, detail: `import from '${site.spec}'` });\n } else if (site.kind === 'export') {\n if (!site.typeOnly) hits.push({ index: at, detail: `re-export from '${site.spec}'` });\n } else hits.push({ index: at, detail: `import('${site.spec}')` });\n }\n return hits;\n}\n\nexport const firestoreRuntimeInUiGuard: GenericGuardDefinition<FirestoreRuntimeInUiFacts> = {\n id: 'firestoreRuntimeInUi',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.uiFolders, 'uiFolders', problems);\n reviewedProblems(facts?.sanctioned, 'sanctioned', problems);\n return problems;\n },\n build(facts) {\n const inUi = (path: string) => facts.uiFolders.some((folder) => isUnder(path, folder));\n return [\n reviewedAllowlist({\n title: 'no component or route imports the Firestore runtime',\n description:\n 'A component or route that reaches into Firestore bypasses the cache, the query keys, and every server check ' +\n 'at once. Flagged: a runtime import, re-export, or dynamic import of the Firestore SDK (a type-only import ' +\n 'passes) in the UI folders. Fix: read through a hook, write through a callable. A sanctioned root provider is ' +\n 'a reviewed entry with its why; one that no longer imports the runtime is stale.',\n scope: APP_SOURCE,\n match: (file) => (inUi(file.path) ? firestoreRuntimeImports(file) : []),\n allowlist: facts.sanctioned,\n samples: {\n flags: [\n {\n path: `${facts.uiFolders[0]}/probe.tsx`,\n text: \"import { doc, getDoc } from 'firebase/firestore';\",\n },\n {\n path: `${facts.uiFolders[0]}/probe.tsx`,\n text: 'import {\\n updateDoc,\\n} from \"firebase/firestore\";',\n },\n ],\n passes: [\n {\n path: `${facts.uiFolders[0]}/typed.tsx`,\n text: \"import type { Timestamp } from 'firebase/firestore';\",\n },\n {\n path: `${facts.uiFolders[0]}/typed.tsx`,\n text: \"import { type Timestamp } from 'firebase/firestore';\",\n },\n ],\n },\n }),\n ];\n },\n};\n\nconst CLIENT_WRITES = new Set([\n 'setDoc',\n 'updateDoc',\n 'deleteDoc',\n 'addDoc',\n 'writeBatch',\n 'runTransaction',\n]);\n\nexport interface FirestoreClientWritesFacts {\n sanctioned: readonly Reviewed[];\n}\n\nexport function firestoreClientWriteHits(file: FileView): Hit[] {\n const source = file.sourceFile;\n const hits: Hit[] = [];\n const namespaces = new Set<string>();\n for (const site of moduleImports(source, ['import', 'export'])) {\n if (!FIRESTORE_SDK.test(site.spec) || site.typeOnly) continue;\n if (site.namespace) namespaces.add(site.namespace);\n for (const name of site.named)\n if (!name.typeOnly && CLIENT_WRITES.has(name.imported))\n hits.push({\n index: site.node.getStart(source),\n detail: `${name.imported} from '${site.spec}'`,\n });\n }\n forEachNode(source, (node) => {\n if (\n ts.isPropertyAccessExpression(node) &&\n ts.isIdentifier(node.expression) &&\n namespaces.has(node.expression.text) &&\n CLIENT_WRITES.has(node.name.text)\n )\n hits.push({ index: node.getStart(source), detail: node.getText(source) });\n });\n return hits;\n}\n\nexport const firestoreClientWritesGuard: GenericGuardDefinition<FirestoreClientWritesFacts> = {\n id: 'firestoreClientWrites',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.sanctioned, 'sanctioned', problems);\n return problems;\n },\n build(facts) {\n return [\n reviewedAllowlist({\n title: 'the client never writes Firestore',\n description:\n 'Every write goes through a callable that checks it on the server; a client SDK write skips that check and ' +\n 'every rule the callable enforces. Flagged: a runtime import of a Firestore write function (' +\n `${[...CLIENT_WRITES].join(', ')}) from the Firestore SDK, or a call to one through a namespace import, in ` +\n \"the app's client source. Fix: call the callable that owns the write. A sanctioned site is a reviewed entry \" +\n 'with its why; one that no longer writes is stale.',\n scope: APP_SOURCE,\n match: firestoreClientWriteHits,\n allowlist: facts.sanctioned,\n samples: {\n flags: [\n \"import { doc, setDoc } from 'firebase/firestore';\",\n \"import { writeBatch as batchOf } from 'firebase/firestore';\",\n \"import * as fs from 'firebase/firestore';\\nawait fs.updateDoc(ref, patch);\",\n ],\n passes: [\n \"import { doc, getDoc, onSnapshot } from 'firebase/firestore';\",\n \"import { type WriteBatch } from 'firebase/firestore';\",\n 'await callable({ id });',\n ],\n },\n }),\n ];\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"client-guards.js","sourceRoot":"","sources":["../../../src/modules/firestore/client-guards.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nimport type { GenericGuardDefinition } from '../../node/suite/config.js';\nimport type { Scope } from '../../node/reader.js';\nimport type { Reviewed } from '../../node/layout.js';\nimport type { FileView } from '../../reader/view.js';\nimport { reviewedAllowlist, type Hit } from '../../shapes/shapes.js';\nimport { forEachNode } from '../../support/ast.js';\nimport { namesProblem, reviewedProblems } from '../../support/facts.js';\nimport { moduleImports } from '../../support/imports.js';\nimport { isUnder } from '../../support/text.js';\n\nconst FIRESTORE_SDK = /^firebase\\/firestore(?:\\/|$)/;\nconst APP_SOURCE: Scope = { roots: ['app'], kinds: ['code'], tests: false };\n\nfunction propertyName(node: ts.ObjectLiteralElementLike): string | null {\n if (ts.isShorthandPropertyAssignment(node)) return node.name.text;\n if (ts.isPropertyAssignment(node) || ts.isMethodDeclaration(node))\n return ts.isIdentifier(node.name) || ts.isStringLiteral(node.name) ? node.name.text : null;\n return null;\n}\n\n// An object holding `read` beside `subscribe` is an external store source (query-core's\n// `LiveSessionSource`); no Firestore read hook takes a `read` option.\nfunction isStoreSource(object: ts.ObjectLiteralExpression): boolean {\n return object.properties.some((property) => propertyName(property) === 'read');\n}\n\nexport function liveSubscriptionHits(file: FileView): Hit[] {\n const source = file.sourceFile;\n const snapshotNames = new Set(['onSnapshot']);\n const namespaces = new Set<string>();\n for (const site of moduleImports(source, ['import'])) {\n if (!site.topLevel || !FIRESTORE_SDK.test(site.spec)) continue;\n if (site.namespace) namespaces.add(site.namespace);\n for (const name of site.named)\n if (name.imported === 'onSnapshot') snapshotNames.add(name.local);\n }\n const hits: Hit[] = [];\n const at = (node: ts.Node, detail: string) => hits.push({ index: node.getStart(source), detail });\n forEachNode(source, (node) => {\n if (ts.isPropertyAssignment(node) && ts.isObjectLiteralExpression(node.parent)) {\n if (\n propertyName(node) === 'subscribe' &&\n node.initializer.kind !== ts.SyntaxKind.FalseKeyword &&\n !isStoreSource(node.parent)\n )\n at(node, `subscribe: ${node.initializer.getText(source)}`);\n } else if (\n ts.isShorthandPropertyAssignment(node) &&\n node.name.text === 'subscribe' &&\n !isStoreSource(node.parent)\n ) {\n at(node, '{ subscribe }');\n } else if (ts.isCallExpression(node)) {\n const callee = node.expression;\n if (ts.isIdentifier(callee) && snapshotNames.has(callee.text)) at(node, `${callee.text}(…)`);\n else if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'onSnapshot')\n at(node, `${callee.getText(source)}(…)`);\n }\n });\n return hits;\n}\n\nexport interface LiveSubscriptionFacts {\n allowlist: readonly Reviewed[];\n}\n\nexport const liveSubscriptionGuard: GenericGuardDefinition<LiveSubscriptionFacts> = {\n id: 'firestoreLiveSubscriptions',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.allowlist, 'allowlist', problems);\n return problems;\n },\n build(facts) {\n return [\n reviewedAllowlist({\n title: 'every live Firestore subscription is on the reviewed list',\n description:\n 'A live read bills a document read on every change for as long as it is mounted, so it is a reviewed exception: ' +\n 'a file that declares live mode — a subscribe option set to anything but a literal false, the { subscribe } ' +\n \"shorthand, or an onSnapshot call under any name the file bound the Firestore SDK's to — is on the reviewed \" +\n 'list with why it needs real-time delivery. An object holding read beside subscribe is a store source (a ' +\n 'session feed), not a read option, and is not live mode. Fix: read once and keep it fresh through the cache, or add the ' +\n 'reviewed entry. An entry whose file no longer subscribes is stale.',\n scope: APP_SOURCE,\n match: liveSubscriptionHits,\n allowlist: facts.allowlist,\n samples: {\n flags: [\n 'useFirestoreDoc({ docPath, queryKey, subscribe: true });',\n 'useBatchFirestoreDocs({ ids, subscribe: isLive });',\n 'useFirestoreCollection({ collectionPath, subscribe, enabled });',\n \"import { doc, onSnapshot as listen } from 'firebase/firestore';\\nconst stop = listen(doc(db, p), render);\",\n \"import * as fs from 'firebase/firestore';\\nconst stop = fs.onSnapshot(ref, handle);\",\n ],\n passes: [\n \"useBatchFirestoreDocs({ db, collectionPath, ids, transport: 'get' });\",\n 'useFirestoreDoc({ docPath, queryKey, subscribe: false });',\n 'const unsubscribe = cache.subscribe((event) => handle(event));',\n 'return useSyncExternalStore(subscribe, readValue, getServerValue);',\n 'const LIVE_SESSION: LiveSessionSource = { read: liveUid, subscribe: subscribeSession };',\n '<MutationSessionProvider liveSession={{ read, subscribe }} />;',\n '// subscribe: true is a reviewed exception\\nconst x = 1;',\n ],\n },\n }),\n ];\n },\n};\n\nexport interface FirestoreRuntimeInUiFacts {\n uiFolders: readonly string[];\n sanctioned: readonly Reviewed[];\n}\n\nexport function firestoreRuntimeImports(file: FileView): Hit[] {\n const source = file.sourceFile;\n const hits: Hit[] = [];\n for (const site of moduleImports(source, ['import', 'export', 'dynamic'])) {\n if (!FIRESTORE_SDK.test(site.spec)) continue;\n const at = site.node.getStart(source);\n if (site.kind === 'import') {\n const typeOnly =\n !site.sideEffect &&\n (site.typeOnly ||\n (!site.defaultName &&\n !site.namespace &&\n site.named.length > 0 &&\n site.named.every((n) => n.typeOnly)));\n if (!typeOnly) hits.push({ index: at, detail: `import from '${site.spec}'` });\n } else if (site.kind === 'export') {\n if (!site.typeOnly) hits.push({ index: at, detail: `re-export from '${site.spec}'` });\n } else hits.push({ index: at, detail: `import('${site.spec}')` });\n }\n return hits;\n}\n\nexport const firestoreRuntimeInUiGuard: GenericGuardDefinition<FirestoreRuntimeInUiFacts> = {\n id: 'firestoreRuntimeInUi',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n namesProblem(facts?.uiFolders, 'uiFolders', problems);\n reviewedProblems(facts?.sanctioned, 'sanctioned', problems);\n return problems;\n },\n build(facts) {\n const inUi = (path: string) => facts.uiFolders.some((folder) => isUnder(path, folder));\n return [\n reviewedAllowlist({\n title: 'no component or route imports the Firestore runtime',\n description:\n 'A component or route that reaches into Firestore bypasses the cache, the query keys, and every server check ' +\n 'at once. Flagged: a runtime import, re-export, or dynamic import of the Firestore SDK (a type-only import ' +\n 'passes) in the UI folders. Fix: read through a hook, write through a callable. A sanctioned root provider is ' +\n 'a reviewed entry with its why; one that no longer imports the runtime is stale.',\n scope: APP_SOURCE,\n match: (file) => (inUi(file.path) ? firestoreRuntimeImports(file) : []),\n allowlist: facts.sanctioned,\n samples: {\n flags: [\n {\n path: `${facts.uiFolders[0]}/probe.tsx`,\n text: \"import { doc, getDoc } from 'firebase/firestore';\",\n },\n {\n path: `${facts.uiFolders[0]}/probe.tsx`,\n text: 'import {\\n updateDoc,\\n} from \"firebase/firestore\";',\n },\n ],\n passes: [\n {\n path: `${facts.uiFolders[0]}/typed.tsx`,\n text: \"import type { Timestamp } from 'firebase/firestore';\",\n },\n {\n path: `${facts.uiFolders[0]}/typed.tsx`,\n text: \"import { type Timestamp } from 'firebase/firestore';\",\n },\n ],\n },\n }),\n ];\n },\n};\n\nconst CLIENT_WRITES = new Set([\n 'setDoc',\n 'updateDoc',\n 'deleteDoc',\n 'addDoc',\n 'writeBatch',\n 'runTransaction',\n]);\n\nexport interface FirestoreClientWritesFacts {\n sanctioned: readonly Reviewed[];\n}\n\nexport function firestoreClientWriteHits(file: FileView): Hit[] {\n const source = file.sourceFile;\n const hits: Hit[] = [];\n const namespaces = new Set<string>();\n for (const site of moduleImports(source, ['import', 'export'])) {\n if (!FIRESTORE_SDK.test(site.spec) || site.typeOnly) continue;\n if (site.namespace) namespaces.add(site.namespace);\n for (const name of site.named)\n if (!name.typeOnly && CLIENT_WRITES.has(name.imported))\n hits.push({\n index: site.node.getStart(source),\n detail: `${name.imported} from '${site.spec}'`,\n });\n }\n forEachNode(source, (node) => {\n if (\n ts.isPropertyAccessExpression(node) &&\n ts.isIdentifier(node.expression) &&\n namespaces.has(node.expression.text) &&\n CLIENT_WRITES.has(node.name.text)\n )\n hits.push({ index: node.getStart(source), detail: node.getText(source) });\n });\n return hits;\n}\n\nexport const firestoreClientWritesGuard: GenericGuardDefinition<FirestoreClientWritesFacts> = {\n id: 'firestoreClientWrites',\n absentWhen: 'the app stores nothing in Firestore',\n factProblems(facts) {\n const problems: string[] = [];\n reviewedProblems(facts?.sanctioned, 'sanctioned', problems);\n return problems;\n },\n build(facts) {\n return [\n reviewedAllowlist({\n title: 'the client never writes Firestore',\n description:\n 'Every write goes through a callable that checks it on the server; a client SDK write skips that check and ' +\n 'every rule the callable enforces. Flagged: a runtime import of a Firestore write function (' +\n `${[...CLIENT_WRITES].join(', ')}) from the Firestore SDK, or a call to one through a namespace import, in ` +\n \"the app's client source. Fix: call the callable that owns the write. A sanctioned site is a reviewed entry \" +\n 'with its why; one that no longer writes is stale.',\n scope: APP_SOURCE,\n match: firestoreClientWriteHits,\n allowlist: facts.sanctioned,\n samples: {\n flags: [\n \"import { doc, setDoc } from 'firebase/firestore';\",\n \"import { writeBatch as batchOf } from 'firebase/firestore';\",\n \"import * as fs from 'firebase/firestore';\\nawait fs.updateDoc(ref, patch);\",\n ],\n passes: [\n \"import { doc, getDoc, onSnapshot } from 'firebase/firestore';\",\n \"import { type WriteBatch } from 'firebase/firestore';\",\n 'await callable({ id });',\n ],\n },\n }),\n ];\n },\n};\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ExpectedCodebase } from './deployed-functions.js';
|
|
2
|
+
import { type FunctionsManifest } from './functions-deploy-passes.js';
|
|
2
3
|
export declare function applyStorageCors(repoRoot: string, projectId: string): void;
|
|
3
4
|
export declare function checkCallableInvokers({ repoRoot, region, projectId: requested, extraPublicServices, }: {
|
|
4
5
|
repoRoot: string;
|
|
@@ -12,4 +13,12 @@ export declare function checkDeployedFunctions({ repoRoot, region, projectId: re
|
|
|
12
13
|
projectId: string | undefined;
|
|
13
14
|
expected: () => readonly ExpectedCodebase[];
|
|
14
15
|
}): void;
|
|
16
|
+
export declare function deployFunctionsInPasses({ repoRoot, region, projectId: requested, targets, manifest, nonFunctionTargets, }: {
|
|
17
|
+
repoRoot: string;
|
|
18
|
+
region: string;
|
|
19
|
+
projectId: string | undefined;
|
|
20
|
+
targets: string | undefined;
|
|
21
|
+
manifest: () => FunctionsManifest;
|
|
22
|
+
nonFunctionTargets: readonly string[];
|
|
23
|
+
}): void;
|
|
15
24
|
//# sourceMappingURL=cloud-checks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-checks.d.ts","sourceRoot":"","sources":["../../../src/node/tooling/cloud-checks.ts"],"names":[],"mappings":"AASA,OAAO,
|
|
1
|
+
{"version":3,"file":"cloud-checks.d.ts","sourceRoot":"","sources":["../../../src/node/tooling/cloud-checks.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,KAAK,gBAAgB,EAEtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAA4B,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAsDhG,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CA0B1E;AAED,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,MAAM,EACN,SAAS,EAAE,SAAS,EACpB,mBAAwB,GACzB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,GAAG,IAAI,CAwEP;AAED,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,MAAM,EACN,SAAS,EAAE,SAAS,EACpB,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,EAAE,MAAM,SAAS,gBAAgB,EAAE,CAAC;CAC7C,GAAG,IAAI,CAgDP;AAED,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,MAAM,EACN,SAAS,EAAE,SAAS,EACpB,OAAO,EACP,QAAQ,EACR,kBAAkB,GACnB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,iBAAiB,CAAC;IAClC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC,GAAG,IAAI,CAsCP"}
|
|
@@ -2,7 +2,8 @@ import { execFileSync } from 'node:child_process';
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { CALLABLE_LABEL_FILTER, assessInvokers, lines, } from './callable-invokers.js';
|
|
5
|
-
import { compareDeployedFunctions, parseLiveFunctions, } from './deployed-functions.js';
|
|
5
|
+
import { compareDeployedFunctions, parseLiveFunctions, targetedCodebases, } from './deployed-functions.js';
|
|
6
|
+
import { runFunctionsDeployPasses } from './functions-deploy-passes.js';
|
|
6
7
|
import { assertSafeCors, defaultStorageBucket, normalizeCors, readBucketCors, } from './storage-cors.js';
|
|
7
8
|
import { readFirebaseProjects } from './firebase-projects-file.js';
|
|
8
9
|
function gcloud(args, cwd) {
|
|
@@ -13,6 +14,15 @@ function gcloud(args, cwd) {
|
|
|
13
14
|
maxBuffer: 64 * 1024 * 1024,
|
|
14
15
|
});
|
|
15
16
|
}
|
|
17
|
+
function listLiveFunctions(projectId, region) {
|
|
18
|
+
return parseLiveFunctions(JSON.parse(gcloud([
|
|
19
|
+
'functions',
|
|
20
|
+
'list',
|
|
21
|
+
`--project=${projectId}`,
|
|
22
|
+
`--regions=${region}`,
|
|
23
|
+
'--format=json',
|
|
24
|
+
]) || '[]'));
|
|
25
|
+
}
|
|
16
26
|
function firstLine(error) {
|
|
17
27
|
const e = error;
|
|
18
28
|
return String(e?.stderr || e?.message || error).split('\n')[0];
|
|
@@ -114,13 +124,7 @@ export function checkDeployedFunctions({ repoRoot, region, projectId: requested,
|
|
|
114
124
|
}
|
|
115
125
|
let live;
|
|
116
126
|
try {
|
|
117
|
-
live =
|
|
118
|
-
'functions',
|
|
119
|
-
'list',
|
|
120
|
-
`--project=${projectId}`,
|
|
121
|
-
`--regions=${region}`,
|
|
122
|
-
'--format=json',
|
|
123
|
-
]) || '[]'));
|
|
127
|
+
live = listLiveFunctions(projectId, region);
|
|
124
128
|
}
|
|
125
129
|
catch (error) {
|
|
126
130
|
console.error(`::error::[deployed-functions] Could not list the functions on ${projectId} (${firstLine(error)}). The guard fails CLOSED.`);
|
|
@@ -143,4 +147,37 @@ export function checkDeployedFunctions({ repoRoot, region, projectId: requested,
|
|
|
143
147
|
const count = groups.reduce((n, g) => n + g.names.length, 0);
|
|
144
148
|
console.log(`[deployed-functions] OK — ${count} functions on ${projectId}: every expected function is live and ACTIVE, and nothing else is.`);
|
|
145
149
|
}
|
|
150
|
+
export function deployFunctionsInPasses({ repoRoot, region, projectId: requested, targets, manifest, nonFunctionTargets, }) {
|
|
151
|
+
const projectId = knownProject(repoRoot, requested, 'deploy-functions');
|
|
152
|
+
let codebases;
|
|
153
|
+
let selected;
|
|
154
|
+
try {
|
|
155
|
+
codebases = manifest();
|
|
156
|
+
selected = targetedCodebases(targets ?? '', Object.keys(codebases));
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
console.error(`::error::[deploy-functions] Could not read the deploy targets (${firstLine(error)}).`);
|
|
160
|
+
process.exit(2);
|
|
161
|
+
}
|
|
162
|
+
const pauseLock = new Int32Array(new SharedArrayBuffer(4));
|
|
163
|
+
const ok = runFunctionsDeployPasses({ targets: selected, manifest: codebases, nonFunctionTargets }, {
|
|
164
|
+
listLive: () => listLiveFunctions(projectId, region),
|
|
165
|
+
deploy: (only) => {
|
|
166
|
+
try {
|
|
167
|
+
execFileSync('firebase', ['deploy', '--only', only, '--project', projectId, '--non-interactive', '--force'], { cwd: repoRoot, stdio: 'inherit' });
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
pause: (ms) => {
|
|
175
|
+
Atomics.wait(pauseLock, 0, 0, ms);
|
|
176
|
+
},
|
|
177
|
+
log: (line) => console.log(line),
|
|
178
|
+
error: (line) => console.error(`::error::${line}`),
|
|
179
|
+
});
|
|
180
|
+
if (!ok)
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
146
183
|
//# sourceMappingURL=cloud-checks.js.map
|