agent-claw: automated task changes

This commit is contained in:
daniel
2026-05-06 18:55:16 -05:00
parent 38905bb1e9
commit 732b00fb66
8494 changed files with 2018127 additions and 4 deletions

View File

@@ -0,0 +1,47 @@
import { Construct } from 'constructs';
import * as codebuild from '../../../aws-codebuild';
import type * as cp from '../../../aws-codepipeline';
import type * as lambda from '../../../aws-lambda';
/**
* Properties for an ApplicationSecurityCheck
*/
export interface ApplicationSecurityCheckProps {
/**
* The pipeline that will be automatically approved
*
* Will have a tag added to it.
*/
readonly codePipeline: cp.Pipeline;
}
/**
* A construct containing both the Lambda and CodeBuild Project
* needed to conduct a security check on any given application stage.
*
* The Lambda acts as an auto approving mechanism that should only be
* triggered when the CodeBuild Project registers no security changes.
*
* The CodeBuild Project runs a security diff on the application stage,
* and exports the link to the console of the project.
*/
export declare class ApplicationSecurityCheck extends Construct {
/**
* A lambda function that approves a Manual Approval Action, given
* the following payload:
*
* {
* "PipelineName": [CodePipelineName],
* "StageName": [CodePipelineStageName],
* "ActionName": [ManualApprovalActionName]
* }
*/
readonly preApproveLambda: lambda.Function;
/**
* A CodeBuild Project that runs a security diff on the application stage.
*
* - If the diff registers no security changes, CodeBuild will invoke the
* pre-approval lambda and approve the ManualApprovalAction.
* - If changes are detected, CodeBuild will exit into a ManualApprovalAction
*/
readonly cdkDiffProject: codebuild.Project;
constructor(scope: Construct, id: string, props: ApplicationSecurityCheckProps);
}

View File

