diff --git a/.eslintrc.json b/.eslintrc.json index e3436242..30965b3e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -47,6 +47,10 @@ "node_modules/", "*.generated.ts", "coverage", + "e2e/helpers/exec.ts", + "e2e/helpers/lambda-telemetry-checker.ts", + "e2e/helpers/lambda-verifier.ts", + "e2e/helpers/naming.ts", "!.projenrc.ts", "!projenrc/**/*.ts" ], @@ -154,6 +158,7 @@ "devDependencies": [ "**/test/**", "**/build-tools/**", + "e2e/**", ".projenrc.ts", "projenrc/**/*.ts" ], diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 00000000..ac041c9a --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,78 @@ +name: e2e + +# Full instrumentation lifecycle against a live, ephemeral Lambda function. +on: + push: + branches: [main] + paths: + - "src/**" + - "e2e/**" + - "package.json" + - "yarn.lock" + - ".github/workflows/e2e.yml" + pull_request: + paths: + - "src/**" + - "e2e/**" + - "package.json" + - "yarn.lock" + - ".github/workflows/e2e.yml" + workflow_dispatch: + +jobs: + lambda-e2e: + # Fork pull requests cannot use the canonical repository's OIDC identities. + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + env: + AWS_REGION: ${{ vars.AWS_REGION_E2E || 'ap-northeast-3' }} + DD_SITE: ${{ vars.DD_SITE_E2E || 'datadoghq.com' }} + steps: + - name: Checkout + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + + # Enable Corepack before setup-node so its package-manager cache step detects + # the yarn berry version from package.json instead of falling back to yarn 1. + - name: Enable Corepack + run: corepack enable + + - name: Set up Node 24 + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5 + with: + node-version: 24 + + - name: Install dependencies + run: yarn install --immutable + + # Dedicated GitHub-OIDC role in the serverless sandbox account, scoped to deploy + # one-e2e-cdk-lambda-* via the CDK bootstrap roles. See serverless-ci/e2e/iam-infra.md. + - name: Configure AWS credentials via OIDC + uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 + with: + role-to-assume: ${{ vars.AWS_ROLE_ARN_E2E }} + aws-region: ${{ env.AWS_REGION }} + + # Short-lived Datadog API + App keys via OIDC federation (dd-sts), governed by the + # policy in dd-source. No static Datadog keys are stored in this repo. + - name: Get Datadog credentials (dd-sts) + id: dd-sts + uses: DataDog/dd-sts-action@2e8187910199bd93129520183c093e19aa585c75 # v1.0.0 + with: + policy: datadog-cdk-constructs-e2e + + # The account is already CDK-bootstrapped; deploy reads the bootstrap version + # from SSM, so no bootstrap step is needed. + - name: Resolve account id + run: echo "CDK_DEFAULT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)" >> "$GITHUB_ENV" + + - name: Run Lambda e2e suite + run: yarn test:e2e + env: + # Baked into the function at synth + used by the construct/extension. + DD_API_KEY: ${{ steps.dd-sts.outputs.api_key }} + # Used by the telemetry checker to query spans/logs. + DATADOG_API_KEY: ${{ steps.dd-sts.outputs.api_key }} + DATADOG_APP_KEY: ${{ steps.dd-sts.outputs.app_key }} diff --git a/.gitignore b/.gitignore index a439a2f1..b49b393e 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,8 @@ test/__snapshots__ .DS_Store integration_tests/cdk.out integration_tests/testlib +e2e/.build +e2e/.env.local bin obj __pycache__ diff --git a/.npmignore b/.npmignore index 56b1a8d3..60bd6dbf 100644 --- a/.npmignore +++ b/.npmignore @@ -4,6 +4,7 @@ !NOTICE /scripts /integration_tests +/e2e .prettierrc /.ncurc.cjs cdk.out/* diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..05e6d1c2 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +# Synced from serverless-ci/e2e/shared by the e2e-shared sync. Generated code is not +# hand-formatted here -- the source-of-truth style can't satisfy every consumer's +# prettier config, so the formatter skips these files. +e2e/helpers/exec.ts +e2e/helpers/naming.ts +e2e/helpers/lambda-telemetry-checker.ts +e2e/helpers/lambda-verifier.ts diff --git a/.projen/deps.json b/.projen/deps.json index 43256515..155c3b4b 100644 --- a/.projen/deps.json +++ b/.projen/deps.json @@ -5,6 +5,11 @@ "version": "^2.134.0-alpha.0", "type": "build" }, + { + "name": "@datadog/datadog-api-client", + "version": "^1.34.1", + "type": "build" + }, { "name": "@stylistic/eslint-plugin", "version": "^2", @@ -105,6 +110,11 @@ "name": "typescript", "type": "build" }, + { + "name": "vitest", + "version": "^3.2.4", + "type": "build" + }, { "name": "loglevel", "type": "bundled" diff --git a/.projen/tasks.json b/.projen/tasks.json index 072902b2..6b608fb6 100644 --- a/.projen/tasks.json +++ b/.projen/tasks.json @@ -30,7 +30,7 @@ "name": "check-formatting", "steps": [ { - "exec": "prettier --check src/**/*.ts integration_tests/**/*.ts examples/**/*.ts" + "exec": "prettier --check src/**/*.ts integration_tests/**/*.ts examples/**/*.ts e2e/*.ts e2e/app/**/*.ts e2e/helpers/e2e.config.ts" } ] }, @@ -87,7 +87,7 @@ }, "steps": [ { - "exec": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern $@ src test build-tools projenrc .projenrc.ts", + "exec": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern $@ src test build-tools e2e projenrc .projenrc.ts", "receiveArgs": true } ] @@ -230,6 +230,14 @@ } ] }, + "test:e2e": { + "name": "test:e2e", + "steps": [ + { + "exec": "tsc --noEmit -p e2e/tsconfig.json && vitest run --config e2e/vitest.config.ts e2e" + } + ] + }, "test:watch": { "name": "test:watch", "description": "Run jest in watch mode", @@ -269,6 +277,7 @@ "up", "-R", "@aws-cdk/aws-lambda-python-alpha", + "@datadog/datadog-api-client", "@stylistic/eslint-plugin", "@types/jest", "@types/node", @@ -292,6 +301,7 @@ "ts-jest", "ts-node", "typescript", + "vitest", "loglevel", "aws-cdk-lib", "constructs" diff --git a/.projenrc.ts b/.projenrc.ts index e16dfba8..c9812b80 100644 --- a/.projenrc.ts +++ b/.projenrc.ts @@ -47,6 +47,9 @@ const project = new awscdk.AwsCdkConstructLibrary({ "esbuild", "standard-version", "@aws-cdk/aws-lambda-python-alpha@^2.134.0-alpha.0", + // e2e suite (runs out of e2e/, separate from the jsii-packaged library) + "vitest@^3.2.4", + "@datadog/datadog-api-client@^1.34.1", ], gitignore: [ "*.js", @@ -63,6 +66,8 @@ const project = new awscdk.AwsCdkConstructLibrary({ ".DS_Store", "integration_tests/cdk.out", "integration_tests/testlib", + "e2e/.build", + "e2e/.env.local", "bin", "obj", "__pycache__", @@ -76,6 +81,7 @@ const project = new awscdk.AwsCdkConstructLibrary({ "!NOTICE", "/scripts", "/integration_tests", + "/e2e", ".prettierrc", "/.ncurc.cjs", "cdk.out/*", @@ -183,6 +189,12 @@ project.github?.tryFindWorkflow("upgrade")?.file?.patch( }), ); +project.eslint?.addLintPattern("e2e"); +project.eslint?.allowDevDeps("e2e/**"); +for (const helper of ["exec.ts", "lambda-telemetry-checker.ts", "lambda-verifier.ts", "naming.ts"]) { + project.eslint?.addIgnorePattern(`e2e/helpers/${helper}`); +} + const eslintConfig = project.tryFindObjectFile(".eslintrc.json")!; eslintConfig.addOverride("extends", [ "plugin:@typescript-eslint/recommended", @@ -272,7 +284,10 @@ npmScripts.addDeletionOverride("scripts.compat"); projenTasks.addDeletionOverride("scripts.test:compile"); // Replaces the removed `scripts` project option (dropped in projen 0.100/0.101). project.addTask("check-formatting", { - exec: "prettier --check src/**/*.ts integration_tests/**/*.ts examples/**/*.ts", + exec: "prettier --check src/**/*.ts integration_tests/**/*.ts examples/**/*.ts e2e/*.ts e2e/app/**/*.ts e2e/helpers/e2e.config.ts", +}); +project.addTask("test:e2e", { + exec: "tsc --noEmit -p e2e/tsconfig.json && vitest run --config e2e/vitest.config.ts e2e", }); project.addTask("create-release", { exec: "bash scripts/create_release.sh", diff --git a/e2e/README.md b/e2e/README.md new file mode 100644 index 00000000..3c058712 --- /dev/null +++ b/e2e/README.md @@ -0,0 +1,35 @@ +# Lambda E2E tests + +The suite runs the `DatadogLambda` construct against a temporary AWS Lambda function: + +1. Deploy the uninstrumented function. +2. Apply the construct and verify its layers, handler, runtime, environment, and tags. +3. Invoke the function and wait for matching spans and logs in Datadog. +4. Confirm `cdk diff --fail` reports no changes. +5. Destroy the stack and verify the function is gone. + +Layer and runtime versions are pinned in [`helpers/versions.ts`](helpers/versions.ts). + +## Run locally + +You need Node 22+, Yarn, AWS credentials for a CDK-bootstrapped account, and Datadog API and application keys for the serverless org. + +```bash +aws-vault exec sso-serverless-sandbox-account-admin -- \ + dd-auth --domain ddserverless.datadoghq.com -- bash -c ' + export DATADOG_API_KEY="$DD_API_KEY" DATADOG_APP_KEY="$DD_APP_KEY" + yarn test:e2e + ' +``` + +The suite defaults to `ap-northeast-3` and `datadoghq.com`. Set `AWS_REGION` or `DD_SITE` to override them. + +## CI + +[The E2E workflow](../.github/workflows/e2e.yml) runs when the construct or suite changes. It assumes the repository's AWS role through GitHub OIDC and obtains short-lived Datadog keys through `dd-sts`; missing credentials fail the run. + +The workflow uses `AWS_ROLE_ARN_E2E`, `AWS_REGION_E2E`, and `DD_SITE_E2E` repository variables. The AWS account must be CDK-bootstrapped. + +## Resource cleanup + +Each run uses a unique `one-e2e-cdk-lambda-` name and stamps its run ID and creation time on the function. The test always attempts `cdk destroy`; the cross-repository sweeper removes resources left by interrupted runs. diff --git a/e2e/helpers/e2e.config.ts b/e2e/helpers/e2e.config.ts new file mode 100644 index 00000000..9aa162aa --- /dev/null +++ b/e2e/helpers/e2e.config.ts @@ -0,0 +1,78 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2026 Datadog, Inc. + */ + +import { type ExpectedLayers, type LambdaVerifierConfig } from "./lambda-verifier"; +import { type E2ENaming, RUN_ID_TAG_KEY } from "./naming"; +import { E2E_EXTENSION_LAYER_VERSION, E2E_NODE_LAYER_VERSION } from "../app/versions"; + +// Repo-local config feeding the shared e2e helpers. This file is NOT synced -- it holds +// everything specific to datadog-cdk-constructs that the shared, parameterized helpers +// read through their config arguments. + +export const NAMING: E2ENaming = { tool: "cdk", platform: "lambda" }; + +export const ENV_NAME = process.env.E2E_ENV ?? "e2e"; +export const ENV_VERSION = process.env.E2E_VERSION ?? "1.0.0"; + +// Datadog's public layer account (commercial, non-GovCloud). The e2e defaults to ap-northeast-3. +const DD_ACCOUNT_ID = "464622532012"; + +// Transient cloud-provider errors safe to retry, passed as ExecOptions.retryPatterns. +export const RETRY_PATTERNS = [ + "RequestTimeout", + "Throttling", + "TooManyRequests", + "Rate exceeded", + "ServiceUnavailable", + "InternalFailure", + "ResourceConflictException", + "OperationAbortedException", + "ETIMEDOUT", + "ECONNRESET", + "EAI_AGAIN", + "Connection reset", + "timed out", + "UPDATE_IN_PROGRESS", +]; + +// The CDK app names the function after the run-unique service name, so the deployed +// function name is the service name itself. +export const functionName = (serviceName: string): string => serviceName; + +// Pinned artifact versions come from this repo's e2e/helpers/versions.ts, so a version +// mismatch blames the construct's wiring, not upstream layer drift. +export const expectedLayerArns = (region: string): ExpectedLayers => ({ + node: `arn:aws:lambda:${region}:${DD_ACCOUNT_ID}:layer:Datadog-Node22-x:${E2E_NODE_LAYER_VERSION}`, + extension: `arn:aws:lambda:${region}:${DD_ACCOUNT_ID}:layer:Datadog-Extension:${E2E_EXTENSION_LAYER_VERSION}`, +}); + +export const verifierConfig = (site: string, runId: string): LambdaVerifierConfig => ({ + functionName, + expectedLayerArns, + redirectHandler: "/opt/nodejs/node_modules/datadog-lambda-js/handler.handler", + originalHandler: "index.handler", + // The construct tags every instrumented function with its own marker tag. + toolTag: { key: "dd_cdk_construct", pattern: /.+/ }, + env: { + apiKeyVars: ["DD_API_KEY", "DD_API_KEY_SECRET_ARN", "DD_KMS_API_KEY", "DD_API_KEY_SSM_ARN"], + present: [], + values: (serviceName) => ({ + DD_SERVICE: serviceName, + DD_ENV: ENV_NAME, + DD_VERSION: ENV_VERSION, + DD_SITE: site, + DD_TAGS: `${RUN_ID_TAG_KEY}:${runId}`, + DD_TRACE_ENABLED: "true", + // With the extension, log collection is enabled via DD_SERVERLESS_LOGS_ENABLED; + // the construct intentionally forces DD_LOGS_INJECTION=false in this path. + DD_SERVERLESS_LOGS_ENABLED: "true", + DD_LOGS_INJECTION: "false", + DD_LAMBDA_HANDLER: "index.handler", + }), + }, +}); diff --git a/e2e/helpers/lambda-telemetry-checker.ts b/e2e/helpers/lambda-telemetry-checker.ts index 0954909e..cf6c11ff 100644 --- a/e2e/helpers/lambda-telemetry-checker.ts +++ b/e2e/helpers/lambda-telemetry-checker.ts @@ -90,6 +90,9 @@ const buildConfiguration = (): client.Configuration => { apiKeyAuth: process.env.DATADOG_API_KEY ?? process.env.DD_API_KEY, appKeyAuth: process.env.DATADOG_APP_KEY ?? process.env.DD_APP_KEY, }, + // node-fetch can fail while decoding compressed search responses. Requesting + // identity encoding keeps polling reliable without changing request payloads. + httpConfig: {compress: false}, }); const site = process.env.DATADOG_SITE ?? process.env.DD_SITE; if (site) { diff --git a/e2e/lambda.test.ts b/e2e/lambda.test.ts new file mode 100644 index 00000000..b93ad774 --- /dev/null +++ b/e2e/lambda.test.ts @@ -0,0 +1,227 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +import { readdir, readFile, rm } from "node:fs/promises"; +import path from "node:path"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { ENV_NAME, ENV_VERSION, NAMING, RETRY_PATTERNS, expectedLayerArns } from "./helpers/e2e.config"; +import { execPromise, execPromiseWithRetries, type ExecResult } from "./helpers/exec"; +import { checkTelemetryFlowing } from "./helpers/lambda-telemetry-checker"; +import { freshnessTimestamp, namePrefix, newRunId } from "./helpers/naming"; +import { verifyCdkClean, verifyCdkInstrumented } from "./verifier"; + +const DEPLOY_TIMEOUT_MS = 900_000; +const LIFECYCLE_TIMEOUT_MS = 1_800_000; +const HEARTBEAT_INTERVAL_MS = 30_000; + +const elapsed = (started: number): string => `${Math.round((Date.now() - started) / 1000)}s`; + +const runPhase = async (name: string, action: () => Promise): Promise => { + const started = Date.now(); + console.log(`START: ${name}`); + const heartbeat = setInterval(() => { + console.log(`RUNNING: ${name} (${elapsed(started)} elapsed)`); + }, HEARTBEAT_INTERVAL_MS); + + try { + return await action(); + } finally { + clearInterval(heartbeat); + console.log(`DONE: ${name} (${elapsed(started)})`); + } +}; + +const requireEnv = (name: string): void => { + if (!process.env[name]) { + throw new Error(`Missing required environment variable ${name}`); + } +}; + +const requireAnyEnv = (names: string[]): void => { + if (!names.some((name) => process.env[name])) { + throw new Error(`Missing required environment variable: one of ${names.join(", ")}`); + } +}; + +const assertSuccess = (result: ExecResult, message: string): void => { + expect(result.exitCode, `${message}: ${result.stderr || result.stdout}`).toBe(0); +}; + +interface TemplateResource { + Type: string; + Properties?: { Layers?: string[] }; +} + +interface CloudFormationTemplate { + Resources: Record; +} + +describe("cdk lambda e2e", () => { + const region = process.env.AWS_REGION ?? "ap-northeast-3"; + const runId = newRunId(); + const serviceName = namePrefix(NAMING, runId); + const createdTs = freshnessTimestamp(); + const env = ENV_NAME; + const version = ENV_VERSION; + const site = process.env.DD_SITE ?? "datadoghq.com"; + const buildDir = "e2e/.build"; + const appBundle = `${buildDir}/app.cjs`; + + let account: string; + let canDestroy = false; + let removed = false; + + const baseEnv = (instrument: boolean): Record => ({ + E2E_SERVICE_NAME: serviceName, + E2E_RUN_ID: runId, + E2E_CREATED_TS: createdTs, + E2E_INSTRUMENT: instrument ? "true" : "false", + E2E_ENV: env, + E2E_VERSION: version, + DD_SITE: site, + CDK_DEFAULT_ACCOUNT: account, + CDK_DEFAULT_REGION: region, + AWS_REGION: region, + }); + + const assemblyDir = (instrument: boolean): string => `${buildDir}/cdk-${instrument ? "instrumented" : "baseline"}`; + + const synthesize = async (instrument: boolean): Promise => { + const output = assemblyDir(instrument); + await rm(output, { recursive: true, force: true }); + const result = await execPromise( + `npx cdk --app "node ${appBundle}" --output "${output}" synth "${serviceName}" --quiet`, + { env: baseEnv(instrument) }, + ); + assertSuccess(result, "Failed to synthesize workload"); + + if (instrument) { + const templates = (await readdir(output)).filter((file) => file.endsWith(".template.json")); + expect(templates, "Expected one synthesized stack template").toHaveLength(1); + const template = JSON.parse(await readFile(path.join(output, templates[0]), "utf8")) as CloudFormationTemplate; + const functions = Object.values(template.Resources).filter( + (resource) => resource.Type === "AWS::Lambda::Function", + ); + expect(functions, "Expected one synthesized Lambda function").toHaveLength(1); + + const layers = functions[0].Properties?.Layers ?? []; + for (const expected of Object.values(expectedLayerArns(region))) { + expect( + layers.filter((layer) => layer === expected), + `Expected pinned layer ${expected}; got ${layers}`, + ).toHaveLength(1); + } + } + }; + + const deploy = (instrument: boolean) => + execPromiseWithRetries( + `npx cdk --app "${assemblyDir(instrument)}" deploy "${serviceName}" --require-approval never`, + { + env: baseEnv(instrument), + retryPatterns: RETRY_PATTERNS, + }, + ); + + const destroy = () => + execPromiseWithRetries(`npx cdk --app "${assemblyDir(false)}" destroy "${serviceName}" --force`, { + env: baseEnv(false), + retryPatterns: RETRY_PATTERNS, + }); + + beforeAll(async () => { + await runPhase("validating credentials", async () => { + requireEnv("DD_API_KEY"); + requireAnyEnv(["DATADOG_APP_KEY", "DD_APP_KEY"]); + + const identity = await execPromise("aws sts get-caller-identity --query Account --output text"); + assertSuccess(identity, "AWS credential validation failed"); + account = identity.stdout; + + const configuredAccount = process.env.CDK_DEFAULT_ACCOUNT; + if (configuredAccount && configuredAccount !== account) { + throw new Error(`CDK_DEFAULT_ACCOUNT is ${configuredAccount}, but AWS credentials belong to ${account}`); + } + }); + + await runPhase("bundling the CDK app", async () => { + const bundle = await execPromise( + `npx esbuild e2e/app/app.ts --bundle --platform=node --target=node22 --packages=external --outfile=${appBundle}`, + ); + assertSuccess(bundle, "Failed to bundle CDK app"); + }); + + await runPhase("synthesizing the baseline function", async () => { + await synthesize(false); + canDestroy = true; + }); + + await runPhase("deploying the baseline function", async () => { + assertSuccess(await deploy(false), "Failed to provision workload"); + }); + }, DEPLOY_TIMEOUT_MS); + + afterAll(async () => { + try { + if (!canDestroy || removed) { + return; + } + + const result = await runPhase("cleaning up the function", destroy); + if (result.exitCode !== 0) { + console.error(`Failed to destroy workload stack: ${result.stderr || result.stdout}`); + } + } finally { + await rm(buildDir, { recursive: true, force: true }); + } + }, DEPLOY_TIMEOUT_MS); + + it( + "runs the instrumentation lifecycle", + async () => { + await runPhase("synthesizing the instrumented function", () => synthesize(true)); + + await runPhase("instrumenting the function", async () => { + assertSuccess(await deploy(true), "Failed to instrument workload"); + }); + + await runPhase("verifying the deployed configuration", () => + verifyCdkInstrumented(serviceName, region, site, runId, createdTs), + ); + + await runPhase("invoking the function", async () => { + const invoke = await execPromiseWithRetries( + `aws lambda invoke --function-name "${serviceName}" --region "${region}" --payload '{}' --cli-binary-format raw-in-base64-out /dev/null`, + { retryPatterns: RETRY_PATTERNS }, + ); + assertSuccess(invoke, "Failed to invoke workload"); + }); + + await runPhase("waiting for Datadog telemetry", () => + checkTelemetryFlowing({ serviceName, env, version, runId }), + ); + + await runPhase("checking CDK idempotence", async () => { + await synthesize(true); + const diff = await execPromise(`npx cdk --app "${assemblyDir(true)}" diff "${serviceName}" --fail`, { + env: baseEnv(true), + }); + assertSuccess(diff, "Expected no diff on re-apply"); + }); + + await runPhase("removing the function", async () => { + const result = await destroy(); + assertSuccess(result, "Failed to remove workload"); + removed = true; + }); + + await runPhase("verifying cleanup", () => verifyCdkClean(serviceName, region, site, runId)); + }, + LIFECYCLE_TIMEOUT_MS, + ); +}); diff --git a/e2e/tsconfig.json b/e2e/tsconfig.json new file mode 100644 index 00000000..209aa31d --- /dev/null +++ b/e2e/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "noEmit": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ES2022", + "types": ["node", "vitest/globals"] + }, + "include": ["**/*.ts"] +} diff --git a/e2e/verifier.ts b/e2e/verifier.ts new file mode 100644 index 00000000..309a4896 --- /dev/null +++ b/e2e/verifier.ts @@ -0,0 +1,75 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2026 Datadog, Inc. + */ + +import assert from "node:assert/strict"; + +import { E2E_RUNTIME } from "./app/versions"; +import { functionName, verifierConfig } from "./helpers/e2e.config"; +import { execPromise } from "./helpers/exec"; +import { verifyInstrumented, verifyUninstrumented } from "./helpers/lambda-verifier"; +import { FRESHNESS_TAG_KEY, RUN_ID_TAG_KEY } from "./helpers/naming"; + +interface LambdaConfiguration { + FunctionArn: string; + Runtime: string; +} + +interface TagsResponse { + Tags?: Record; +} + +interface LogGroupsResponse { + logGroups?: Array<{ logGroupName?: string }>; +} + +const awsJson = async (command: string): Promise => { + const result = await execPromise(command); + assert.equal(result.exitCode, 0, result.stderr || result.stdout); + + return JSON.parse(result.stdout) as T; +}; + +export const verifyCdkInstrumented = async ( + serviceName: string, + region: string, + site: string, + runId: string, + createdTs: string, +): Promise => { + await verifyInstrumented(verifierConfig(site, runId), serviceName, region); + + const name = functionName(serviceName); + const lambda = await awsJson( + `aws lambda get-function-configuration --function-name "${name}" --region "${region}" --output json`, + ); + assert.equal(lambda.Runtime, E2E_RUNTIME.name, `runtime = ${lambda.Runtime}, want ${E2E_RUNTIME.name}`); + + const { Tags: tags = {} } = await awsJson( + `aws lambda list-tags --resource "${lambda.FunctionArn}" --region "${region}" --output json`, + ); + assert.equal(tags[FRESHNESS_TAG_KEY], createdTs, `${FRESHNESS_TAG_KEY} tag has the wrong timestamp`); + assert.equal(tags[RUN_ID_TAG_KEY], runId, `${RUN_ID_TAG_KEY} tag has the wrong run id`); +}; + +export const verifyCdkClean = async ( + serviceName: string, + region: string, + site: string, + runId: string, +): Promise => { + await verifyUninstrumented(verifierConfig(site, runId), serviceName, region); + + const logGroupName = `/aws/lambda/${functionName(serviceName)}`; + const { logGroups = [] } = await awsJson( + `aws logs describe-log-groups --log-group-name-prefix "${logGroupName}" --region "${region}" --output json`, + ); + assert.ok( + !logGroups.some((group) => group.logGroupName === logGroupName), + `log group ${logGroupName} still exists after remove`, + ); +}; diff --git a/e2e/vitest.config.ts b/e2e/vitest.config.ts new file mode 100644 index 00000000..3d680974 --- /dev/null +++ b/e2e/vitest.config.ts @@ -0,0 +1,23 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["**/*.test.ts"], + // The lifecycle is one ordered chain (apply -> trigger -> re-apply -> remove) + // sharing a single deployed function, so it must run serially. + fileParallelism: false, + sequence: { concurrent: false }, + hookTimeout: 900_000, + testTimeout: 900_000, + // Real cloud deploys are slow; never let a hung step wedge CI past its budget. + teardownTimeout: 900_000, + }, +}); diff --git a/package.json b/package.json index 021c1ccf..194138af 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "post-upgrade": "projen post-upgrade", "pre-compile": "projen pre-compile", "test": "projen test", + "test:e2e": "projen test:e2e", "test:watch": "projen test:watch", "upgrade": "projen upgrade", "watch": "projen watch", @@ -35,6 +36,7 @@ }, "devDependencies": { "@aws-cdk/aws-lambda-python-alpha": "^2.134.0-alpha.0", + "@datadog/datadog-api-client": "^1.34.1", "@stylistic/eslint-plugin": "^2", "@types/jest": "^30.0.0", "@types/node": "^22", @@ -59,7 +61,8 @@ "standard-version": "^9.5.0", "ts-jest": "^29.4.12", "ts-node": "^10.9.2", - "typescript": "^6.0.3" + "typescript": "^6.0.3", + "vitest": "^3.2.4" }, "peerDependencies": { "aws-cdk-lib": "^2.261.0", diff --git a/yarn.lock b/yarn.lock index ecaa83d1..87608309 100644 --- a/yarn.lock +++ b/yarn.lock @@ -455,6 +455,22 @@ __metadata: languageName: node linkType: hard +"@datadog/datadog-api-client@npm:^1.34.1": + version: 1.60.0 + resolution: "@datadog/datadog-api-client@npm:1.60.0" + dependencies: + "@types/buffer-from": "npm:^1.1.0" + "@types/node": "npm:*" + "@types/pako": "npm:^1.0.3" + buffer-from: "npm:^1.1.2" + cross-fetch: "npm:^3.1.5" + form-data: "npm:^4.0.4" + loglevel: "npm:^1.8.1" + pako: "npm:^2.0.4" + checksum: 10c0/2ae830284d688706a433169543150641a84ae2b5408e17b8a3d49bb8f431ca15fcd41c629523ab1260ef4b4e4426c9307d234aebb795030eb105d40c28b9b49c + languageName: node + linkType: hard + "@emnapi/core@npm:^1.4.3": version: 1.10.0 resolution: "@emnapi/core@npm:1.10.0" @@ -1197,7 +1213,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0, @jridgewell/sourcemap-codec@npm:^1.5.5": version: 1.5.5 resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 @@ -1241,6 +1257,13 @@ __metadata: languageName: node linkType: hard +"@napi-rs/lzma-linux-x64-gnu@npm:1.5.1": + version: 1.5.1 + resolution: "@napi-rs/lzma-linux-x64-gnu@npm:1.5.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@napi-rs/wasm-runtime@npm:^0.2.11": version: 0.2.12 resolution: "@napi-rs/wasm-runtime@npm:0.2.12" @@ -1366,6 +1389,181 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-android-arm-eabi@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.62.4" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-android-arm64@npm:4.62.4" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-darwin-arm64@npm:4.62.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-darwin-x64@npm:4.62.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.62.4" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-x64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-freebsd-x64@npm:4.62.4" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.62.4" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.62.4" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.62.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.62.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.62.4" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-loong64-musl@npm:4.62.4" + conditions: os=linux & cpu=loong64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.62.4" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.62.4" + conditions: os=linux & cpu=ppc64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.62.4" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.62.4" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.62.4" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.62.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.62.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-openbsd-x64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-openbsd-x64@npm:4.62.4" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-openharmony-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.62.4" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.62.4" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.62.4" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.62.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.62.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@rtsao/scc@npm:^1.1.0": version: 1.1.0 resolution: "@rtsao/scc@npm:1.1.0" @@ -1491,6 +1689,39 @@ __metadata: languageName: node linkType: hard +"@types/buffer-from@npm:^1.1.0": + version: 1.1.3 + resolution: "@types/buffer-from@npm:1.1.3" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/c8e0e3a9e24085a3af83b8c10ce1630aa3e21d6800263d4bdcb0b734afa75addc02a2ccb1d404f83ccff4619e5100219d3aaae8d558df6709c97e6c458c99e05 + languageName: node + linkType: hard + +"@types/chai@npm:^5.2.2": + version: 5.2.3 + resolution: "@types/chai@npm:5.2.3" + dependencies: + "@types/deep-eql": "npm:*" + assertion-error: "npm:^2.0.1" + checksum: 10c0/e0ef1de3b6f8045a5e473e867c8565788c444271409d155588504840ad1a53611011f85072188c2833941189400228c1745d78323dac13fcede9c2b28bacfb2f + languageName: node + linkType: hard + +"@types/deep-eql@npm:*": + version: 4.0.2 + resolution: "@types/deep-eql@npm:4.0.2" + checksum: 10c0/bf3f811843117900d7084b9d0c852da9a044d12eb40e6de73b552598a6843c21291a8a381b0532644574beecd5e3491c5ff3a0365ab86b15d59862c025384844 + languageName: node + linkType: hard + +"@types/estree@npm:1.0.9, @types/estree@npm:^1.0.0": + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 + languageName: node + linkType: hard + "@types/estree@npm:^1.0.6": version: 1.0.8 resolution: "@types/estree@npm:1.0.8" @@ -1579,6 +1810,13 @@ __metadata: languageName: node linkType: hard +"@types/pako@npm:^1.0.3": + version: 1.0.7 + resolution: "@types/pako@npm:1.0.7" + checksum: 10c0/1ba133db0b30a974c3d651c85651fd30135f629727b4b4d7ef2649c8f8b01014d5ef41f75399d939e320a50bfa87c32beccbb513badfeaf85d74ea6d5370fdcc + languageName: node + linkType: hard + "@types/stack-utils@npm:^2.0.3": version: 2.0.3 resolution: "@types/stack-utils@npm:2.0.3" @@ -1962,6 +2200,89 @@ __metadata: languageName: node linkType: hard +"@vitest/expect@npm:3.2.7": + version: 3.2.7 + resolution: "@vitest/expect@npm:3.2.7" + dependencies: + "@types/chai": "npm:^5.2.2" + "@vitest/spy": "npm:3.2.7" + "@vitest/utils": "npm:3.2.7" + chai: "npm:^5.2.0" + tinyrainbow: "npm:^2.0.0" + checksum: 10c0/5a13fee261d1020d47a3517f4d9a2cb209d7475399c815f6ebe22be116ddb0c6c401592f07d24f9a8b1c192155d11f651397ee28061f886ea61f1f9181a8fd48 + languageName: node + linkType: hard + +"@vitest/mocker@npm:3.2.7": + version: 3.2.7 + resolution: "@vitest/mocker@npm:3.2.7" + dependencies: + "@vitest/spy": "npm:3.2.7" + estree-walker: "npm:^3.0.3" + magic-string: "npm:^0.30.17" + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + checksum: 10c0/e8d9a155723e77b3e14c5a1eba35d8966b94420ebc733ffd7119b7bede22006580c468eec2aec6612fb77852cbcdfa94c6f49218f3ca1427aa9363d545c624fd + languageName: node + linkType: hard + +"@vitest/pretty-format@npm:3.2.7, @vitest/pretty-format@npm:^3.2.7": + version: 3.2.7 + resolution: "@vitest/pretty-format@npm:3.2.7" + dependencies: + tinyrainbow: "npm:^2.0.0" + checksum: 10c0/f556dd5f9e5240c7ab054d795622292c1b23f6aad3332d1e250f33d801783efbb7883387640b76d22cc91b81f30cb735b40371ec3e4f5293e735495f45d624df + languageName: node + linkType: hard + +"@vitest/runner@npm:3.2.7": + version: 3.2.7 + resolution: "@vitest/runner@npm:3.2.7" + dependencies: + "@vitest/utils": "npm:3.2.7" + pathe: "npm:^2.0.3" + strip-literal: "npm:^3.0.0" + checksum: 10c0/d73ba6df95175ea2b545d37fde3e743d113ecd608693b444af1d4dc27956abe4d5b500e25e09ffe46ce720de6b7cec68c264fca20366fc6da0d9ce75c52047cc + languageName: node + linkType: hard + +"@vitest/snapshot@npm:3.2.7": + version: 3.2.7 + resolution: "@vitest/snapshot@npm:3.2.7" + dependencies: + "@vitest/pretty-format": "npm:3.2.7" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + checksum: 10c0/c58a17a2c98788e77d30d39837c024852eca91618efe9b53ec399cf76332365b8cc592a69617e0f7d696df716dcc341dac61c6cbea86ae98cdb49a4a84f48d19 + languageName: node + linkType: hard + +"@vitest/spy@npm:3.2.7": + version: 3.2.7 + resolution: "@vitest/spy@npm:3.2.7" + dependencies: + tinyspy: "npm:^4.0.3" + checksum: 10c0/cf2728b4ddc6137e0ca749215c7714845e8221a5f799e933bc623216a9958fd8b032cdd7f033ed8375df9e6ed84a18b64687ca2530f50e8a76bc3b1d16d88c42 + languageName: node + linkType: hard + +"@vitest/utils@npm:3.2.7": + version: 3.2.7 + resolution: "@vitest/utils@npm:3.2.7" + dependencies: + "@vitest/pretty-format": "npm:3.2.7" + loupe: "npm:^3.1.4" + tinyrainbow: "npm:^2.0.0" + checksum: 10c0/fea57d6cf66853926f54ea6e9bd249b707120b0abba565d96a3880c7f04d5c5cd4778546879b9074cc73c0b81b475c1873791d4b3b3e5a324115b5bcfd3a46bb + languageName: node + linkType: hard + "@xmldom/xmldom@npm:^0.9.10": version: 0.9.10 resolution: "@xmldom/xmldom@npm:0.9.10" @@ -2230,6 +2551,13 @@ __metadata: languageName: node linkType: hard +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8 + languageName: node + linkType: hard + "async-function@npm:^1.0.0": version: 1.0.0 resolution: "async-function@npm:1.0.0" @@ -2237,6 +2565,13 @@ __metadata: languageName: node linkType: hard +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d + languageName: node + linkType: hard + "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" @@ -2448,13 +2783,20 @@ __metadata: languageName: node linkType: hard -"buffer-from@npm:^1.0.0": +"buffer-from@npm:^1.0.0, buffer-from@npm:^1.1.2": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" checksum: 10c0/124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 languageName: node linkType: hard +"cac@npm:^6.7.14": + version: 6.7.14 + resolution: "cac@npm:6.7.14" + checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10 + languageName: node + linkType: hard + "cacache@npm:^20.0.1": version: 20.0.4 resolution: "cacache@npm:20.0.4" @@ -2551,6 +2893,19 @@ __metadata: languageName: node linkType: hard +"chai@npm:^5.2.0": + version: 5.3.3 + resolution: "chai@npm:5.3.3" + dependencies: + assertion-error: "npm:^2.0.1" + check-error: "npm:^2.1.1" + deep-eql: "npm:^5.0.1" + loupe: "npm:^3.1.0" + pathval: "npm:^2.0.0" + checksum: 10c0/b360fd4d38861622e5010c2f709736988b05c7f31042305fa3f4e9911f6adb80ccfb4e302068bf8ed10e835c2e2520cba0f5edc13d878b886987e5aa62483f53 + languageName: node + linkType: hard + "chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" @@ -2579,6 +2934,13 @@ __metadata: languageName: node linkType: hard +"check-error@npm:^2.1.1": + version: 2.1.3 + resolution: "check-error@npm:2.1.3" + checksum: 10c0/878e99038fb6476316b74668cd6a498c7e66df3efe48158fa40db80a06ba4258742ac3ee2229c4a2a98c5e73f5dff84eb3e50ceb6b65bbd8f831eafc8338607d + languageName: node + linkType: hard + "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -2686,6 +3048,15 @@ __metadata: languageName: node linkType: hard +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: "npm:~1.0.0" + checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 + languageName: node + linkType: hard + "comment-json@npm:4.2.2": version: 4.2.2 resolution: "comment-json@npm:4.2.2" @@ -2979,6 +3350,15 @@ __metadata: languageName: node linkType: hard +"cross-fetch@npm:^3.1.5": + version: 3.2.0 + resolution: "cross-fetch@npm:3.2.0" + dependencies: + node-fetch: "npm:^2.7.0" + checksum: 10c0/d8596adf0269130098a676f6739a0922f3cc7b71cc89729925411ebe851a87026171c82ea89154c4811c9867c01c44793205a52e618ce2684650218c7fbeeb9f + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" @@ -3035,6 +3415,7 @@ __metadata: resolution: "datadog-cdk-constructs-v2@workspace:." dependencies: "@aws-cdk/aws-lambda-python-alpha": "npm:^2.134.0-alpha.0" + "@datadog/datadog-api-client": "npm:^1.34.1" "@stylistic/eslint-plugin": "npm:^2" "@types/jest": "npm:^30.0.0" "@types/node": "npm:^22" @@ -3061,6 +3442,7 @@ __metadata: ts-jest: "npm:^29.4.12" ts-node: "npm:^10.9.2" typescript: "npm:^6.0.3" + vitest: "npm:^3.2.4" peerDependencies: aws-cdk-lib: ^2.261.0 constructs: ^10.5.1 @@ -3147,6 +3529,13 @@ __metadata: languageName: node linkType: hard +"deep-eql@npm:^5.0.1": + version: 5.0.2 + resolution: "deep-eql@npm:5.0.2" + checksum: 10c0/7102cf3b7bb719c6b9c0db2e19bf0aa9318d141581befe8c7ce8ccd39af9eaa4346e5e05adef7f9bd7015da0f13a3a25dcfe306ef79dc8668aedbecb658dd247 + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -3183,6 +3572,13 @@ __metadata: languageName: node linkType: hard +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 + languageName: node + linkType: hard + "detect-indent@npm:^5.0.0": version: 5.0.0 resolution: "detect-indent@npm:5.0.0" @@ -3391,6 +3787,13 @@ __metadata: languageName: node linkType: hard +"es-module-lexer@npm:^1.7.0": + version: 1.7.0 + resolution: "es-module-lexer@npm:1.7.0" + checksum: 10c0/4c935affcbfeba7fb4533e1da10fa8568043df1e3574b869385980de9e2d475ddc36769891936dbb07036edb3c3786a8b78ccf44964cd130dedc1f2c984b6c7b + languageName: node + linkType: hard + "es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": version: 1.1.1 resolution: "es-object-atoms@npm:1.1.1" @@ -3432,7 +3835,7 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.28.1": +"esbuild@npm:^0.27.0 || ^0.28.0, esbuild@npm:^0.28.1": version: 0.28.1 resolution: "esbuild@npm:0.28.1" dependencies: @@ -3797,6 +4200,15 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -3828,6 +4240,13 @@ __metadata: languageName: node linkType: hard +"expect-type@npm:^1.2.1": + version: 1.4.0 + resolution: "expect-type@npm:1.4.0" + checksum: 10c0/d40d76b8570695d36587beb3cc28494da2ca3ec8f04e67f5622ed2d372d850e401a9adef19c6835e1a8173903f157c79540b34c7b3fbd7cd8ce726cc903c57b7 + languageName: node + linkType: hard + "expect@npm:30.4.1": version: 30.4.1 resolution: "expect@npm:30.4.1" @@ -4042,6 +4461,19 @@ __metadata: languageName: node linkType: hard +"form-data@npm:^4.0.4": + version: 4.0.6 + resolution: "form-data@npm:4.0.6" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + es-set-tostringtag: "npm:^2.1.0" + hasown: "npm:^2.0.4" + mime-types: "npm:^2.1.35" + checksum: 10c0/43947a77bf0ff45c6ceed789778982d47a3f3e720a74b71721174ebf3310a5f1a8be1d6b38a3ee3688e8a18a2c4273073ec0844cd37efda3eaf46d41c9c318ff + languageName: node + linkType: hard + "fs-extra@npm:^10.1.0": version: 10.1.0 resolution: "fs-extra@npm:10.1.0" @@ -4091,7 +4523,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^2.3.3": +"fsevents@npm:^2.3.3, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -4101,7 +4533,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^2.3.3#optional!builtin": +"fsevents@patch:fsevents@npm%3A^2.3.3#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" dependencies: @@ -4485,6 +4917,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.4": + version: 2.0.4 + resolution: "hasown@npm:2.0.4" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506 + languageName: node + linkType: hard + "hosted-git-info@npm:^2.1.4": version: 2.8.9 resolution: "hosted-git-info@npm:2.8.9" @@ -5566,6 +6007,13 @@ __metadata: languageName: node linkType: hard +"js-tokens@npm:^9.0.1": + version: 9.0.1 + resolution: "js-tokens@npm:9.0.1" + checksum: 10c0/68dcab8f233dde211a6b5fd98079783cbcd04b53617c1250e3553ee16ab3e6134f5e65478e41d82f6d351a052a63d71024553933808570f04dbf828d7921e80e + languageName: node + linkType: hard + "js-yaml@npm:^3.13.1": version: 3.14.2 resolution: "js-yaml@npm:3.14.2" @@ -5971,13 +6419,20 @@ __metadata: languageName: node linkType: hard -"loglevel@npm:^1.9.2": +"loglevel@npm:^1.8.1, loglevel@npm:^1.9.2": version: 1.9.2 resolution: "loglevel@npm:1.9.2" checksum: 10c0/1e317fa4648fe0b4a4cffef6de037340592cee8547b07d4ce97a487abe9153e704b98451100c799b032c72bb89c9366d71c9fb8192ada8703269263ae77acdc7 languageName: node linkType: hard +"loupe@npm:^3.1.0, loupe@npm:^3.1.4": + version: 3.2.1 + resolution: "loupe@npm:3.2.1" + checksum: 10c0/910c872cba291309664c2d094368d31a68907b6f5913e989d301b5c25f30e97d76d77f23ab3bf3b46d0f601ff0b6af8810c10c31b91d2c6b2f132809ca2cc705 + languageName: node + linkType: hard + "lru-cache@npm:^10.2.0": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -6010,6 +6465,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.30.17": + version: 0.30.21 + resolution: "magic-string@npm:0.30.21" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.5" + checksum: 10c0/299378e38f9a270069fc62358522ddfb44e94244baa0d6a8980ab2a9b2490a1d03b236b447eee309e17eb3bddfa482c61259d47960eb018a904f0ded52780c4a + languageName: node + linkType: hard + "make-dir@npm:^4.0.0": version: 4.0.0 resolution: "make-dir@npm:4.0.0" @@ -6318,6 +6782,15 @@ __metadata: languageName: node linkType: hard +"nanoid@npm:^3.3.16": + version: 3.3.17 + resolution: "nanoid@npm:3.3.17" + bin: + nanoid: bin/nanoid.cjs + checksum: 10c0/06f7949c7cce5c92c6aea66022f29a1eae7f56e05acbfddf1e049e819b4bf234c44a765cc44da7163482b111677948514012e27acdfa56f95309295768bdae32 + languageName: node + linkType: hard + "napi-postinstall@npm:^0.3.0": version: 0.3.4 resolution: "napi-postinstall@npm:0.3.4" @@ -6348,6 +6821,20 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:^2.7.0": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" + dependencies: + whatwg-url: "npm:^5.0.0" + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: 10c0/b55786b6028208e6fbe594ccccc213cab67a72899c9234eb59dba51062a299ea853210fcf526998eaa2867b0963ad72338824450905679ff0fa304b8c5093ae8 + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 12.2.0 resolution: "node-gyp@npm:12.2.0" @@ -6637,6 +7124,13 @@ __metadata: languageName: node linkType: hard +"pako@npm:^2.0.4": + version: 2.2.0 + resolution: "pako@npm:2.2.0" + checksum: 10c0/e5d31de1940fdd13cc4014296b0026112483d0834bce4856ca29c8af8438d030c6416986a0f6df7d5372cae18d6dd6c57f48b24a49d6c207c0a4cc66af15c07d + languageName: node + linkType: hard + "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -6743,6 +7237,20 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^2.0.3": + version: 2.0.3 + resolution: "pathe@npm:2.0.3" + checksum: 10c0/c118dc5a8b5c4166011b2b70608762e260085180bb9e33e80a50dcdb1e78c010b1624f4280c492c92b05fc276715a4c357d1f9edc570f8f1b3d90b6839ebaca1 + languageName: node + linkType: hard + +"pathval@npm:^2.0.0": + version: 2.0.1 + resolution: "pathval@npm:2.0.1" + checksum: 10c0/460f4709479fbf2c45903a65655fc8f0a5f6d808f989173aeef5fdea4ff4f303dc13f7870303999add60ec49d4c14733895c0a869392e9866f1091fa64fd7581 + languageName: node + linkType: hard + "picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" @@ -6808,6 +7316,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:^8.5.6": + version: 8.5.25 + resolution: "postcss@npm:8.5.25" + dependencies: + nanoid: "npm:^3.3.16" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10c0/0a12c1e74b456c57122e81f684e02fd98ff4d57526f794d10c996df1147158808f5ae373ac82b988c8de6cbbaa82dbd7b13803b14f5dd3cf7cc6a42ccad5c9f2 + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -7140,6 +7659,99 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^4.43.0": + version: 4.62.4 + resolution: "rollup@npm:4.62.4" + dependencies: + "@napi-rs/lzma-linux-x64-gnu": "npm:1.5.1" + "@rollup/rollup-android-arm-eabi": "npm:4.62.4" + "@rollup/rollup-android-arm64": "npm:4.62.4" + "@rollup/rollup-darwin-arm64": "npm:4.62.4" + "@rollup/rollup-darwin-x64": "npm:4.62.4" + "@rollup/rollup-freebsd-arm64": "npm:4.62.4" + "@rollup/rollup-freebsd-x64": "npm:4.62.4" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.62.4" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.62.4" + "@rollup/rollup-linux-arm64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-arm64-musl": "npm:4.62.4" + "@rollup/rollup-linux-loong64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-loong64-musl": "npm:4.62.4" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-ppc64-musl": "npm:4.62.4" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-riscv64-musl": "npm:4.62.4" + "@rollup/rollup-linux-s390x-gnu": "npm:4.62.4" + "@rollup/rollup-linux-x64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-x64-musl": "npm:4.62.4" + "@rollup/rollup-openbsd-x64": "npm:4.62.4" + "@rollup/rollup-openharmony-arm64": "npm:4.62.4" + "@rollup/rollup-win32-arm64-msvc": "npm:4.62.4" + "@rollup/rollup-win32-ia32-msvc": "npm:4.62.4" + "@rollup/rollup-win32-x64-gnu": "npm:4.62.4" + "@rollup/rollup-win32-x64-msvc": "npm:4.62.4" + "@types/estree": "npm:1.0.9" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@napi-rs/lzma-linux-x64-gnu": + optional: true + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-freebsd-arm64": + optional: true + "@rollup/rollup-freebsd-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-loong64-gnu": + optional: true + "@rollup/rollup-linux-loong64-musl": + optional: true + "@rollup/rollup-linux-ppc64-gnu": + optional: true + "@rollup/rollup-linux-ppc64-musl": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-openbsd-x64": + optional: true + "@rollup/rollup-openharmony-arm64": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-gnu": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10c0/d83bcc89f02db337963dcd0b0d16620129cee263f8437464c02d782dde4e1bb89a6b5b511cd230317ce2c5959fb858884305a9a1a33d1d3da4eef9fe6368414b + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -7350,6 +7962,13 @@ __metadata: languageName: node linkType: hard +"siginfo@npm:^2.0.0": + version: 2.0.0 + resolution: "siginfo@npm:2.0.0" + checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34 + languageName: node + linkType: hard + "signal-exit@npm:^3.0.3": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" @@ -7412,6 +8031,13 @@ __metadata: languageName: node linkType: hard +"source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf + languageName: node + linkType: hard + "source-map-support@npm:0.5.13": version: 0.5.13 resolution: "source-map-support@npm:0.5.13" @@ -7527,6 +8153,13 @@ __metadata: languageName: node linkType: hard +"stackback@npm:0.0.2": + version: 0.0.2 + resolution: "stackback@npm:0.0.2" + checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983 + languageName: node + linkType: hard + "standard-version@npm:^9.5.0": version: 9.5.0 resolution: "standard-version@npm:9.5.0" @@ -7551,6 +8184,13 @@ __metadata: languageName: node linkType: hard +"std-env@npm:^3.9.0": + version: 3.10.0 + resolution: "std-env@npm:3.10.0" + checksum: 10c0/1814927a45004d36dde6707eaf17552a546769bc79a6421be2c16ce77d238158dfe5de30910b78ec30d95135cc1c59ea73ee22d2ca170f8b9753f84da34c427f + languageName: node + linkType: hard + "stop-iteration-iterator@npm:^1.1.0": version: 1.1.0 resolution: "stop-iteration-iterator@npm:1.1.0" @@ -7738,6 +8378,15 @@ __metadata: languageName: node linkType: hard +"strip-literal@npm:^3.0.0": + version: 3.1.0 + resolution: "strip-literal@npm:3.1.0" + dependencies: + js-tokens: "npm:^9.0.1" + checksum: 10c0/50918f669915d9ad0fe4b7599902b735f853f2201c97791ead00104a654259c0c61bc2bc8fa3db05109339b61f4cf09e47b94ecc874ffbd0e013965223893af8 + languageName: node + linkType: hard + "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -7847,6 +8496,20 @@ __metadata: languageName: node linkType: hard +"tinybench@npm:^2.9.0": + version: 2.9.0 + resolution: "tinybench@npm:2.9.0" + checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c + languageName: node + linkType: hard + +"tinyexec@npm:^0.3.2": + version: 0.3.2 + resolution: "tinyexec@npm:0.3.2" + checksum: 10c0/3efbf791a911be0bf0821eab37a3445c2ba07acc1522b1fa84ae1e55f10425076f1290f680286345ed919549ad67527d07281f1c19d584df3b74326909eb1f90 + languageName: node + linkType: hard + "tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.15": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15" @@ -7867,6 +8530,27 @@ __metadata: languageName: node linkType: hard +"tinypool@npm:^1.1.1": + version: 1.1.1 + resolution: "tinypool@npm:1.1.1" + checksum: 10c0/bf26727d01443061b04fa863f571016950888ea994ba0cd8cba3a1c51e2458d84574341ab8dbc3664f1c3ab20885c8cf9ff1cc4b18201f04c2cde7d317fff69b + languageName: node + linkType: hard + +"tinyrainbow@npm:^2.0.0": + version: 2.0.0 + resolution: "tinyrainbow@npm:2.0.0" + checksum: 10c0/c83c52bef4e0ae7fb8ec6a722f70b5b6fa8d8be1c85792e829f56c0e1be94ab70b293c032dc5048d4d37cfe678f1f5babb04bdc65fd123098800148ca989184f + languageName: node + linkType: hard + +"tinyspy@npm:^4.0.3": + version: 4.0.4 + resolution: "tinyspy@npm:4.0.4" + checksum: 10c0/a8020fc17799251e06a8398dcc352601d2770aa91c556b9531ecd7a12581161fd1c14e81cbdaff0c1306c93bfdde8ff6d1c1a3f9bbe6d91604f0fd4e01e2f1eb + languageName: node + linkType: hard + "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5" @@ -7883,6 +8567,13 @@ __metadata: languageName: node linkType: hard +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 10c0/047cb209a6b60c742f05c9d3ace8fa510bff609995c129a37ace03476a9b12db4dbf975e74600830ef0796e18882b2381fb5fb1f6b4f96b832c374de3ab91a11 + languageName: node + linkType: hard + "trim-newlines@npm:^3.0.0": version: 3.0.1 resolution: "trim-newlines@npm:3.0.1" @@ -8337,6 +9028,132 @@ __metadata: languageName: node linkType: hard +"vite-node@npm:3.2.4": + version: 3.2.4 + resolution: "vite-node@npm:3.2.4" + dependencies: + cac: "npm:^6.7.14" + debug: "npm:^4.4.1" + es-module-lexer: "npm:^1.7.0" + pathe: "npm:^2.0.3" + vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0" + bin: + vite-node: vite-node.mjs + checksum: 10c0/6ceca67c002f8ef6397d58b9539f80f2b5d79e103a18367288b3f00a8ab55affa3d711d86d9112fce5a7fa658a212a087a005a045eb8f4758947dd99af2a6c6b + languageName: node + linkType: hard + +"vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0": + version: 7.3.6 + resolution: "vite@npm:7.3.6" + dependencies: + esbuild: "npm:^0.27.0 || ^0.28.0" + fdir: "npm:^6.5.0" + fsevents: "npm:~2.3.3" + picomatch: "npm:^4.0.3" + postcss: "npm:^8.5.6" + rollup: "npm:^4.43.0" + tinyglobby: "npm:^0.2.15" + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + jiti: ">=1.21.0" + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + bin: + vite: bin/vite.js + checksum: 10c0/c6d359f84ad362f5c97ff7988b77c90add04162c60cdf6059375a7d9e3217848c53a8cb6b6c48517bef84b6bba4c9bc85319a889b5236acb7d5a2bc8cb7b9a8d + languageName: node + linkType: hard + +"vitest@npm:^3.2.4": + version: 3.2.7 + resolution: "vitest@npm:3.2.7" + dependencies: + "@types/chai": "npm:^5.2.2" + "@vitest/expect": "npm:3.2.7" + "@vitest/mocker": "npm:3.2.7" + "@vitest/pretty-format": "npm:^3.2.7" + "@vitest/runner": "npm:3.2.7" + "@vitest/snapshot": "npm:3.2.7" + "@vitest/spy": "npm:3.2.7" + "@vitest/utils": "npm:3.2.7" + chai: "npm:^5.2.0" + debug: "npm:^4.4.1" + expect-type: "npm:^1.2.1" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + picomatch: "npm:^4.0.2" + std-env: "npm:^3.9.0" + tinybench: "npm:^2.9.0" + tinyexec: "npm:^0.3.2" + tinyglobby: "npm:^0.2.14" + tinypool: "npm:^1.1.1" + tinyrainbow: "npm:^2.0.0" + vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0" + vite-node: "npm:3.2.4" + why-is-node-running: "npm:^2.3.0" + peerDependencies: + "@edge-runtime/vm": "*" + "@types/debug": ^4.1.12 + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + "@vitest/browser": 3.2.7 + "@vitest/ui": 3.2.7 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/debug": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: ./vitest.mjs + checksum: 10c0/4eb7a63a1d62b88c425bcbc609835055a5644a1994d6f47605fe396dddf732e3c0277c9ec89a028fe81557dc4051dd15fc15b9eba6a51d1466cd5c682ddc1261 + languageName: node + linkType: hard + "walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8" @@ -8346,6 +9163,23 @@ __metadata: languageName: node linkType: hard +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db + languageName: node + linkType: hard + +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: "npm:~0.0.3" + webidl-conversions: "npm:^3.0.0" + checksum: 10c0/1588bed84d10b72d5eec1d0faa0722ba1962f1821e7539c535558fb5398d223b0c50d8acab950b8c488b4ba69043fd833cc2697056b167d8ad46fac3995a55d5 + languageName: node + linkType: hard + "which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": version: 1.1.1 resolution: "which-boxed-primitive@npm:1.1.1" @@ -8429,6 +9263,18 @@ __metadata: languageName: node linkType: hard +"why-is-node-running@npm:^2.3.0": + version: 2.3.0 + resolution: "why-is-node-running@npm:2.3.0" + dependencies: + siginfo: "npm:^2.0.0" + stackback: "npm:0.0.2" + bin: + why-is-node-running: cli.js + checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054 + languageName: node + linkType: hard + "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5"