diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index af37736..e6fdf11 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -20,8 +20,65 @@ jobs: release-please: runs-on: ubuntu-latest steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Compute release-as (align to premain RC) + id: version + run: | + set -euo pipefail + + release_as="$( + python3 - <<'PY' + import json + from pathlib import Path + + + def parse_base(v: str) -> tuple[int, int, int]: + v = v.strip() + if v.startswith("v"): + v = v[1:] + v = v.split("+", 1)[0] + base = v.split("-", 1)[0] + parts = base.split(".") + if len(parts) != 3: + raise ValueError(f"invalid semver base: {v}") + return (int(parts[0]), int(parts[1]), int(parts[2])) + + + stable = json.loads(Path(".release-please-manifest.json").read_text(encoding="utf-8")).get(".", "") + premain = json.loads(Path(".release-please-manifest.premain.json").read_text(encoding="utf-8")).get(".", "") + + if not stable or not premain: + raise SystemExit("") + + premain_base = premain.split("+", 1)[0].split("-", 1)[0] + + # If premain is already on a higher major/minor/patch line (e.g., 1.3.0-rc.1), + # force the stable Release PR to promote that baseline (e.g., 1.3.0). + if parse_base(premain_base) > parse_base(stable): + print(premain_base) + PY + )" + + echo "release_as=${release_as}" >> "${GITHUB_OUTPUT}" + echo "release-as: ${release_as:-}" + + - name: Release Please (PR only) (aligned) + if: steps.version.outputs.release_as != '' + id: release_aligned + uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4 + with: + token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }} + target-branch: main + config-file: release-please-config.json + manifest-file: .release-please-manifest.json + release-as: ${{ steps.version.outputs.release_as }} + skip-github-release: true + - name: Release Please (PR only) - id: release + if: steps.version.outputs.release_as == '' + id: release_default uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4 with: token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index d50a7cc..056e81e 100644 --- a/.gitignore +++ b/.gitignore @@ -140,3 +140,4 @@ py/coverage-*.json docs/development/notes/* !docs/development/notes/template-notes.md /notes/ +.pai diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c3f1463..41ea87d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.2.0" + ".": "1.2.1" } diff --git a/AGENTS.md b/AGENTS.md index f943518..6ad1f49 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -39,3 +39,31 @@ Single test example: `go test -v -run TestName ./pkg/query` - Branch naming commonly uses `feature/...`, `fix/...`, `chore/...`. - Prefer Conventional Commit-style subjects (`feat:`, `fix:`, `docs:`, `test:`) and keep the first line ≤72 chars. - PRs: describe intent and scope, link issues, list commands run, add/adjust tests, and update `CHANGELOG.md` + relevant docs when public APIs change (see `CONTRIBUTING.md`). + +## Release / Versioning (immutable GitHub releases) + +TableTheory publishes **immutable** GitHub releases (no retagging / no overwriting release assets). Any change that must be +published requires: + +- **staging → premain**: merge a PR from `staging` into `premain` to start the prerelease pipeline (RCs) +- **premain → main**: merge a PR from `premain` into `main` to start the stable release pipeline +- **post-release sync**: back-merge `main` into `staging` so the next cycle starts from the latest stable baseline + +Branch roles: + +- **`staging`**: integration branch (all work lands here first) +- **`premain`**: prerelease branch (RCs like `vX.Y.Z-rc.N`) +- **`main`**: stable release branch (releases like `vX.Y.Z`) + +Multi-language versioning: + +- **Stable manifest**: `.release-please-manifest.json` +- **Prerelease manifest**: `.release-please-manifest.premain.json` +- **TypeScript**: `ts/package.json`, `ts/package-lock.json` +- **Python**: `py/src/theorydb_py/version.json` + +Release automation must keep these files coherent so the stable line never lags the prerelease line on promotion. +The rubric enforces this via: + +- `bash scripts/verify-branch-release-supply-chain.sh` +- `bash scripts/verify-branch-version-sync.sh` diff --git a/AI_FRIENDLY_DOCUMENTATION_GUIDE.md b/AI_FRIENDLY_DOCUMENTATION_GUIDE.md deleted file mode 100644 index 3cf0126..0000000 --- a/AI_FRIENDLY_DOCUMENTATION_GUIDE.md +++ /dev/null @@ -1,556 +0,0 @@ -# AI-Friendly Documentation Guide - -## Purpose - -This guide teaches developers how to write documentation that serves three audiences simultaneously: -1. **Human developers** reading the docs -2. **AI assistants** learning from the docs -3. **Semantic knowledge bases** indexing the docs - -Well-structured documentation becomes training data that teaches AI to use your libraries correctly. - -## Core Principles - -### 1. Explicit Context Over Implicit Knowledge - -**❌ Bad (Assumes Context):** -```markdown -## Installation -Run `npm install lift` -``` - -**✅ Good (Provides Context):** -```markdown -## Installation - -Lift is a Go serverless framework for AWS Lambda. To install: - -```bash -# For Go projects using Lambda -go get github.com/theory-cloud/lift - -# This is the preferred method for serverless Go applications -``` -``` - -### 2. Semantic Structure Over Visual Structure - -**❌ Bad (Visual Only):** -```markdown -LIFT -==== -A framework for Lambda --------------------- -``` - -**✅ Good (Semantic):** -```markdown -# Lift: Go Serverless Framework for AWS Lambda - -## What is Lift? -Lift is the standard framework for building production-ready Lambda functions in Go. It provides automatic error handling, logging, and observability. - -## When to Use Lift -- Building AWS Lambda functions in Go -- Need production-ready error handling -- Want consistent patterns across functions -- Require built-in observability -``` - -### 3. Examples Before Explanations - -**❌ Bad (Theory First):** -```markdown -Lift uses middleware patterns to compose functionality... -``` - -**✅ Good (Example First):** -```go -// Example: Basic Lambda handler with Lift -package main - -import "github.com/theory-cloud/lift" - -func main() { - lift.Start(HandlePayment) -} - -func HandlePayment(ctx *lift.Context) error { - // Automatic error handling, logging, and tracing - payment := &Payment{} - if err := ctx.Bind(payment); err != nil { - return lift.BadRequest(err) // Automatic error response - } - - // Process payment... - return ctx.JSON(200, result) -} -``` - -## Documentation Structure Template - -### 1. README.md Template - -```markdown -# [Library Name]: [One-Line Purpose] - - -**[Library] is the [preferred/standard/recommended] way to [core purpose] in [language/framework].** - -## Why [Library]? - - -Use [Library] when you need: -- ✅ [Primary use case] -- ✅ [Secondary use case] -- ✅ [Performance benefit] -- ❌ Don't use for: [Anti-pattern] - -## Quick Start - - -```[language] -// This is the preferred pattern for [use case] -// It provides [key benefits] -[Minimal working example] -``` - -## Core Concepts - - -### [Concept 1] -[Concept] is how [Library] handles [problem]. This is important because [reason]. - -**Example:** -```[language] -// Always use [Pattern] for [use case] -// Never use [anti-pattern] because [reason] -``` - -## Installation - - -### For [Use Case 1] (Recommended) -```bash -# This method is preferred for [type of project] -[install command] -``` - -### For [Use Case 2] -```bash -# Use this method when [specific condition] -[alternate install] -``` - -## Common Patterns - - -### Pattern: [Name] -**When to use:** [Specific scenario] -**Why:** [Business/technical reason] - -```[language] -// CORRECT: [Pattern name] -[good example] - -// INCORRECT: [Anti-pattern name] -// This will cause [specific problem] -[bad example] -``` - -## API Reference - - -### `functionName(params): ReturnType` - -**Purpose:** [What it does in business terms] -**When to use:** [Specific scenarios] -**When NOT to use:** [Anti-patterns] - -```[language] -// Example: [Use case description] -result := functionName(param1, param2) -// This returns [what it means, not just type] -``` - -## Best Practices - - -1. **Always** [do this] because [reason] -2. **Never** [do that] because [consequence] -3. **Prefer** [pattern A] over [pattern B] for [reason] - -## Integration Examples - - -### With [Common Tool/Framework] -```[language] -// When using with [tool], always follow this pattern -[integration example] -``` - -## Troubleshooting - - -### Error: [Common Error Message] -**Cause:** This happens when [scenario] -**Solution:** [Specific fix] -```[language] -// Correct approach: -[solution code] -``` - -## Migration Guide - - -### From [Alternative Library] -```[language] -// Old pattern (deprecated): -[old code] - -// New pattern with [Library]: -[new code] -// Benefits: [specific improvements] -``` -``` - -### 2. Code Documentation Template - -```go -// Package lift implements the Pay Theory serverless pattern for AWS Lambda. -// -// This is the RECOMMENDED way to build Lambda functions in Go. -// It provides automatic error handling, logging, and distributed tracing. -// -// AI Usage Note: Always prefer lift.Handler over raw Lambda handlers. -// This pattern reduces boilerplate by 80% and prevents common errors. -// -// Example (Preferred Pattern): -// -// func HandlePayment(ctx *lift.Context) error { -// // Automatic request parsing, validation, and error handling -// var payment Payment -// if err := ctx.Bind(&payment); err != nil { -// return lift.BadRequest(err) -// } -// return ctx.JSON(200, result) -// } -// -// DO NOT use raw Lambda handlers like this: -// -// func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { -// // This pattern lacks error handling, logging, and observability -// } -// -package lift - -// Context provides a unified interface for Lambda function handlers. -// -// AI Training: Context is the ONLY parameter your handler needs. -// It contains request data, response methods, and service clients. -// -// Common Usage Patterns: -// - ctx.Bind(&struct) for parsing request bodies -// - ctx.JSON(code, data) for JSON responses -// - ctx.Logger for structured logging -// - ctx.Tracer for distributed tracing -type Context struct { - // ... fields -} - -// Start initializes and runs a Lambda function with the Lift pattern. -// -// AI Training: This is the REQUIRED entry point for all Lift functions. -// -// Example: -// -// func main() { -// // Always use lift.Start, never lambda.Start -// lift.Start(HandleRequest) -// } -// -// Parameters: -// - handler: Your function that processes requests -// -// The handler function MUST have this signature: -// func(ctx *lift.Context) error -// -// DO NOT use other signatures or raw Lambda handlers. -func Start(handler Handler) { - // ... implementation -} -``` - -### 3. Tutorial Documentation Template - -```markdown -# Building a Payment API with Lift - - -This tutorial shows the STANDARD way to build payment APIs using Lift and TableTheory. - -## What We're Building - -A production-ready payment processing endpoint that: -- Handles errors gracefully -- Logs all operations -- Scales automatically -- Costs only what you use - -## Prerequisites - - -- Go 1.21 or higher -- AWS account with Lambda access -- Basic understanding of HTTP APIs - -## Step 1: Project Setup - - -```bash -# This is the standard structure for Lift projects -mkdir payment-api && cd payment-api -go mod init payment-api -go get github.com/theory-cloud/lift -go get github.com/theory-cloud/tabletheory -``` - -**Project structure:** -``` -payment-api/ -├── cmd/ -│ └── payment-handler/ -│ └── main.go # Lambda entry point -├── internal/ -│ ├── models/ -│ │ └── payment.go # TableTheory models -│ └── handlers/ -│ └── payment.go # Business logic -├── go.mod -└── serverless.yml # Deployment config -``` - -## Step 2: Define the Model - - -```go -// internal/models/payment.go -package models - -import "github.com/theory-cloud/tabletheory" - -// Payment represents a payment transaction. -// AI Note: Always embed tabletheory.Model for DynamoDB entities. -type Payment struct { - tabletheory.Model - ID string `theorydb:"pk" json:"id"` - Amount int64 `theorydb:"index:amount" json:"amount"` - Status string `theorydb:"index:status" json:"status"` - Customer string `theorydb:"index:customer" json:"customer_id"` -} - -// This pattern provides: -// - Automatic CRUD operations -// - Index management -// - Query building -// - Cost optimization -``` - - -``` - -## Semantic Knowledge Base Structure - -### 1. Concept Hierarchy - -```yaml -# _concepts.yaml - Machine-readable concept map -concepts: - lift: - type: framework - purpose: AWS Lambda development in Go - provides: - - error_handling - - logging - - tracing - - request_parsing - replaces: - - raw_lambda_handlers - - custom_middleware - use_when: - - building_lambda_functions - - need_production_features - - want_consistent_patterns - dont_use_when: - - not_using_aws_lambda - - need_custom_runtime -``` - -### 2. Pattern Registry - -```yaml -# _patterns.yaml - Machine-readable patterns -patterns: - lambda_handler: - name: "Lift Handler Pattern" - problem: "Lambda functions need consistent error handling" - solution: "Use lift.Context and lift.Start" - example: | - func HandleRequest(ctx *lift.Context) error { - // Implementation - } - anti_patterns: - - name: "Raw Lambda Handler" - why: "Lacks error handling and observability" - example: | - func handler(request events.APIGatewayProxyRequest) -``` - -### 3. Decision Trees - -```yaml -# _decisions.yaml - Help AI make choices -decisions: - choosing_handler: - question: "What type of Lambda handler to use?" - answers: - - condition: "Using Go and AWS Lambda" - choice: "lift.Handler" - reason: "Standard pattern with built-in features" - - condition: "Need custom runtime" - choice: "Raw handler" - reason: "Lift requires standard Lambda runtime" -``` - -## AI Documentation Prompt Template - -Use this prompt to generate documentation for your libraries: - -```markdown -Generate comprehensive, AI-friendly documentation for [Library Name]. - -Context: -- Library Purpose: [What it does] -- Target Users: [Who uses it] -- Key Problems Solved: [Main benefits] -- Anti-patterns to Avoid: [What not to do] - -Follow these principles: -1. Examples before explanations -2. Show correct and incorrect usage -3. Explain WHY, not just HOW -4. Include semantic markers for AI training -5. Structure for both humans and machines - -Include: -- README with quick start -- API documentation with examples -- Common patterns and anti-patterns -- Integration examples -- Troubleshooting guide -- Migration guide from alternatives - -For each code example: -- Add comment explaining this is the preferred pattern -- Show what problem it solves -- Include anti-pattern comparison -- Explain consequences of wrong approach - -Make the documentation serve as ideal training data for AI assistants. -``` - -## Validation Checklist - -### Documentation Quality Metrics - -- [ ] **Searchability**: Can AI find the right pattern by describing the problem? -- [ ] **Clarity**: Does each example state if it's correct or incorrect? -- [ ] **Context**: Does every code block explain when to use it? -- [ ] **Completeness**: Are common errors and solutions documented? -- [ ] **Semantic Structure**: Can it be parsed into a knowledge graph? - -### AI Training Signals - -- [ ] "Preferred/Standard/Recommended" language used consistently -- [ ] Anti-patterns explicitly marked as incorrect -- [ ] Business purpose explained for technical features -- [ ] Common mistakes documented with solutions -- [ ] Integration patterns with popular tools shown - -## Example: Complete Mini-Documentation - -```markdown -# QuickCache: In-Memory Caching for Go - -**QuickCache is the STANDARD in-memory caching solution for Go applications that need sub-millisecond response times.** - -## When to Use QuickCache - -✅ **USE** QuickCache when: -- Need sub-millisecond cache reads -- Data fits in memory (<10GB) -- Can tolerate data loss on restart - -❌ **DON'T USE** when: -- Need persistent cache (use Redis) -- Data exceeds memory (use DynamoDB) -- Need cache sharing between instances - -## Quick Start - -```go -// This is the CORRECT way to use QuickCache -package main - -import "github.com/example/quickcache" - -func main() { - // Always initialize with size limit - cache := quickcache.New(quickcache.Options{ - MaxSize: 1000000, // 1MB limit prevents OOM - TTL: 300, // 5 minute expiry - }) - - // Set value - automatic serialization - cache.Set("user:123", userData) - - // Get value - automatic deserialization - var user User - found := cache.Get("user:123", &user) -} - -// INCORRECT - Don't do this: -cache := quickcache.New(nil) // No size limit = memory leak risk -``` - -## Best Practices - -1. **ALWAYS set size limits** - Prevents memory exhaustion -2. **ALWAYS set TTL** - Prevents stale data -3. **NEVER cache sensitive data** - It's in-memory and unencrypted -4. **PREFER specific keys** - "user:123" over "123" - -## Common Errors - -### Error: "cache: memory limit exceeded" -**Cause:** Cache size exceeds MaxSize -**Solution:** Increase MaxSize or reduce cached data -```go -// Solution: Configure appropriate limits -cache := quickcache.New(quickcache.Options{ - MaxSize: 10000000, // 10MB - OnEvict: func(key string) { - log.Printf("Evicted: %s", key) - }, -}) -``` -``` - -## Result - -Following this guide produces documentation that: -1. **Humans** can quickly understand and apply -2. **AI** learns correct patterns and avoids mistakes -3. **Knowledge bases** can parse and query semantically - -Your documentation becomes living training data that improves AI code generation for everyone using your libraries. \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ccc8403..de0be62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.2.1](https://github.com/theory-cloud/TableTheory/compare/v1.2.0...v1.2.1) (2026-01-23) + + +### Bug Fixes + +* improved transaction handling ([30a5d7a](https://github.com/theory-cloud/TableTheory/commit/30a5d7acc371cbcbd38bee1d240e5eab24d49882)) + ## [1.2.0](https://github.com/theory-cloud/TableTheory/compare/v1.1.5...v1.2.0) (2026-01-22) diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index a4d0b94..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,138 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -TableTheory is a Lambda-native, type-safe ORM for Amazon DynamoDB written in Go. It provides lightweight wrappers around DynamoDB operations while maintaining compatibility with Infrastructure as Code patterns. - -## Key Development Commands - -### Essential Commands -```bash -make build # Build the project -make test # Run unit tests -make lint # Run golangci-lint -make fmt # Format code with gofmt -make check # Check for compilation errors -``` - -### Testing Commands -```bash -make test # Run unit tests with race detector -make integration # Run integration tests (starts DynamoDB Local automatically) -make benchmark # Run performance benchmarks -make test-all # Run all tests (unit, integration, benchmarks, stress) -make coverage # Show test coverage in browser - -# Team-specific testing -make team1-test # Test core, model, types, session, errors packages -make team2-test # Test query, expr, index packages -make examples-test # Test example code - -# Run a single test -go test -v -run TestFunctionName ./path/to/package -``` - -### Docker Commands -```bash -make docker-up # Start DynamoDB Local on port 8000 -make docker-down # Stop DynamoDB Local -``` - -### Lambda Development -```bash -make lambda-build # Build Lambda function example -make lambda-test # Test Lambda functionality -make lambda-bench # Run Lambda benchmarks -``` - -## High-Level Architecture - -### Package Structure -- **`/pkg/core/`** - Core interfaces (DB, Query, UpdateBuilder) that define the contract -- **`/pkg/model/`** - Model registry and metadata management -- **`/pkg/query/`** - Query building and execution logic -- **`/pkg/session/`** - AWS session management -- **`/pkg/types/`** - Type conversion between Go and DynamoDB -- **`/pkg/marshal/`** - Optimized marshaling/unmarshaling -- **`/pkg/transaction/`** - Transaction support -- **`/pkg/mocks/`** - Pre-built mocks for testing (v1.0.1+) -- **`/internal/expr/`** - Expression building for DynamoDB queries - -### Key Design Patterns - -1. **Interface-Driven Design**: All major components are defined as interfaces in `/pkg/core/`. This enables: - - Easy mocking for tests (mocks provided in `/pkg/mocks/`) - - Clean dependency injection - - Testable code without DynamoDB - -2. **Builder Pattern**: Fluent API for query construction with chainable methods: - ```go - db.Model(&User{}).Where("ID", "=", "123").OrderBy("CreatedAt", "DESC").All(&users) - ``` - -3. **Repository Pattern**: Each model acts as its own repository through the Model() method - -4. **Lazy Evaluation**: Queries are built up and only executed on terminal operations (First, All, Create, Update, Delete) - -### Lambda Optimizations - -The codebase includes specific optimizations for Lambda in `lambda.go`: -- Connection reuse across invocations -- Memory optimization -- Cold start reduction (11ms vs 127ms for standard SDK) -- Use `tabletheory.WithLambdaOptimizations()` when initializing - -### Testing Strategy - -- **Unit Tests**: Alongside source files (`*_test.go`) -- **Integration Tests**: `/tests/integration/` (require DynamoDB Local) -- **Benchmarks**: `/tests/benchmarks/` -- **Test Models**: `/tests/models/` contains test model definitions -- **Mocking**: Use interfaces from `/pkg/core/` and mocks from `/pkg/mocks/` - -### Important Conventions - -1. **Struct Tags**: DynamoDB configuration via struct tags: - - `theorydb:"pk"` - Partition key - - `theorydb:"sk"` - Sort key - - `theorydb:"created_at"` - Custom attribute name - - `theorydb:"index:gsi1,pk"` - GSI partition key - - `theorydb:"index:gsi1,sk"` - GSI sort key - -2. **Embedded Structs**: TableTheory supports embedded structs for code reuse: - ```go - type BaseModel struct { - PK string `theorydb:"pk"` - SK string `theorydb:"sk"` - UpdatedAt time.Time `theorydb:"updated_at"` - } - - type Customer struct { - BaseModel // Embedded fields are recognized - Name string - } - ``` - -3. **Error Handling**: Custom error types in `/pkg/errors/` with retry strategies - -4. **Performance**: Focus on reducing allocations and reusing resources - -5. **Multi-Account**: Built-in support via `WithMultiAccount()` option - -## Development Workflow - -1. Before making changes, run `make test` to ensure tests pass -2. Use `make fmt` and `make lint` before committing -3. Write tests for new functionality -4. Run `make integration` for integration testing -5. Use interfaces from `/pkg/core/` for testable code -6. Follow existing patterns in similar files - -## Key Files to Understand - -- `theorydb.go` - Main DB implementation and entry point -- `/pkg/core/interfaces.go` - Core interfaces that define the API -- `/pkg/query/builder.go` - Query builder implementation -- `/pkg/model/registry.go` - Model metadata and registration \ No newline at end of file diff --git a/docs/development/planning/theorydb-branch-release-policy.md b/docs/development/planning/theorydb-branch-release-policy.md index 2ee3651..d4fd16c 100644 --- a/docs/development/planning/theorydb-branch-release-policy.md +++ b/docs/development/planning/theorydb-branch-release-policy.md @@ -4,21 +4,26 @@ This document defines the intended branch strategy and release automation for Ta ## Branches -- `premain` — prerelease integration branch (source of prereleases). +- `staging` — integration branch (all work lands here first). +- `premain` — prerelease branch (source of prereleases). - `main` — release branch (source of stable releases). ## Merge flow (expected) -- Feature/fix work lands via PRs into `premain`. -- A release is cut by merging `premain` into `main` (via PR). -- Hotfixes may merge directly into `main` (then backported to `premain`). +- Feature/fix work lands via PRs into `staging`. +- An **RC** is cut by merging `staging` into `premain` (via PR), then merging the release-please prerelease PR. +- A **release** is cut by merging `premain` into `main` (via PR), then merging the release-please stable release PR. +- Hotfixes should still follow `staging` -> `premain` -> `main` so version lines stay aligned. ## Post-release sync (required) -After a stable release is cut on `main`, immediately back-merge `main` into `premain` (via PR) so: +After a stable release is cut on `main`, immediately back-merge `main` into `staging` (via PR) so: -- `premain` carries the latest `.release-please-manifest.json` stable version, and -- prereleases do not remain on an older major/minor track. +- `staging` carries the latest `.release-please-manifest.json` stable version (and changelog/version files), and +- the next `staging` -> `premain` promotion will carry forward the correct stable baseline. + +If `premain` is used directly after a stable release (without a `staging` promotion), back-merge `main` into `premain` +as well so prereleases do not remain on an older major/minor track. If `.release-please-manifest.premain.json` is behind the latest stable version, reset it to the latest stable version to start the next prerelease cycle from the correct baseline. diff --git a/hgm-infra/evidence/hgm-rubric-report.json b/hgm-infra/evidence/hgm-rubric-report.json index 619cf47..d14c5c7 100644 --- a/hgm-infra/evidence/hgm-rubric-report.json +++ b/hgm-infra/evidence/hgm-rubric-report.json @@ -1,7 +1,7 @@ { "$schema": "https://hgm.pai.dev/schemas/hgm-rubric-report.schema.json", "schemaVersion": 1, - "timestamp": "2026-01-23T01:42:09Z", + "timestamp": "2026-01-29T18:09:53Z", "pack": { "version": "816465a1618d", "digest": "896aed16549928f21626fb4effe9bb6236fc60292a8f50bae8ce77e873ac775b" diff --git a/scripts/verify-branch-release-supply-chain.sh b/scripts/verify-branch-release-supply-chain.sh index da8cdfc..1570270 100644 --- a/scripts/verify-branch-release-supply-chain.sh +++ b/scripts/verify-branch-release-supply-chain.sh @@ -12,7 +12,9 @@ failures=0 required_files=( "docs/development/planning/theorydb-branch-release-policy.md" ".github/workflows/prerelease.yml" + ".github/workflows/prerelease-pr.yml" ".github/workflows/release.yml" + ".github/workflows/release-pr.yml" "release-please-config.premain.json" "release-please-config.json" ".release-please-manifest.premain.json" @@ -116,6 +118,67 @@ if [[ -f ".github/workflows/release.yml" ]]; then } fi +if [[ -f ".github/workflows/prerelease-pr.yml" ]]; then + grep -Eq 'branches:.*premain' ".github/workflows/prerelease-pr.yml" || { + echo "branch-release: prerelease-pr workflow must target premain" + failures=$((failures + 1)) + } + grep -Eq 'googleapis/release-please-action@[0-9a-fA-F]{40}.*\bv4\b' ".github/workflows/prerelease-pr.yml" || { + echo "branch-release: prerelease-pr workflow must pin release-please v4 by commit SHA" + failures=$((failures + 1)) + } + grep -Eq 'config-file:\s*release-please-config\.premain\.json' ".github/workflows/prerelease-pr.yml" || { + echo "branch-release: prerelease-pr workflow must reference release-please-config.premain.json" + failures=$((failures + 1)) + } + grep -Eq 'manifest-file:\s*\.release-please-manifest\.premain\.json' ".github/workflows/prerelease-pr.yml" || { + echo "branch-release: prerelease-pr workflow must reference .release-please-manifest.premain.json" + failures=$((failures + 1)) + } + grep -Eq 'skip-github-release:\s*true' ".github/workflows/prerelease-pr.yml" || { + echo "branch-release: prerelease-pr workflow must set skip-github-release: true" + failures=$((failures + 1)) + } +fi + +if [[ -f ".github/workflows/release-pr.yml" ]]; then + grep -Eq 'branches:.*main' ".github/workflows/release-pr.yml" || { + echo "branch-release: release-pr workflow must target main" + failures=$((failures + 1)) + } + grep -Eq 'googleapis/release-please-action@[0-9a-fA-F]{40}.*\bv4\b' ".github/workflows/release-pr.yml" || { + echo "branch-release: release-pr workflow must pin release-please v4 by commit SHA" + failures=$((failures + 1)) + } + grep -Eq 'config-file:\s*release-please-config\.json' ".github/workflows/release-pr.yml" || { + echo "branch-release: release-pr workflow must reference release-please-config.json" + failures=$((failures + 1)) + } + grep -Eq 'manifest-file:\s*\.release-please-manifest\.json' ".github/workflows/release-pr.yml" || { + echo "branch-release: release-pr workflow must reference .release-please-manifest.json" + failures=$((failures + 1)) + } + grep -Eq 'skip-github-release:\s*true' ".github/workflows/release-pr.yml" || { + echo "branch-release: release-pr workflow must set skip-github-release: true" + failures=$((failures + 1)) + } + + # Ensure stable releases promote the RC baseline on premain (e.g., 1.3.0-rc.1 -> 1.3.0), + # so the stable line never lags behind the prerelease line. + grep -Fq "release-as:" ".github/workflows/release-pr.yml" || { + echo "branch-release: release-pr workflow must set release-as to promote the premain RC baseline" + failures=$((failures + 1)) + } + grep -Fq "steps.version.outputs.release_as" ".github/workflows/release-pr.yml" || { + echo "branch-release: release-pr workflow must pass release-as from computed premain RC baseline" + failures=$((failures + 1)) + } + grep -Fq ".release-please-manifest.premain.json" ".github/workflows/release-pr.yml" || { + echo "branch-release: release-pr workflow must read .release-please-manifest.premain.json to align versions" + failures=$((failures + 1)) + } +fi + for wf in ".github/workflows/quality-gates.yml" ".github/workflows/codeql.yml"; do if [[ ! -f "${wf}" ]]; then continue diff --git a/ts/.eslintrc.cjs b/ts/.eslintrc.cjs deleted file mode 100644 index bf78a87..0000000 --- a/ts/.eslintrc.cjs +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - root: true, - env: { - node: true, - es2022: true, - }, - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - }, - plugins: ['@typescript-eslint'], - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], - ignorePatterns: ['dist', 'node_modules'], -}; diff --git a/ts/eslint.config.js b/ts/eslint.config.js new file mode 100644 index 0000000..2e8b25e --- /dev/null +++ b/ts/eslint.config.js @@ -0,0 +1,34 @@ +import js from '@eslint/js'; +import globals from 'globals'; +import tseslint from '@typescript-eslint/eslint-plugin'; +import tsParser from '@typescript-eslint/parser'; + +/** @type {import("eslint").Linter.FlatConfig[]} */ +export default [ + { + ignores: ['dist/**', 'node_modules/**'], + }, + js.configs.recommended, + { + files: ['**/*.ts'], + languageOptions: { + parser: tsParser, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + globals: { + ...globals.es2022, + ...globals.node, + }, + }, + plugins: { + '@typescript-eslint': tseslint, + }, + rules: { + ...tseslint.configs.recommended.rules, + // TypeScript handles undefined checks for types/namespaces (e.g., `NodeJS`). + 'no-undef': 'off', + }, + }, +]; diff --git a/ts/package-lock.json b/ts/package-lock.json index 90abd97..288a5c1 100644 --- a/ts/package-lock.json +++ b/ts/package-lock.json @@ -15,10 +15,12 @@ "yaml": "^2.8.0" }, "devDependencies": { + "@eslint/js": "^9.39.2", "@types/node": "^24.10.9", "@typescript-eslint/eslint-plugin": "^8.26.0", "@typescript-eslint/parser": "^8.26.0", - "eslint": "^8.57.1", + "eslint": "^9.39.2", + "globals": "^17.2.0", "prettier": "^3.6.0", "tsx": "^4.21.0", "typescript": "^5.9.3" @@ -1678,25 +1680,90 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1713,6 +1780,19 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1737,53 +1817,64 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "brace-expansion": "^1.1.7" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": "*" + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -1800,50 +1891,18 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "node": ">=18.18" }, - "engines": { - "node": ">= 8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@smithy/abort-controller": { @@ -2440,6 +2499,20 @@ "node": ">=18.0.0" } }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "24.10.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", @@ -2684,13 +2757,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2732,16 +2798,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2882,19 +2938,6 @@ "dev": true, "license": "MIT" }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/esbuild": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", @@ -2951,67 +2994,70 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -3019,7 +3065,7 @@ "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3049,6 +3095,19 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3073,18 +3132,31 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3175,16 +3247,6 @@ "fxparser": "src/cli/cli.js" } }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -3204,16 +3266,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/find-up": { @@ -3234,18 +3296,17 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -3255,13 +3316,6 @@ "dev": true, "license": "ISC" }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3290,28 +3344,6 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3325,53 +3357,19 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.2.0.tgz", + "integrity": "sha512-tovnCz/fEq+Ripoq+p/gN1u7l6A7wwkoBT9pRCzTHzsD/LvADIzXZdjmRymh5Ztf0DYC3Rwg5cZRYjxzBmzbWg==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3419,25 +3417,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3461,16 +3440,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3604,16 +3573,6 @@ "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==", "license": "MIT" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -3687,16 +3646,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -3757,27 +3706,6 @@ "node": ">=6" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3798,58 +3726,6 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/semver": { "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", @@ -3886,19 +3762,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3937,13 +3800,6 @@ "node": ">=8" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -4013,19 +3869,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -4084,13 +3927,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/yaml": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", diff --git a/ts/package.json b/ts/package.json index 0e0650e..4057eeb 100644 --- a/ts/package.json +++ b/ts/package.json @@ -38,10 +38,12 @@ "yaml": "^2.8.0" }, "devDependencies": { + "@eslint/js": "^9.39.2", "@types/node": "^24.10.9", "@typescript-eslint/eslint-plugin": "^8.26.0", "@typescript-eslint/parser": "^8.26.0", - "eslint": "^8.57.1", + "eslint": "^9.39.2", + "globals": "^17.2.0", "prettier": "^3.6.0", "tsx": "^4.21.0", "typescript": "^5.9.3"