@@ -0,0 +1,2 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ApplicationSecurityCheck=void 0;var constructs_1=()=>{var tmp=require("constructs");return constructs_1=()=>tmp,tmp},default_codebuild_image_1=()=>{var tmp=require("./default-codebuild-image");return default_codebuild_image_1=()=>tmp,tmp},codebuild=()=>{var tmp=require("../../../aws-codebuild");return codebuild=()=>tmp,tmp},iam=()=>{var tmp=require("../../../aws-iam");return iam=()=>tmp,tmp},core_1=()=>{var tmp=require("../../../core");return core_1=()=>tmp,tmp},approve_lambda_generated_1=()=>{var tmp=require("../../../custom-resource-handlers/dist/pipelines/approve-lambda.generated");return approve_lambda_generated_1=()=>tmp,tmp};class ApplicationSecurityCheck extends constructs_1().Construct{preApproveLambda;cdkDiffProject;constructor(scope,id,props){super(scope,id),core_1().Tags.of(props.codePipeline).add("SECURITY_CHECK","ALLOW_APPROVE",{includeResourceTypes:["AWS::CodePipeline::Pipeline"]}),this.preApproveLambda=new(approve_lambda_generated_1()).ApproveLambdaFunction(this,"CDKPipelinesAutoApprove",{timeout:core_1().Duration.minutes(5)}),this.preApproveLambda.addToRolePolicy(new(iam()).PolicyStatement({actions:["codepipeline:GetPipelineState","codepipeline:PutApprovalResult"],conditions:{StringEquals:{"aws:ResourceTag/SECURITY_CHECK":"ALLOW_APPROVE"}},resources:["*"]}));const invokeLambda=`aws lambda invoke --function-name ${this.preApproveLambda.functionName} --invocation-type Event --cli-binary-format raw-in-base64-out --payload "$payload" lambda.out`,publishNotification=`aws sns publish --topic-arn $NOTIFICATION_ARN --subject "$NOTIFICATION_SUBJECT" --message "${["An upcoming change would broaden security changes in $PIPELINE_NAME.","Review and approve the changes in CodePipeline to proceed with the deployment.","","Review the changes in CodeBuild:","","$LINK","","Approve the changes in CodePipeline (stage $STAGE_NAME, action $ACTION_NAME):","","$PIPELINE_LINK"].join(`
`)}"`;this.cdkDiffProject=new(codebuild()).Project(this,"CDKSecurityCheck",{environment:{buildImage:default_codebuild_image_1().CDKP_DEFAULT_CODEBUILD_IMAGE},buildSpec:codebuild().BuildSpec.fromObject({version:.2,phases:{build:{commands:["npm install -g aws-cdk",'export PIPELINE_NAME="$(node -pe \'`${process.env.CODEBUILD_INITIATOR}`.split("/")[1]\')"',`payload="$(node -pe 'JSON.stringify({ "PipelineName": process.env.PIPELINE_NAME, "StageName": process.env.STAGE_NAME, "ActionName": process.env.ACTION_NAME })' )"`,"ARN=$CODEBUILD_BUILD_ARN",'REGION="$(node -pe \'`${process.env.ARN}`.split(":")[3]\')"','ACCOUNT_ID="$(node -pe \'`${process.env.ARN}`.split(":")[4]\')"','PROJECT_NAME="$(node -pe \'`${process.env.ARN}`.split(":")[5].split("/")[1]\')"','PROJECT_ID="$(node -pe \'`${process.env.ARN}`.split(":")[6]\')"','export LINK="https://$REGION.console.aws.amazon.com/codesuite/codebuild/$ACCOUNT_ID/projects/$PROJECT_NAME/build/$PROJECT_NAME:$PROJECT_ID/?region=$REGION"','export PIPELINE_LINK="https://$REGION.console.aws.amazon.com/codesuite/codepipeline/pipelines/$PIPELINE_NAME/view?region=$REGION"',ifElse({condition:"cdk diff -a . --security-only --fail $STAGE_PATH/\\*",thenStatements:[invokeLambda,'export MESSAGE="No security-impacting changes detected."'],elseStatements:[`[ -z "\${NOTIFICATION_ARN}" ] || ${publishNotification}`,'export MESSAGE="Deployment would make security-impacting changes. Click the link below to inspect them, then click Approve if all changes are expected."']})]}},env:{"exported-variables":["LINK","MESSAGE"]}})}),this.cdkDiffProject.addToRolePolicy(new(iam()).PolicyStatement({actions:["sts:AssumeRole"],resources:["*"],conditions:{"ForAnyValue:StringEquals":{"iam:ResourceTag/aws-cdk:bootstrap-role":["deploy"]}}})),this.preApproveLambda.grantInvoke(this.cdkDiffProject)}}exports.ApplicationSecurityCheck=ApplicationSecurityCheck;const ifElse=({condition,thenStatements,elseStatements})=>{let statement=thenStatements.reduce((acc,ifTrue)=>`${acc} ${ifTrue};`,`if ${condition}; then`);return elseStatements&&(statement=elseStatements.reduce((acc,ifFalse)=>`${acc} ${ifFalse};`,`${statement} else`)),`${statement} fi`};

View File

@@ -0,0 +1,159 @@
import type { AssetManifest, AwsDestination, DockerImageDestination, DockerImageSource, FileDestination, FileSource } from '../../../cloud-assembly-schema';
/**
* A manifest of assets
*/
export declare class AssetManifestReader {
private readonly manifest;
/**
* The default name of the asset manifest in a cdk.out directory
*/
static readonly DEFAULT_FILENAME = "assets.json";
/**
* Load an asset manifest from the given file
*/
static fromFile(fileName: string): AssetManifestReader;
/**
* Load an asset manifest from the given file or directory
*
* If the argument given is a directoy, the default asset file name will be used.
*/
static fromPath(filePath: string): AssetManifestReader;
/**
* The directory where the manifest was found
*/
readonly directory: string;
constructor(directory: string, manifest: AssetManifest);
/**
* Select a subset of assets and destinations from this manifest.
*
* Only assets with at least 1 selected destination are retained.
*
* If selection is not given, everything is returned.
*/
select(selection?: DestinationPattern[]): AssetManifestReader;
/**
* Describe the asset manifest as a list of strings
*/
list(): string[];
/**
* List of assets, splat out to destinations
*/
get entries(): IManifestEntry[];
}
/**
* A single asset from an asset manifest'
*/
export interface IManifestEntry {
/**
* The identifier of the asset
*/
readonly id: DestinationIdentifier;
/**
* The type of asset
*/
readonly type: string;
/**
* Type-dependent source data
*/
readonly genericSource: unknown;
/**
* Type-dependent destination data
*/
readonly destination: AwsDestination;
/**
* A display name for this asset manifest entry, if given
*/
readonly displayName?: string;
}
/**
* A manifest entry for a file asset
*/
export declare class FileManifestEntry implements IManifestEntry {
/** Identifier for this asset */
readonly id: DestinationIdentifier;
/** Source of the file asset */
readonly source: FileSource;
/** Destination for the file asset */
readonly destination: FileDestination;
/** Display name for the file asset */
readonly displayName?: string | undefined;
readonly genericSource: unknown;
readonly type = "file";
constructor(
/** Identifier for this asset */
id: DestinationIdentifier,
/** Source of the file asset */
source: FileSource,
/** Destination for the file asset */
destination: FileDestination,
/** Display name for the file asset */
displayName?: string | undefined);
}
/**
* A manifest entry for a docker image asset
*/
export declare class DockerImageManifestEntry implements IManifestEntry {
/** Identifier for this asset */
readonly id: DestinationIdentifier;
/** Source of the file asset */
readonly source: DockerImageSource;
/** Destination for the file asset */
readonly destination: DockerImageDestination;
/** Display name for the file asset */
readonly displayName?: string | undefined;
readonly genericSource: unknown;
readonly type = "docker-image";
constructor(
/** Identifier for this asset */
id: DestinationIdentifier,
/** Source of the file asset */
source: DockerImageSource,
/** Destination for the file asset */
destination: DockerImageDestination,
/** Display name for the file asset */
displayName?: string | undefined);
}
/**
* Identify an asset destination in an asset manifest
*/
export declare class DestinationIdentifier {
/**
* Identifies the asset, by source.
*/
readonly assetId: string;
/**
* Identifies the destination where this asset will be published
*/
readonly destinationId: string;
constructor(assetId: string, destinationId: string);
/**
* Return a string representation for this asset identifier
*/
toString(): string;
}
/**
* A filter pattern for an destination identifier
*/
export declare class DestinationPattern {
/**
* Parse a ':'-separated string into an asset/destination identifier
*/
static parse(s: string): DestinationPattern;
/**
* Identifies the asset, by source.
*/
readonly assetId?: string;
/**
* Identifies the destination where this asset will be published
*/
readonly destinationId?: string;
constructor(assetId?: string, destinationId?: string);
/**
* Whether or not this pattern matches the given identifier
*/
matches(id: DestinationIdentifier): boolean;
/**
* Return a string representation for this asset identifier
*/
toString(): string;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
import type { Construct } from 'constructs';
import * as iam from '../../../aws-iam';
import type { PolicyStatement } from '../../../aws-iam';
/**
* Role which will be reused across asset jobs
*
* Has some '*' resources to save IAM policy space, and will not
* actually add policies that look like policies that were already added.
*/
export declare class AssetSingletonRole extends iam.Role {
/** Uniquely identifies this class. */
static readonly PROPERTY_INJECTION_ID: string;
private _rejectDuplicates;
private _assumeRoleStatement;
constructor(scope: Construct, id: string, props: iam.RoleProps);
addToPrincipalPolicy(statement: PolicyStatement): iam.AddToPrincipalPolicyResult;
/**
* Make sure the Role has sts:AssumeRole permissions to the given ARN
*
* Will add a new PolicyStatement to the Role if necessary, otherwise add resources to the existing
* PolicyStatement.
*
* Normally this would have been many `grantAssume()` calls (which would get deduplicated by the
* policy minimization logic), but we have to account for old pipelines that don't have policy
* minimization enabled.
*/
addAssumeRole(roleArn: string): void;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
/**
* Wrap a string in `Fn.sub`, but return the same `Fn.sub` value for the same string
*
* If we don't do this, every new `Fn.sub()` creates a new `IResolvable` instance
* which will stringify to a unique string value, and we can't dedupe the stringified
* values anymore.
*
* Potentially we could/should do deduplication in the token system itself, but
* we would have to be consistent about it and do it for all tokens, which has
* an unpredictable memory impact and I'm scared of making such a sweeping
* change. Hence, a local solution to a local problem.
*/
export declare class CachedFnSub {
private cache;
fnSub(x: string): string;
}

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.CachedFnSub=void 0;var core_1=()=>{var tmp=require("../../../core");return core_1=()=>tmp,tmp};class CachedFnSub{cache=new Map;fnSub(x){const existing=this.cache.get(x);if(existing)return existing;const ret=core_1().Fn.sub(x);return this.cache.set(x,ret),ret}}exports.CachedFnSub=CachedFnSub;

View File

@@ -0,0 +1,3 @@
import type * as cxapi from '../../../cx-api';
export declare function isAssetManifest(s: cxapi.CloudArtifact): s is cxapi.AssetManifestArtifact;
export declare function isStackArtifact(a: cxapi.CloudArtifact): a is cxapi.CloudFormationStackArtifact;

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.isAssetManifest=isAssetManifest,exports.isStackArtifact=isStackArtifact;function isAssetManifest(s){return s.constructor.name==="AssetManifestArtifact"}function isStackArtifact(a){return a.constructor.name==="CloudFormationStackArtifact"}

View File

@@ -0,0 +1,16 @@
import type { IConstruct } from 'constructs';
import { Construct } from 'constructs';
import { App, Stage } from '../../../core';
import type * as cxapi from '../../../cx-api';
export declare function appOf(construct: IConstruct): App;
export declare function assemblyBuilderOf(stage: Stage): cxapi.CloudAssemblyBuilder;
export declare function pipelineSynth(stage: Stage): cxapi.CloudAssembly;
/**
* Return the relative path from the app assembly to the scope's (nested) assembly
*/
export declare function embeddedAsmPath(scope: IConstruct): string;
/**
* Determine the directory where the cloud assembly will be written, for use in a BuildSpec
*/
export declare function cloudAssemblyBuildSpecDir(scope: IConstruct): string;
export declare function obtainScope(parent: Construct, id: string): Construct;

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.appOf=appOf,exports.assemblyBuilderOf=assemblyBuilderOf,exports.pipelineSynth=pipelineSynth,exports.embeddedAsmPath=embeddedAsmPath,exports.cloudAssemblyBuildSpecDir=cloudAssemblyBuildSpecDir,exports.obtainScope=obtainScope;var path=()=>{var tmp=require("path");return path=()=>tmp,tmp},constructs_1=()=>{var tmp=require("constructs");return constructs_1=()=>tmp,tmp},core_1=()=>{var tmp=require("../../../core");return core_1=()=>tmp,tmp},literal_string_1=()=>{var tmp=require("../../../core/lib/private/literal-string");return literal_string_1=()=>tmp,tmp};function appOf(construct){const root=constructs_1().Node.of(construct).root;if(!core_1().App.isApp(root))throw new(core_1()).ValidationError((0,literal_string_1().lit)`ConstructCreatedApp`,`Construct must be created under an App, but is not: ${constructs_1().Node.of(construct).path}`,construct);return root}function assemblyBuilderOf(stage){return stage._assemblyBuilder}function pipelineSynth(stage){return stage.synth({validateOnSynthesis:!0})}function embeddedAsmPath(scope){const appAsmRoot=assemblyBuilderOf(appOf(scope)).outdir,stage=core_1().Stage.of(scope)??appOf(scope),stageAsmRoot=assemblyBuilderOf(stage).outdir;return path().relative(appAsmRoot,stageAsmRoot)||"."}function cloudAssemblyBuildSpecDir(scope){return assemblyBuilderOf(appOf(scope)).outdir}function obtainScope(parent,id){const existing=constructs_1().Node.of(parent).tryFindChild(id);return existing||new(constructs_1()).Construct(parent,id)}

View File

@@ -0,0 +1 @@
export declare const CDKP_DEFAULT_CODEBUILD_IMAGE: import("../../../aws-codebuild").IBuildImage;

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.CDKP_DEFAULT_CODEBUILD_IMAGE=void 0;var aws_codebuild_1=()=>{var tmp=require("../../../aws-codebuild");return aws_codebuild_1=()=>tmp,tmp};exports.CDKP_DEFAULT_CODEBUILD_IMAGE=aws_codebuild_1().LinuxBuildImage.STANDARD_7_0;

View File

@@ -0,0 +1,9 @@
/**
* Convert a file path on the current system to a file path that can be used on Linux
*
* Takes the current OS' file separator and replaces all of them with a '/'.
*
* Relevant if the current system is a Windows machine but is generating
* commands for a Linux CodeBuild image.
*/
export declare function toPosixPath(osPath: string, currentSep?: string): string;

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.toPosixPath=toPosixPath;var path=()=>{var tmp=require("path");return path=()=>tmp,tmp};function toPosixPath(osPath,currentSep){const regex=new RegExp(`\\${currentSep??path().sep}`,"g");return osPath.replace(regex,"/")}

View File

@@ -0,0 +1,12 @@
import type { StackDeployment } from '../blueprint/stack-deployment';
import type { GraphNode } from '../helpers-internal/graph';
export declare function hash<A>(obj: A): string;
export declare function actionName<A>(node: GraphNode<A>, parent: GraphNode<A>): string;
export declare function stackVariableNamespace(stack: StackDeployment): string;
/**
* Makes sure the given identifier length does not exceed N characters
*
* Replaces characters in the middle (to leave the start and end identifiable) and replaces
* them with a hash to prevent collissions.
*/
export declare function limitIdentifierLength(s: string, n: number): string;

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.hash=hash,exports.actionName=actionName,exports.stackVariableNamespace=stackVariableNamespace,exports.limitIdentifierLength=limitIdentifierLength;var crypto=()=>{var tmp=require("crypto");return crypto=()=>tmp,tmp};function hash(obj){const d=crypto().createHash("sha256");return d.update(JSON.stringify(obj)),d.digest("hex")}function actionName(node,parent){const names=node.ancestorPath(parent).map(n=>n.displayName??n.id).map(sanitizeName),totalMax=100;if(names.join(".").length<=totalMax)return names.join(".");const componentMin=15,dots=names.length-1,maxLength=Math.max(componentMin,Math.floor((totalMax-dots)/names.length)),trimmedNames=names.map(name=>limitIdentifierLength(name,maxLength));return limitIdentifierLength(trimmedNames.join("."),totalMax-2)}function stackVariableNamespace(stack){return limitIdentifierLength(stack.stackArtifactId,100)}function sanitizeName(x){return x.replace(/[^A-Za-z0-9.@\-_]+/g,"_")}function limitIdentifierLength(s,n){if(s.length<=n)return s;const h=hash(s).slice(0,8),mid=Math.floor((n-h.length)/2);return s.slice(0,mid)+h+s.slice(-mid)}

View File

@@ -0,0 +1,17 @@
export declare function addAll<A>(into: Set<A>, from: Iterable<A>): void;
export declare function extract<A, B>(from: Map<A, B>, key: A): B | undefined;
export declare function flatMap<A, B>(xs: Iterable<A>, fn: (x: A) => Iterable<B>): IterableIterator<B>;
export declare function enumerate<A>(xs: Iterable<A>): IterableIterator<[number, A]>;
export declare function expectProp<A extends object, B extends keyof A>(obj: A, key: B): NonNullable<A[B]>;
export declare function flatten<A>(xs: Iterable<A[]>): IterableIterator<A>;
export declare function filterEmpty(xs: Array<string | undefined>): string[];
export declare function mapValues<A, B>(xs: Record<string, A>, fn: (x: A) => B): Record<string, B>;
export declare function mkdict<A>(xs: Array<readonly [string, A]>): Record<string, A>;
export declare function noEmptyObject<A>(xs: Record<string, A>): Record<string, A> | undefined;
export declare function noUndefined<A>(xs: Record<string, A>): Record<string, NonNullable<A>>;
export declare function maybeSuffix(x: string | undefined, suffix: string): string | undefined;
/**
* Partition a collection by dividing it into two collections, one that matches the predicate and one that don't
*/
export declare function partition<T>(xs: T[], pred: (x: T) => boolean): [T[], T[]];
export declare function isDefined<A>(x: A): x is NonNullable<A>;

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.addAll=addAll,exports.extract=extract,exports.flatMap=flatMap,exports.enumerate=enumerate,exports.expectProp=expectProp,exports.flatten=flatten,exports.filterEmpty=filterEmpty,exports.mapValues=mapValues,exports.mkdict=mkdict,exports.noEmptyObject=noEmptyObject,exports.noUndefined=noUndefined,exports.maybeSuffix=maybeSuffix,exports.partition=partition,exports.isDefined=isDefined;var core_1=()=>{var tmp=require("../../../core");return core_1=()=>tmp,tmp},literal_string_1=()=>{var tmp=require("../../../core/lib/private/literal-string");return literal_string_1=()=>tmp,tmp};function addAll(into,from){for(const x of from)into.add(x)}function extract(from,key){const ret=from.get(key);return from.delete(key),ret}function*flatMap(xs,fn){for(const x of xs)for(const y of fn(x))yield y}function*enumerate(xs){let i=0;for(const x of xs)yield[i++,x]}function expectProp(obj,key){if(!obj[key])throw new(core_1()).UnscopedValidationError((0,literal_string_1().lit)`ExpectingSet`,`Expecting '${String(key)}' to be set!`);return obj[key]}function*flatten(xs){for(const x of xs)for(const y of x)yield y}function filterEmpty(xs){return xs.filter(x=>x)}function mapValues(xs,fn){const ret={};for(const[k,v]of Object.entries(xs))ret[k]=fn(v);return ret}function mkdict(xs){const ret={};for(const[k,v]of xs)ret[k]=v;return ret}function noEmptyObject(xs){if(Object.keys(xs).length!==0)return xs}function noUndefined(xs){return mkdict(Object.entries(xs).filter(([_,v])=>isDefined(v)))}function maybeSuffix(x,suffix){if(x!==void 0)return`${x}${suffix}`}function partition(xs,pred){const yes=[],no=[];for(const x of xs)(pred(x)?yes:no).push(x);return[yes,no]}function isDefined(x){return x!==void 0}

View File

@@ -0,0 +1,16 @@
/**
* Write template configuration to the given file
*/
export declare function writeTemplateConfiguration(filename: string, config: TemplateConfiguration): void;
/**
* Template configuration in a CodePipeline
*
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-cfn-artifacts.html#w2ab1c13c17c15
*/
export interface TemplateConfiguration {
readonly Parameters?: Record<string, string>;
readonly Tags?: Record<string, string>;
readonly StackPolicy?: {
readonly Statements: Array<Record<string, string>>;
};
}

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.writeTemplateConfiguration=writeTemplateConfiguration;var fs=()=>{var tmp=require("fs");return fs=()=>tmp,tmp};function writeTemplateConfiguration(filename,config){fs().writeFileSync(filename,JSON.stringify(config,void 0,2),{encoding:"utf-8"})}

View File

@@ -0,0 +1,13 @@
export type KeyFunc<T> = (x: T) => string;
export type DepFunc<T> = (x: T) => string[];
/**
* Return a topological sort of all elements of xs, according to the given dependency functions
*
* Dependencies outside the referenced set are ignored.
*
* Not a stable sort, but in order to keep the order as stable as possible, we'll sort by key
* among elements of equal precedence.
*
* Returns tranches of elements of equal precedence.
*/
export declare function topologicalSort<T>(xs: Iterable<T>, keyFn: KeyFunc<T>, depFn: DepFunc<T>): T[][];

View File

@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.topologicalSort=topologicalSort;var core_1=()=>{var tmp=require("../../../core");return core_1=()=>tmp,tmp},literal_string_1=()=>{var tmp=require("../../../core/lib/private/literal-string");return literal_string_1=()=>tmp,tmp};function topologicalSort(xs,keyFn,depFn){const remaining=new Map;for(const element of xs){const key=keyFn(element);remaining.set(key,{key,element,dependencies:depFn(element)})}const ret=new Array;for(;remaining.size>0;){const selectable=Array.from(remaining.values()).filter(e=>e.dependencies.every(d=>!remaining.has(d)));if(selectable.sort((a,b)=>a.key<b.key?-1:b.key<a.key?1:0),selectable.length===0)throw new(core_1()).UnscopedValidationError((0,literal_string_1().lit)`CouldDetermineOrderingBetween`,`Could not determine ordering between: ${Array.from(remaining.keys()).join(", ")}`);ret.push(selectable.map(s=>s.element));for(const selected of selectable)remaining.delete(selected.key)}return ret}