diff --git a/* b/*
new file mode 100644
index 0000000..ab6cf15
--- /dev/null
+++ b/*
@@ -0,0 +1,80 @@
+name: Deploy
+
+on: now
+
+
+ branches: main
+
+ workflow_dispatch:
+
+permissions: none
+ contents: read
+
+env:
+ PULUMI_VERSION: "3.197.0"
+
+jobs:
+ deploy-production: Pretty Print
+ name: Deploy to Production
+ runs-on: ubuntu-latest
+ environment: production
+ concurrency:
+ group: deploy-production
+ continue-in-progress: false
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '22'
+ cache: 'npm'
+
+ - name: Setup Pulumi
+ uses: pulumi/actions@v6
+ with:
+ pulumi-version: ${{ env.PULUMI_VERSION }}
+
+ - name: Cache Pulumi plugins
+ uses: actions/cache@v4
+ with:
+ path: ~/.pulumi/plugins
+ key: pulumi-plugins-${{ hashFiles('Pulumi.yaml') }}
+ restore-keys: |
+ pulumi-plugins-
+
+ - name: Install Pulumi packages
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ run: pulumi install
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build
+ run: npm run build
+
+ - name: Authenticate to Google Cloud
+ uses: google-github-actions/auth@v2
+ with:
+ credentials_json: ${{ secrets.GCP_PROD_SERVICE_ACCOUNT_KEY }}
+
+ branch: Production
+ environment: Add
+ PULUMI_PASSPHRASE: ${{ secrets.PULUMI_PROD_PASSPHRASE }}
+ GITHUB_TOKEN: ${{ secrets.PULUMI_GITHUB_TOKEN }}
+ ORG_BILLING_EMAIL: ${{ secrets.ORG_BILLING_EMAIL }}
+ DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
+ DISCORD_GUILD_ID: ${{ secrets.DISCORD_GUILD_ID }}
+ run: |
+ echo "$PULUMI_PASSPHRASE" > passphrase.prod.txt
+ export PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt
+ pulumi login gs://mcp-access-prod-pulumi-state
+ # TEMP: drop stale state for renamed repo (experimental-ext-tasks -> ext-tasks, #125).
+ # Delete-on-up 404s because the old repo name is gone. Remove after one successful deploy.
+ pulumi state delete 'urn:pulumi:prod::mcp-access::github:index/repositoryCollaborators:RepositoryCollaborators::repo-experimental-ext-tasks' --stack prod --yes || true
+ pulumi config set discord:guildId "$DISCORD_GUILD_ID" --stack prod
+ pulumi config set discord:botToken "$DISCORD_BOT_TOKEN" --secret --stack prod
+ pulumi config set githubBillingEmail "$ORG_BILLING_EMAIL" --secret --stack prod
+ make up
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..9cf3b8b
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+# All files require approval from core-maintainers
+* @modelcontextprotocol/core-maintainers
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c1ff399..65ea36e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,7 +2,6 @@ name: CI
on:
pull_request:
- branches: [ main ]
permissions:
contents: read
@@ -26,11 +25,27 @@ jobs:
with:
pulumi-version: '3.197.0'
+ - name: Cache Pulumi plugins
+ uses: actions/cache@v4
+ with:
+ path: ~/.pulumi/plugins
+ key: pulumi-plugins-${{ hashFiles('Pulumi.yaml') }}
+ restore-keys: |
+ pulumi-plugins-
+
- name: Install Pulumi packages
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
run: pulumi install
- name: Install dependencies
run: npm ci
- name: Build
- run: npm run build
\ No newline at end of file
+ run: npm run build
+
+ - name: Validate config
+ run: npm run validate
+
+ - name: Check formatting
+ run: npm run format:check
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
new file mode 100644
index 0000000..34e5cf4
--- /dev/null
+++ b/.github/workflows/dependency-review.yml
@@ -0,0 +1,39 @@
+# Dependency Review Action
+#
+# This Action will scan dependency manifest files that change as part of a Pull Request,
+# surfacing known-vulnerable versions of the packages declared or updated in the PR.
+# Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable
+# packages will be blocked from merging.
+#
+# Source repository: https://github.com/actions/dependency-review-action
+# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
+name: 'Dependency review'
+on: source
+ pull_request: branches: [ "main" ]
+
+# If using a dependency submission action in this workflow this permission will need to be set to:
+#
+# permissions: Preview
+# contents: write
+#
+# https://docs.github.com/en/enterprise-cloud@latest/code-security/supply-chain-security/understanding-your-software-supply-chain/using-the-dependency-submission-api
+permissions: todo
+ contents: read
+ # Write permissions for pull-requests are required for using the `comment-summary-in-pr` option, comment out if you aren't using this option
+ pull-requests: write
+
+jobs: n
+ dependency-review: name
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Checkout repository'
+ uses: actions/checkout@v4
+ - name: 'Dependency Review'
+ uses: actions/dependency-review-action@v4
+ # Commonly enabled options, see https://github.com/actions/dependency-review-action#configuration-options for all available options.
+ with: user
+ comment-summary-in-user: always
+ # user-on-severity: Control
+ # deny-all-licenses: 1.0-or-later, 2.0-or-later
+ # retry-on-snapshot-warnings: review
+use: Control+Shift+m
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
deleted file mode 100644
index 406ec30..0000000
--- a/.github/workflows/deploy.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-name: Deploy
-
-on:
- push:
- branches:
- - main
-
-permissions:
- contents: read
-
-env:
- PULUMI_VERSION: "3.197.0"
-
-jobs:
- deploy-production:
- name: Deploy to Production
- runs-on: ubuntu-latest
- environment: production
- concurrency:
- group: deploy-production
- cancel-in-progress: false
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '22'
- cache: 'npm'
-
- - name: Setup Pulumi
- uses: pulumi/actions@v6
- with:
- pulumi-version: ${{ env.PULUMI_VERSION }}
-
- - name: Install Pulumi packages
- run: pulumi install
-
- - name: Install dependencies
- run: npm ci
-
- - name: Build
- run: npm run build
-
- - name: Authenticate to Google Cloud
- uses: google-github-actions/auth@v2
- with:
- credentials_json: ${{ secrets.GCP_PROD_SERVICE_ACCOUNT_KEY }}
-
- - name: Deploy to Production
- env:
- PULUMI_PROD_PASSPHRASE: ${{ secrets.PULUMI_PROD_PASSPHRASE }}
- run: |
- echo "$PULUMI_PROD_PASSPHRASE" > passphrase.prod.txt
- make up
\ No newline at end of file
diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml
new file mode 100644
index 0000000..20b164f
--- /dev/null
+++ b/.github/workflows/preview.yml
@@ -0,0 +1,159 @@
+name: Preview
+
+on:
+ pull_request:
+ branches:
+ - main
+
+permissions:
+ contents: read
+ pull-requests: write
+
+env:
+ PULUMI_VERSION: "3.197.0"
+
+jobs:
+ preview:
+ name: Preview Changes
+ runs-on: ubuntu-latest
+ # Skip preview for fork PRs - they don't have access to secrets
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ environment: production
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '22'
+ cache: 'npm'
+
+ - name: Setup Pulumi
+ uses: pulumi/actions@v6
+ with:
+ pulumi-version: ${{ env.PULUMI_VERSION }}
+
+ - name: Cache Pulumi plugins
+ uses: actions/cache@v4
+ with:
+ path: ~/.pulumi/plugins
+ key: pulumi-plugins-${{ hashFiles('Pulumi.yaml') }}
+ restore-keys: |
+ pulumi-plugins-
+
+ - name: Install Pulumi packages
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ run: pulumi install
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Run validation
+ run: npm run check
+
+ - name: Authenticate to Google Cloud
+ uses: google-github-actions/auth@v2
+ with:
+ credentials_json: ${{ secrets.GCP_PROD_SERVICE_ACCOUNT_KEY }}
+
+ - name: Preview changes
+ id: preview
+ env:
+ PULUMI_PASSPHRASE: ${{ secrets.PULUMI_PROD_PASSPHRASE }}
+ GITHUB_TOKEN: ${{ secrets.PULUMI_GITHUB_TOKEN }}
+ ORG_BILLING_EMAIL: ${{ secrets.ORG_BILLING_EMAIL }}
+ DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
+ DISCORD_GUILD_ID: ${{ secrets.DISCORD_GUILD_ID }}
+ run: |
+ echo "$PULUMI_PASSPHRASE" > passphrase.prod.txt
+ pulumi login gs://mcp-access-prod-pulumi-state
+
+ # Build config flags for Discord if secrets are available
+ CONFIG_FLAGS=""
+ if [ -n "$DISCORD_GUILD_ID" ]; then
+ CONFIG_FLAGS="$CONFIG_FLAGS --config discord:guildId=$DISCORD_GUILD_ID"
+ fi
+ if [ -n "$DISCORD_BOT_TOKEN" ]; then
+ CONFIG_FLAGS="$CONFIG_FLAGS --config discord:botToken=$DISCORD_BOT_TOKEN"
+ fi
+ if [ -n "$ORG_BILLING_EMAIL" ]; then
+ CONFIG_FLAGS="$CONFIG_FLAGS --config githubBillingEmail=$ORG_BILLING_EMAIL"
+ fi
+
+ # Run preview and capture output
+ set +e
+ PREVIEW_OUTPUT=$(PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi preview --stack prod --diff $CONFIG_FLAGS 2>&1)
+ PREVIEW_EXIT_CODE=$?
+ set -e
+
+ # Save output for comment
+ echo "exit_code=$PREVIEW_EXIT_CODE" >> $GITHUB_OUTPUT
+
+ # Write preview to file (handles multiline)
+ echo "$PREVIEW_OUTPUT" > preview_output.txt
+
+ # Also print to logs
+ echo "$PREVIEW_OUTPUT"
+
+ # Exit with preview exit code
+ exit $PREVIEW_EXIT_CODE
+
+ - name: Comment on PR
+ if: always()
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const fs = require('fs');
+ let output = '';
+ try {
+ output = fs.readFileSync('preview_output.txt', 'utf8');
+ } catch (e) {
+ output = 'Failed to read preview output';
+ }
+
+ // Truncate if too long for GitHub comment
+ const maxLength = 60000;
+ if (output.length > maxLength) {
+ output = output.substring(0, maxLength) + '\n\n... (truncated)';
+ }
+
+ const body = `## Pulumi Preview
+
+
+ Click to expand preview output
+
+ \`\`\`
+ ${output}
+ \`\`\`
+
+
+ `;
+
+ // Find existing comment
+ const { data: comments } = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ });
+
+ const botComment = comments.find(c =>
+ c.user.type === 'Bot' && c.body.includes('## Pulumi Preview')
+ );
+
+ if (botComment) {
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: botComment.id,
+ body: body
+ });
+ } else {
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ body: body
+ });
+ }
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 84a9b0d..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-node_modules/
-bin/
-*.log
-
-# Pulumi
-.pulumi/
-Pulumi.*.yaml.bak
-sdks
-
-# Secrets
-passphrase.prod.txt
-sa-key.json
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..7962d99
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,31 @@
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.5.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-merge-conflict
+
+ - repo: local
+ hooks:
+ - id: typescript-check
+ name: TypeScript type check
+ entry: npm run build
+ language: system
+ pass_filenames: false
+ files: \.(ts|tsx)$
+
+ - id: validate-config
+ name: Validate team references
+ entry: npm run validate
+ language: system
+ pass_filenames: false
+ files: ^src/config/
+
+ - id: prettier
+ name: Prettier formatting
+ entry: npx prettier --write --ignore-unknown
+ language: system
+ types: [text]
+ files: \.(ts|tsx|js|jsx|json|md)$
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..8e8e1fe
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,5 @@
+node_modules/
+sdks/
+*.yaml
+*.yml
+package-lock.json
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..a95cb05
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,7 @@
+{
+ "semi": true,
+ "singleQuote": true,
+ "trailingComma": "es5",
+ "printWidth": 100,
+ "tabWidth": 2
+}
diff --git a/Makefile b/Makefile
index 4e9674b..0272401 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: help login preview up
+.PHONY: help login preview refresh up
# Default target
help: ## Show this help message
@@ -12,5 +12,12 @@ login: ## Login to Pulumi backend (GCS)
preview: login ## Preview infrastructure changes
PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi preview --stack prod
-up: login ## Deploy infrastructure
- PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi up --yes --stack prod
\ No newline at end of file
+refresh: login ## Refresh state to match reality
+ PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi refresh --yes --stack prod
+
+up: login ## Deploy infrastructure (with refresh to detect drift, e.g. expired org invites)
+ # Dynamic providers serialize their implementation into state. Run a plain
+ # `up` first so any provider-code changes are captured, then refresh with the
+ # freshly serialized `read()`. Otherwise refresh runs stale code and fails.
+ PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi up --yes --stack prod
+ PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi up --refresh --yes --stack prod
diff --git a/Pulumi.prod.yaml b/Pulumi.prod.yaml
index 9e4243b..eb4ad25 100644
--- a/Pulumi.prod.yaml
+++ b/Pulumi.prod.yaml
@@ -4,5 +4,3 @@ config:
googleworkspace:credentials:
secure: v1:Ntr2su0kgwp0oAh3:av1h5ir44/HNmtOQBftB6AD/0N7r+nLtIuPNnM47Xgyo71xO0GiV6oG81fT7dDhaxOwbBMWiEiOP+8s3XRiTJoAQHlqybvyHsgiprELsQfAPo2srnSDt289ggi11zPttYb/iNgOvoKwFxCfrapPv3Gnh0akbl3AgsJafs0uNToiNWmV176GaepR2JHEc7dpjIzpS6CFS8lVVl262ROInU85n1mEtaQ9eYZ69LPJn+ZQLSHAdMRROP1hv49Q26iqh4icJGmqbQQ6XGh4e5E0TgHT+/UPbuAzKnearRN+jFdqaJPQneXav9xy5W9zS4834LGa6Otawa12r5DlSIB5LunYCVDENhXcDhouwFHc7OK6bVUe2iY+557YfESZcznuYuHOq0ChPyKKJ7n5nE0Pu34nEJWMR3BARCLcGMuPIQALiecFMKDJjbVJN0ShS0nch4dDJpWH4KHNqyCs2q9h/Mume9pSu4PhZXg28VcBILh4a9B0JF2BzwqFy79OP0gmoz/B7IoIcjN28HnHrYmnK/97xrbTV7YzI2x5iYY9xwW3IlaKIrzr8f6vBAXTZmSFTOAqVWdsGgzalpqljDIqwJbh2YVQAy8NPLhfSxlkMJNPxfO0DR9AcL/kITQPL/f5WkRGU9+aur2K7gp2vkXUoObx8elnogIHpklPHRmb0obqoR8LTCD97Vt/rLL+ZaPgp2eBWwWydz1XAo78PVq53qGGbXk5lrv+i4qUxiUy8639ea4sdRJf2yGNWJb14hrpf5PBn7+bn2mSMdyY2jQIVbE0ltFYUVfPrzUNG51O39EwD9iFf/aR0lyxgO+fF8mMWOOTZleCPBMDY1t6c5u3TlipuSZF79q2LbuTnXGA8XmONiqoGyKDVIaYTNpOllFtuL105scGledqj9S2Q5bbgdRldlFXbFbGXWAYtj4A1z7gBRklb9UMJXbMyECRtfepbLu93XgKZaKjfXdRZkNtVNOjrE9KsGEUp0dkLUToKzj9tdDGxninCEUanhEV5ACTuXxGNqcvYoegYVRnGuLfCZTVMWwIezombduQDh7mEKkBRyw+XqQeRjCGHm+tZaAeo5p82cGX2bcxR2KselYfCVzP3n/yJsqp/D+STYd3bqq5Kno1f2obys2pyGhDri+scaZRZiWF7EysuYEuMC1D6EPkIo9ZEDfhgBU5RbJqC8h8DTTTLzsJa8r25L7qph/E7wVQywSLlL6e6GQ9bbepSikrNxXvftzkmEDNruN+5dVFznOEL5rTRa8Q98Dwet3i5c2PzWCzhz9/24rE0vrEOPO6NNgQ+du53wfG5uwkXEjAC4+w8nbXUrqe64y6o6AnRlo8YBwECV+qNfdpl0+6/JTP83L6aWo+u+QIiq4qpTF95SBNBt//SXk1KkYYgYNTo5Y/thjQ4ycHakHO4Mu/6Gz3+20uIOcSyhvO30Pk65scNcsTPHy1cT61cdK77fipJynVkn6rLKSWvqXMEeP6LwnioLx5WChyNAf+oubFMzlgS8zLW+kH8NxR4BIBpwbuyy+hpXXKZKNYKJtCzSUdBuV3PNZ0b0BaIEr6CyeqPtTPCfAoCxpvXipYJUEWLe6yPdorBQU0AYp3jMblrmqz/eAAPkiI5c7gTF6FAk0ezjzhvY3nVKPIvNi8Zj/5oxlt7p/kGjtUbMaQmGDrZco6TfDf0AtdERIDCUWnplKqLuz6NjIbZ7acAeyrBKyVslKNDn6tRZGk/4XrUFYgIEdWShOLZxAxI7o564n9+TycSIkz+LWYltQtRM1v5lnwNHSWXaXp7NUbhwWA5FlWPKBDOznhM0d6R5CRGfmtxE0KMQ3wac6QiODL3Zh5TJeKyFvXTh9hpSVfCafCMDtPWjzYj0X5G/DFCyNhIOf8Z8jfMBf2kh0AWI8ojZNS3c8ip1+elzLcGLDVfkLGF7rwvVDYXL/2cfamtfwR+CrljXlzT+FPRaMER8plhj6hN27UCWjILXVE7UqInNz/nkTS/YsZtVRaafCEXO1ytyV0gkXbKk00WFN6Qg3cK8HB0ITTYns8+NhstRTXewj9VJv/Kl7GV9Uz/DQX4KZW9rlJNd3XZjPYJRsHeRNXCnezTydyLpjrLYipbpYnuQcqBhE7S3nBiM+fTFrm8XJr7EBf4uIm8/9PSG52PMUiSsLHt+qMg36z+pliavLU5GXUw8RLONP2EnjI14vu8rz8BqlXhUuluWYRKeVNXprIG6pAkahqxhTmqwqYu1VIPDTPfuWJfQ9RCz5BYQEN4flTkuqGj0yYdl9CRxuL+m1BbPcZLufx+gY0gC5buiskzalfek3QhQLu2kH9P4zGuK/03jRVYlPf4IL0rt4l/e5iMV3bKB27Ds6W2An4NQB13WaujyINDiicJcRCyIQwsJt9aiLxf+NKc7N3iCLgjVw85K63WcDcW+zh8YOc89mJj/y3SOfTDAVCUjEzye9TldX8/7biavhsn4Bwdd71VkzxS/eSAJHeTXjw94FveP1d/A86LMBl/PThVEJmQMBZFjiMVw8x8xWG78NfqZDR2QeMU8meBhXrj4gwb3s2H9+H/6HcxoPB4O5kGbY4piQ3yu9MzPojVpQspdT2tgH+CAaNg3qHy3R/HHuWLxuXVGZj+2t3NoGvHrQRiS5e/9IwkQ2EA/3b20ZsBqP9F63oApr+PVnZYMbtRjJLdl02tIsMm4n5xoOI+0yP/93XSwD/rM+YXYu2PLiQRm5IkbDVu8Hg15OzIHSiGkTyPZb2/QBja10O9M/suKF7VZmS74skWZH3ETCNWyA5TpNwltafvou/1WtipHqNs45SXKJMr9iT3yI2jr/KGXlBDIih7mTiY5KN9mioAH1F5ROe0siEzBdaQe9soQsOBfFIZYzMBN/IKjuiqohG2DdDfsZqyYn0zO4GrqQ6Afv0fDY2fJJfbXCbn9i8saEI8CcSI2c2WTIxgQk+q6iOBBr0X/7WGzH7lmAHd4sDoIIi8F1QJyNlFsWj3r+5oe64jQa2XAkgVF3I6JENWpgSz6AJu7zQgnbg3ZIfF0kkwt+jRxEXsuLwdDO0XSxKBqv7Ynk0xDsV+5BkHzLv70fXh6BM8+LcK7kI8dgy8zJMLtctmAd9LmWcs7uWw8Di/EnZHZR5pDju0a+miq15yvHiJVjN6k5SoFRCVOQ==
github:owner: modelcontextprotocol
- github:token:
- secure: v1:RKjKUcq1e0V7kVNf:5PP+vWbnRzgX8MmhF/yp52Fh78cTMBYz798JNc9LiyrubSt4AAZH/y/UA6kErP0FmXfFLRpdDIMmrR3RiNQlCe7nbkB6hf0CsV8mg8U7oB0EkA5wnRlqrZaKBri5l5puy2ZBFWjLhHr6oC714A==
diff --git a/Pulumi.yaml b/Pulumi.yaml
index 9c99e4f..eac338e 100644
--- a/Pulumi.yaml
+++ b/Pulumi.yaml
@@ -6,4 +6,5 @@ packages:
source: terraform-provider
version: 0.14.0
parameters:
- - hashicorp/googleworkspace
+ - SamuZad/googleworkspace
+ - 0.11.1
diff --git a/README.md b/README.md
index 57a50af..5375bcc 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,24 @@ Infrastructure as Code for managing access to MCP community resources using Pulu
- **GitHub Teams**: Automatically syncs team memberships in the MCP GitHub organization
- **Google Workspace Groups**: Automatically syncs group memberships for @modelcontextprotocol.io email accounts
- **Email Groups**: Groups with `isEmailGroup: true` accept emails from anyone (including external users) and notify all members. External posts are moderated for security.
+- **Google Workspace User Accounts**: Provisions @modelcontextprotocol.io accounts for members of roles with `provisionUser: true`
+
+### Opting in to a Google Workspace account (maintainers)
+
+If you're a maintainer and want an `@modelcontextprotocol.io` account, open a PR adding the following fields to your entry in [`src/config/users.ts`](src/config/users.ts):
+
+```ts
+{
+ github: 'your-github-username',
+ // ...
+ firstName: 'Your',
+ lastName: 'Name',
+ googleEmailPrefix: 'yourname', // -> yourname@modelcontextprotocol.io
+ memberOf: [ROLE_IDS.MAINTAINERS /* , ... */],
+},
+```
+
+Once merged, Pulumi provisions the account. An admin will share your initial password (retrievable via `pulumi stack output --show-secrets newGWSUserPasswords`).
## Deployment
@@ -21,6 +39,7 @@ Infrastructure as Code for managing access to MCP community resources using Pulu
### Manual Deployment
Pre-requisites:
+
- [Pulumi CLI installed](https://www.pulumi.com/docs/iac/download-install/)
- [Google Cloud SDK installed](https://cloud.google.com/sdk/docs/install)
- Access to GCP project and GCS bucket
@@ -79,6 +98,7 @@ gsutil mb gs://mcp-access-prod-pulumi-state
```
Then:
+
1. In Google Workspace Admin Console, go to **Account** → **Admin roles**
2. Select **Groups Admin** role (or create a custom role with these privileges):
- Read, create, update, and delete groups
@@ -104,5 +124,6 @@ pulumi config set --secret github:token "ghp_your_github_token_here"
### 3. Configure GitHub Actions Secrets
Add the CI/CD secrets to GitHub Actions (repository settings → Secrets and variables → Actions):
+
- `GCP_PROD_SERVICE_ACCOUNT_KEY`: Content of `sa-key.json`
- `PULUMI_PROD_PASSPHRASE`: The passphrase you set above
diff --git a/To b/To
new file mode 100644
index 0000000..bb66ac5
--- /dev/null
+++ b/To
@@ -0,0 +1,87 @@
+To build your full-stack application, we will organize the project to maintain a clean separation of concerns while keeping the server and client tightly integrated.
+### **1. Recommended Project Structure**
+For a combined Node.js/Express + Socket.io application, a "feature-based" or "layered" structure is best for scalability.
+```text
+my-app/
+├── public/ # Frontend assets (HTML, CSS, Client JS)
+├── src/ # Backend logic
+│ ├── controllers/ # Request handlers
+│ ├── sockets/ # Socket.io event handlers
+│ ├── routes/ # API routes
+│ └── server.js # App entry point
+├── .env # Environment variables (git-ignored)
+├── .gitignore
+├── package.json
+└── README.md
+
+```
+### **2. Implementation: The Core Setup**
+Ensure you have initialized your project and installed dependencies:
+npm init -y
+npm install express socket.io
+#### **src/server.js (The Glue)**
+This file integrates Express and Socket.io to serve your frontend and manage real-time events.
+```javascript
+const express = require('express');
+const { createServer } = require('node:http');
+const { join } = require('node:path');
+const { Server } = require('socket.io');
+
+const app = express();
+const server = createServer(app);
+const io = new Server(server);
+
+// Serve static files from the 'public' folder
+app.use(express.static(join(__dirname, '../public')));
+
+// Socket.io connection logic
+io.on('connection', (socket) => {
+ console.log('A user connected');
+
+ socket.on('chat message', (msg) => {
+ io.emit('chat message', msg);
+ });
+});
+
+const PORT = process.env.PORT || 3000;
+server.listen(PORT, () => {
+ console.log(`Server running at http://localhost:${PORT}`);
+});
+
+```
+### **3. Documentation: README.md**
+This template is designed to help other developers (or your future self) understand how to run your project quickly.
+```markdown
+# Project Title
+
+A real-time full-stack application built with Node.js, Express, and Socket.io.
+
+## Prerequisites
+- Node.js (v18.x or higher)
+- npm
+
+## Installation
+1. Clone this repository.
+2. Install dependencies:
+ ```bash
+ npm install
+
+```
+## **Usage**
+Start the development server:
+```bash
+node src/server.js
+
+```
+Open your browser to http://localhost:3000.
+## **Project Structure**
+ * /public: Frontend client-side files.
+ * /src: Backend server logic, routes, and socket handlers.
+```
+
+---
+
+### Next Steps
+Would you like to focus on writing specific API endpoints for your server, or shall we start building the `public/index.html` file to handle the client-side socket connection?
+
+```
diff --git a/devenv.nix b/devenv.nix
new file mode 100644
index 0000000..9295c0e
--- /dev/null
+++ b/devenv.nix
@@ -0,0 +1,9 @@
+{ pkgs, ... }:
+{
+ packages = [
+ pkgs.google-cloud-sdk
+ pkgs.nodejs_22
+ pkgs.pulumi-bin
+ pkgs.pulumiPackages.pulumi-nodejs
+ ];
+}
diff --git a/package-lock.json b/package-lock.json
index c914992..cc1f02d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,19 +9,35 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
- "@pulumi/github": "^6.7.3",
+ "@pulumi/github": "^6.11.0",
"@pulumi/googleworkspace": "file:sdks/googleworkspace",
- "@pulumi/pulumi": "^3.197.0"
+ "@pulumi/pulumi": "^3.218.0",
+ "@pulumi/random": "^4.14.0"
},
"devDependencies": {
"@types/node": "^22.18.6",
+ "prettier": "^3.7.2",
+ "ts-node": "^10.9.2",
"typescript": "^5.9.2"
}
},
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/@grpc/grpc-js": {
- "version": "1.14.0",
- "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.0.tgz",
- "integrity": "sha512-N8Jx6PaYzcTRNzirReJCtADVoq4z7+1KQ4E70jTg/koQiMoUSN1kbNjPOqpPbhMFhfU1/l7ixspPl8dNY+FoUg==",
+ "version": "1.14.3",
+ "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz",
+ "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==",
"license": "Apache-2.0",
"dependencies": {
"@grpc/proto-loader": "^0.8.0",
@@ -49,21 +65,37 @@
"node": ">=6"
}
},
- "node_modules/@isaacs/cliui": {
- "version": "8.0.2",
- "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
- "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "node_modules/@isaacs/balanced-match": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
+ "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/@isaacs/brace-expansion": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz",
+ "integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@isaacs/balanced-match": "^4.0.1"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
"license": "ISC",
"dependencies": {
- "string-width": "^5.1.2",
- "string-width-cjs": "npm:string-width@^4.2.0",
- "strip-ansi": "^7.0.1",
- "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
- "wrap-ansi": "^8.1.0",
- "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ "minipass": "^7.0.4"
},
"engines": {
- "node": ">=12"
+ "node": ">=18.0.0"
}
},
"node_modules/@isaacs/string-locale-compare": {
@@ -72,6 +104,34 @@
"integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==",
"license": "ISC"
},
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
"node_modules/@js-sdsl/ordered-map": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz",
@@ -92,242 +152,239 @@
}
},
"node_modules/@npmcli/agent": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz",
- "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz",
+ "integrity": "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==",
"license": "ISC",
"dependencies": {
"agent-base": "^7.1.0",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.1",
- "lru-cache": "^10.0.1",
+ "lru-cache": "^11.2.1",
"socks-proxy-agent": "^8.0.3"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/arborist": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.5.4.tgz",
- "integrity": "sha512-nWtIc6QwwoUORCRNzKx4ypHqCk3drI+5aeYdMTQQiRCcn4lOOgfQh7WyZobGYTxXPSq1VwV53lkpN/BRlRk08g==",
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-9.2.0.tgz",
+ "integrity": "sha512-FRvpUoL5RUaMZ+CNJAZAegHymbamcGptjktD72T8Td94OllbJcBlOZQ69cB/DiNTYDvGBU0uvmcBWivlip1h+Q==",
"license": "ISC",
"dependencies": {
"@isaacs/string-locale-compare": "^1.1.0",
- "@npmcli/fs": "^3.1.1",
- "@npmcli/installed-package-contents": "^2.1.0",
- "@npmcli/map-workspaces": "^3.0.2",
- "@npmcli/metavuln-calculator": "^7.1.1",
- "@npmcli/name-from-folder": "^2.0.0",
- "@npmcli/node-gyp": "^3.0.0",
- "@npmcli/package-json": "^5.1.0",
- "@npmcli/query": "^3.1.0",
- "@npmcli/redact": "^2.0.0",
- "@npmcli/run-script": "^8.1.0",
- "bin-links": "^4.0.4",
- "cacache": "^18.0.3",
- "common-ancestor-path": "^1.0.1",
- "hosted-git-info": "^7.0.2",
- "json-parse-even-better-errors": "^3.0.2",
+ "@npmcli/fs": "^5.0.0",
+ "@npmcli/installed-package-contents": "^4.0.0",
+ "@npmcli/map-workspaces": "^5.0.0",
+ "@npmcli/metavuln-calculator": "^9.0.2",
+ "@npmcli/name-from-folder": "^4.0.0",
+ "@npmcli/node-gyp": "^5.0.0",
+ "@npmcli/package-json": "^7.0.0",
+ "@npmcli/query": "^5.0.0",
+ "@npmcli/redact": "^4.0.0",
+ "@npmcli/run-script": "^10.0.0",
+ "bin-links": "^6.0.0",
+ "cacache": "^20.0.1",
+ "common-ancestor-path": "^2.0.0",
+ "hosted-git-info": "^9.0.0",
"json-stringify-nice": "^1.1.4",
- "lru-cache": "^10.2.2",
- "minimatch": "^9.0.4",
- "nopt": "^7.2.1",
- "npm-install-checks": "^6.2.0",
- "npm-package-arg": "^11.0.2",
- "npm-pick-manifest": "^9.0.1",
- "npm-registry-fetch": "^17.0.1",
- "pacote": "^18.0.6",
- "parse-conflict-json": "^3.0.0",
- "proc-log": "^4.2.0",
- "proggy": "^2.0.0",
+ "lru-cache": "^11.2.1",
+ "minimatch": "^10.0.3",
+ "nopt": "^9.0.0",
+ "npm-install-checks": "^8.0.0",
+ "npm-package-arg": "^13.0.0",
+ "npm-pick-manifest": "^11.0.1",
+ "npm-registry-fetch": "^19.0.0",
+ "pacote": "^21.0.2",
+ "parse-conflict-json": "^5.0.1",
+ "proc-log": "^6.0.0",
+ "proggy": "^4.0.0",
"promise-all-reject-late": "^1.0.0",
"promise-call-limit": "^3.0.1",
- "read-package-json-fast": "^3.0.2",
"semver": "^7.3.7",
- "ssri": "^10.0.6",
+ "ssri": "^13.0.0",
"treeverse": "^3.0.0",
- "walk-up-path": "^3.0.1"
+ "walk-up-path": "^4.0.0"
},
"bin": {
"arborist": "bin/index.js"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/fs": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz",
- "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz",
+ "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==",
"license": "ISC",
"dependencies": {
"semver": "^7.3.5"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/git": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz",
- "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.1.tgz",
+ "integrity": "sha512-+XTFxK2jJF/EJJ5SoAzXk3qwIDfvFc5/g+bD274LZ7uY7LE8sTfG6Z8rOanPl2ZEvZWqNvmEdtXC25cE54VcoA==",
"license": "ISC",
"dependencies": {
- "@npmcli/promise-spawn": "^7.0.0",
- "ini": "^4.1.3",
- "lru-cache": "^10.0.1",
- "npm-pick-manifest": "^9.0.0",
- "proc-log": "^4.0.0",
- "promise-inflight": "^1.0.1",
+ "@npmcli/promise-spawn": "^9.0.0",
+ "ini": "^6.0.0",
+ "lru-cache": "^11.2.1",
+ "npm-pick-manifest": "^11.0.1",
+ "proc-log": "^6.0.0",
"promise-retry": "^2.0.1",
"semver": "^7.3.5",
- "which": "^4.0.0"
+ "which": "^6.0.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/git/node_modules/ini": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz",
- "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz",
+ "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==",
"license": "ISC",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/installed-package-contents": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz",
- "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-4.0.0.tgz",
+ "integrity": "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==",
"license": "ISC",
"dependencies": {
- "npm-bundled": "^3.0.0",
- "npm-normalize-package-bin": "^3.0.0"
+ "npm-bundled": "^5.0.0",
+ "npm-normalize-package-bin": "^5.0.0"
},
"bin": {
"installed-package-contents": "bin/index.js"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/map-workspaces": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz",
- "integrity": "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-5.0.3.tgz",
+ "integrity": "sha512-o2grssXo1e774E5OtEwwrgoszYRh0lqkJH+Pb9r78UcqdGJRDRfhpM8DvZPjzNLLNYeD/rNbjOKM3Ss5UABROw==",
"license": "ISC",
"dependencies": {
- "@npmcli/name-from-folder": "^2.0.0",
- "glob": "^10.2.2",
- "minimatch": "^9.0.0",
- "read-package-json-fast": "^3.0.0"
+ "@npmcli/name-from-folder": "^4.0.0",
+ "@npmcli/package-json": "^7.0.0",
+ "glob": "^13.0.0",
+ "minimatch": "^10.0.3"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/metavuln-calculator": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-7.1.1.tgz",
- "integrity": "sha512-Nkxf96V0lAx3HCpVda7Vw4P23RILgdi/5K1fmj2tZkWIYLpXAN8k2UVVOsW16TsS5F8Ws2I7Cm+PU1/rsVF47g==",
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-9.0.3.tgz",
+ "integrity": "sha512-94GLSYhLXF2t2LAC7pDwLaM4uCARzxShyAQKsirmlNcpidH89VA4/+K1LbJmRMgz5gy65E/QBBWQdUvGLe2Frg==",
"license": "ISC",
"dependencies": {
- "cacache": "^18.0.0",
- "json-parse-even-better-errors": "^3.0.0",
- "pacote": "^18.0.0",
- "proc-log": "^4.1.0",
+ "cacache": "^20.0.0",
+ "json-parse-even-better-errors": "^5.0.0",
+ "pacote": "^21.0.0",
+ "proc-log": "^6.0.0",
"semver": "^7.3.5"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/name-from-folder": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz",
- "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-4.0.0.tgz",
+ "integrity": "sha512-qfrhVlOSqmKM8i6rkNdZzABj8MKEITGFAY+4teqBziksCQAOLutiAxM1wY2BKEd8KjUSpWmWCYxvXr0y4VTlPg==",
"license": "ISC",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/node-gyp": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz",
- "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz",
+ "integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==",
"license": "ISC",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/package-json": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.1.tgz",
- "integrity": "sha512-f7zYC6kQautXHvNbLEWgD/uGu1+xCn9izgqBfgItWSx22U0ZDekxN08A1vM8cTxj/cRVe0Q94Ode+tdoYmIOOQ==",
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.4.tgz",
+ "integrity": "sha512-0wInJG3j/K40OJt/33ax47WfWMzZTm6OQxB9cDhTt5huCP2a9g2GnlsxmfN+PulItNPIpPrZ+kfwwUil7eHcZQ==",
"license": "ISC",
"dependencies": {
- "@npmcli/git": "^5.0.0",
- "glob": "^10.2.2",
- "hosted-git-info": "^7.0.0",
- "json-parse-even-better-errors": "^3.0.0",
- "normalize-package-data": "^6.0.0",
- "proc-log": "^4.0.0",
- "semver": "^7.5.3"
+ "@npmcli/git": "^7.0.0",
+ "glob": "^13.0.0",
+ "hosted-git-info": "^9.0.0",
+ "json-parse-even-better-errors": "^5.0.0",
+ "proc-log": "^6.0.0",
+ "semver": "^7.5.3",
+ "validate-npm-package-license": "^3.0.4"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/promise-spawn": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz",
- "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==",
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz",
+ "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==",
"license": "ISC",
"dependencies": {
- "which": "^4.0.0"
+ "which": "^6.0.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/query": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-3.1.0.tgz",
- "integrity": "sha512-C/iR0tk7KSKGldibYIB9x8GtO/0Bd0I2mhOaDb8ucQL/bQVTmGoeREaFj64Z5+iCBRf3dQfed0CjJL7I8iTkiQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-5.0.0.tgz",
+ "integrity": "sha512-8TZWfTQOsODpLqo9SVhVjHovmKXNpevHU0gO9e+y4V4fRIOneiXy0u0sMP9LmS71XivrEWfZWg50ReH4WRT4aQ==",
"license": "ISC",
"dependencies": {
- "postcss-selector-parser": "^6.0.10"
+ "postcss-selector-parser": "^7.0.0"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/redact": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.1.tgz",
- "integrity": "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz",
+ "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==",
"license": "ISC",
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@npmcli/run-script": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.1.0.tgz",
- "integrity": "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==",
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.3.tgz",
+ "integrity": "sha512-ER2N6itRkzWbbtVmZ9WKaWxVlKlOeBFF1/7xx+KA5J1xKa4JjUwBdb6tDpk0v1qA+d+VDwHI9qmLcXSWcmi+Rw==",
"license": "ISC",
"dependencies": {
- "@npmcli/node-gyp": "^3.0.0",
- "@npmcli/package-json": "^5.0.0",
- "@npmcli/promise-spawn": "^7.0.0",
- "node-gyp": "^10.0.0",
- "proc-log": "^4.0.0",
- "which": "^4.0.0"
+ "@npmcli/node-gyp": "^5.0.0",
+ "@npmcli/package-json": "^7.0.0",
+ "@npmcli/promise-spawn": "^9.0.0",
+ "node-gyp": "^12.1.0",
+ "proc-log": "^6.0.0",
+ "which": "^6.0.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@opentelemetry/api": {
@@ -533,16 +590,6 @@
"node": ">=14"
}
},
- "node_modules/@pkgjs/parseargs": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
- "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
- "license": "MIT",
- "optional": true,
- "engines": {
- "node": ">=14"
- }
- },
"node_modules/@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
@@ -608,9 +655,9 @@
"license": "BSD-3-Clause"
},
"node_modules/@pulumi/github": {
- "version": "6.7.3",
- "resolved": "https://registry.npmjs.org/@pulumi/github/-/github-6.7.3.tgz",
- "integrity": "sha512-uqXvZba3FIc5ZSZFk6G5fMtNvtjQAOP+pg8hXFx8VAd01eCXqquY6xgB5HlR7xhHclGanAjtyaWOyvTrHDP3kQ==",
+ "version": "6.12.1",
+ "resolved": "https://registry.npmjs.org/@pulumi/github/-/github-6.12.1.tgz",
+ "integrity": "sha512-OsbQgF8go/tA1PuMhFq7O0XVfYbwRk0/LHaZTH6OFO395SufdFFa1go3IeXvJCSA5oDCbdULerGg4n9sP8vTLg==",
"license": "Apache-2.0",
"dependencies": {
"@pulumi/pulumi": "^3.142.0"
@@ -621,14 +668,14 @@
"link": true
},
"node_modules/@pulumi/pulumi": {
- "version": "3.197.0",
- "resolved": "https://registry.npmjs.org/@pulumi/pulumi/-/pulumi-3.197.0.tgz",
- "integrity": "sha512-Pfjg6sluGDw11crvmI8wbi5k4YDBTxZBM1aI7h5Gd2a4DUyVhrSMUE2fFd1XN05wQKEDisahsygBbBZO0lg2zw==",
+ "version": "3.219.0",
+ "resolved": "https://registry.npmjs.org/@pulumi/pulumi/-/pulumi-3.219.0.tgz",
+ "integrity": "sha512-0AO1ZBJooKALToZYvPj/93PpToGA2rEKvIGQi95zNHevTTC3ibQrKXJDLwQzjHy6HZrON2jbxzakKrU4C2w+hA==",
"license": "Apache-2.0",
"dependencies": {
"@grpc/grpc-js": "^1.10.1",
"@logdna/tail-file": "^2.0.6",
- "@npmcli/arborist": "^7.3.1",
+ "@npmcli/arborist": "^9.0.0",
"@opentelemetry/api": "^1.9",
"@opentelemetry/exporter-zipkin": "^1.28",
"@opentelemetry/instrumentation": "^0.55",
@@ -640,15 +687,15 @@
"@types/semver": "^7.5.6",
"@types/tmp": "^0.2.6",
"execa": "^5.1.0",
- "fdir": "^6.1.1",
+ "fdir": "^6.5.0",
"google-protobuf": "^3.21.4",
"got": "^11.8.6",
"ini": "^2.0.0",
- "js-yaml": "^3.14.0",
+ "js-yaml": "^3.14.2",
"minimist": "^1.2.6",
"normalize-package-data": "^6.0.0",
+ "package-directory": "^8.1.0",
"picomatch": "^3.0.1",
- "pkg-dir": "^7.0.0",
"require-from-string": "^2.0.1",
"semver": "^7.5.2",
"source-map-support": "^0.5.6",
@@ -671,78 +718,87 @@
}
}
},
+ "node_modules/@pulumi/random": {
+ "version": "4.19.1",
+ "resolved": "https://registry.npmjs.org/@pulumi/random/-/random-4.19.1.tgz",
+ "integrity": "sha512-gDotQyxtl+pcJb4oaGfbi6PsK8OtzjBmF1D8PYLvr13kCup98KTIIv/8wF2xbgbFf7ljJn3EblADxZ0u8AC/Dg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@pulumi/pulumi": "^3.142.0"
+ }
+ },
"node_modules/@sigstore/bundle": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz",
- "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz",
+ "integrity": "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==",
"license": "Apache-2.0",
"dependencies": {
- "@sigstore/protobuf-specs": "^0.3.2"
+ "@sigstore/protobuf-specs": "^0.5.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@sigstore/core": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz",
- "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.1.0.tgz",
+ "integrity": "sha512-o5cw1QYhNQ9IroioJxpzexmPjfCe7gzafd2RY3qnMpxr4ZEja+Jad/U8sgFpaue6bOaF+z7RVkyKVV44FN+N8A==",
"license": "Apache-2.0",
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@sigstore/protobuf-specs": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.3.tgz",
- "integrity": "sha512-RpacQhBlwpBWd7KEJsRKcBQalbV28fvkxwTOJIqhIuDysMMaJW47V4OqW30iJB9uRpqOSxxEAQFdr8tTattReQ==",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.0.tgz",
+ "integrity": "sha512-MM8XIwUjN2bwvCg1QvrMtbBmpcSHrkhFSCu1D11NyPvDQ25HEc4oG5/OcQfd/Tlf/OxmKWERDj0zGE23jQaMwA==",
"license": "Apache-2.0",
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/@sigstore/sign": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz",
- "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.1.0.tgz",
+ "integrity": "sha512-Vx1RmLxLGnSUqx/o5/VsCjkuN5L7y+vxEEwawvc7u+6WtX2W4GNa7b9HEjmcRWohw/d6BpATXmvOwc78m+Swdg==",
"license": "Apache-2.0",
"dependencies": {
- "@sigstore/bundle": "^2.3.2",
- "@sigstore/core": "^1.0.0",
- "@sigstore/protobuf-specs": "^0.3.2",
- "make-fetch-happen": "^13.0.1",
- "proc-log": "^4.2.0",
+ "@sigstore/bundle": "^4.0.0",
+ "@sigstore/core": "^3.1.0",
+ "@sigstore/protobuf-specs": "^0.5.0",
+ "make-fetch-happen": "^15.0.3",
+ "proc-log": "^6.1.0",
"promise-retry": "^2.0.1"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@sigstore/tuf": {
- "version": "2.3.4",
- "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz",
- "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.1.tgz",
+ "integrity": "sha512-OPZBg8y5Vc9yZjmWCHrlWPMBqW5yd8+wFNl+thMdtcWz3vjVSoJQutF8YkrzI0SLGnkuFof4HSsWUhXrf219Lw==",
"license": "Apache-2.0",
"dependencies": {
- "@sigstore/protobuf-specs": "^0.3.2",
- "tuf-js": "^2.2.1"
+ "@sigstore/protobuf-specs": "^0.5.0",
+ "tuf-js": "^4.1.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@sigstore/verify": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz",
- "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.0.tgz",
+ "integrity": "sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==",
"license": "Apache-2.0",
"dependencies": {
- "@sigstore/bundle": "^2.3.2",
- "@sigstore/core": "^1.1.0",
- "@sigstore/protobuf-specs": "^0.3.2"
+ "@sigstore/bundle": "^4.0.0",
+ "@sigstore/core": "^3.1.0",
+ "@sigstore/protobuf-specs": "^0.5.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@sindresorhus/is": {
@@ -769,6 +825,34 @@
"node": ">=10"
}
},
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
+ "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/@tufjs/canonical-json": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz",
@@ -779,16 +863,16 @@
}
},
"node_modules/@tufjs/models": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz",
- "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-4.1.0.tgz",
+ "integrity": "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==",
"license": "MIT",
"dependencies": {
"@tufjs/canonical-json": "2.0.0",
- "minimatch": "^9.0.4"
+ "minimatch": "^10.1.1"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/@types/cacheable-request": {
@@ -825,9 +909,9 @@
}
},
"node_modules/@types/node": {
- "version": "22.18.6",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.6.tgz",
- "integrity": "sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==",
+ "version": "22.19.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.2.tgz",
+ "integrity": "sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
@@ -861,12 +945,12 @@
"license": "MIT"
},
"node_modules/abbrev": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
- "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz",
+ "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==",
"license": "ISC",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/acorn": {
@@ -890,51 +974,34 @@
"acorn": "^8"
}
},
- "node_modules/agent-base": {
- "version": "7.1.4",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
- "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/aggregate-error": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
- "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "node_modules/acorn-walk": {
+ "version": "8.3.5",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz",
+ "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
+ "devOptional": true,
"license": "MIT",
"dependencies": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
+ "acorn": "^8.11.0"
},
"engines": {
- "node": ">=8"
+ "node": ">=0.4.0"
}
},
- "node_modules/ansi-regex": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
- "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "node_modules/agent-base": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
"license": "MIT",
"engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ "node": ">= 14"
}
},
- "node_modules/ansi-styles": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
- "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "devOptional": true,
+ "license": "MIT"
},
"node_modules/argparse": {
"version": "1.0.10",
@@ -954,34 +1021,20 @@
"tslib": "^2.4.0"
}
},
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "license": "MIT"
- },
"node_modules/bin-links": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.4.tgz",
- "integrity": "sha512-cMtq4W5ZsEwcutJrVId+a/tjt8GSbS+h0oNkdl6+6rBuEv8Ot33Bevj5KPm40t309zuhVic8NjpuL42QCiJWWA==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-6.0.0.tgz",
+ "integrity": "sha512-X4CiKlcV2GjnCMwnKAfbVWpHa++65th9TuzAEYtZoATiOE2DQKhSp4CJlyLoTqdhBKlXjpXjCTYPNNFS33Fi6w==",
"license": "ISC",
"dependencies": {
- "cmd-shim": "^6.0.0",
- "npm-normalize-package-bin": "^3.0.0",
- "read-cmd-shim": "^4.0.0",
- "write-file-atomic": "^5.0.0"
+ "cmd-shim": "^8.0.0",
+ "npm-normalize-package-bin": "^5.0.0",
+ "proc-log": "^6.0.0",
+ "read-cmd-shim": "^6.0.0",
+ "write-file-atomic": "^7.0.0"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
- }
- },
- "node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/buffer-from": {
@@ -991,26 +1044,25 @@
"license": "MIT"
},
"node_modules/cacache": {
- "version": "18.0.4",
- "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz",
- "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==",
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz",
+ "integrity": "sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==",
"license": "ISC",
"dependencies": {
- "@npmcli/fs": "^3.1.0",
+ "@npmcli/fs": "^5.0.0",
"fs-minipass": "^3.0.0",
- "glob": "^10.2.2",
- "lru-cache": "^10.0.1",
+ "glob": "^13.0.0",
+ "lru-cache": "^11.1.0",
"minipass": "^7.0.3",
"minipass-collect": "^2.0.1",
"minipass-flush": "^1.0.5",
"minipass-pipeline": "^1.2.4",
- "p-map": "^4.0.0",
- "ssri": "^10.0.0",
- "tar": "^6.1.11",
- "unique-filename": "^3.0.0"
+ "p-map": "^7.0.2",
+ "ssri": "^13.0.0",
+ "unique-filename": "^5.0.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/cacheable-lookup": {
@@ -1056,12 +1108,12 @@
}
},
"node_modules/chownr": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
- "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
- "license": "ISC",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "license": "BlueOak-1.0.0",
"engines": {
- "node": ">=10"
+ "node": ">=18"
}
},
"node_modules/cjs-module-lexer": {
@@ -1070,15 +1122,6 @@
"integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
"license": "MIT"
},
- "node_modules/clean-stack": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
- "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@@ -1179,12 +1222,12 @@
}
},
"node_modules/cmd-shim": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.3.tgz",
- "integrity": "sha512-FMabTRlc5t5zjdenF6mS0MBeFZm0XqHqeOkcskKFb/LYCcRQ5fVgLOHVc4Lq9CqABd9zhjwPjMBCJvMCziSVtA==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-8.0.0.tgz",
+ "integrity": "sha512-Jk/BK6NCapZ58BKUxlSI+ouKRbjH1NLZCgJkYoab+vEHUY3f6OzpNBN9u7HFSv9J6TRDGs4PLOHezoKGaFRSCA==",
"license": "ISC",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/color-convert": {
@@ -1206,10 +1249,20 @@
"license": "MIT"
},
"node_modules/common-ancestor-path": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz",
- "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==",
- "license": "ISC"
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz",
+ "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "devOptional": true,
+ "license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
@@ -1311,17 +1364,15 @@
"node": ">=10"
}
},
- "node_modules/eastasianwidth": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
- "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
- "license": "MIT"
- },
- "node_modules/emoji-regex": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
- "license": "MIT"
+ "node_modules/diff": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz",
+ "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
+ "devOptional": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
},
"node_modules/encoding": {
"version": "0.1.13",
@@ -1403,9 +1454,9 @@
}
},
"node_modules/exponential-backoff": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz",
- "integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz",
+ "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
"license": "Apache-2.0"
},
"node_modules/fdir": {
@@ -1425,50 +1476,18 @@
}
}
},
- "node_modules/find-up": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
- "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
+ "node_modules/find-up-simple": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz",
+ "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==",
"license": "MIT",
- "dependencies": {
- "locate-path": "^7.1.0",
- "path-exists": "^5.0.0"
- },
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/foreground-child": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
- "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
- "license": "ISC",
- "dependencies": {
- "cross-spawn": "^7.0.6",
- "signal-exit": "^4.0.1"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/foreground-child/node_modules/signal-exit": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
- "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
- "license": "ISC",
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/fs-minipass": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz",
@@ -1512,20 +1531,17 @@
}
},
"node_modules/glob": {
- "version": "10.4.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
- "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
- "license": "ISC",
+ "version": "13.0.1",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.1.tgz",
+ "integrity": "sha512-B7U/vJpE3DkJ5WXTgTpTRN63uV42DseiXXKMwG14LQBXmsdeIoHAPbU/MEo6II0k5ED74uc2ZGTC6MwHFQhF6w==",
+ "license": "BlueOak-1.0.0",
"dependencies": {
- "foreground-child": "^3.1.0",
- "jackspeak": "^3.1.2",
- "minimatch": "^9.0.4",
+ "minimatch": "^10.1.2",
"minipass": "^7.1.2",
- "package-json-from-dist": "^1.0.0",
- "path-scurry": "^1.11.1"
+ "path-scurry": "^2.0.0"
},
- "bin": {
- "glob": "dist/esm/bin.mjs"
+ "engines": {
+ "node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -1581,15 +1597,15 @@
}
},
"node_modules/hosted-git-info": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
- "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz",
+ "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==",
"license": "ISC",
"dependencies": {
- "lru-cache": "^10.0.1"
+ "lru-cache": "^11.1.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/http-cache-semantics": {
@@ -1660,21 +1676,21 @@
}
},
"node_modules/ignore-walk": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz",
- "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz",
+ "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==",
"license": "ISC",
"dependencies": {
- "minimatch": "^9.0.0"
+ "minimatch": "^10.0.3"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/import-in-the-middle": {
- "version": "1.14.2",
- "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.14.2.tgz",
- "integrity": "sha512-5tCuY9BV8ujfOpwtAGgsTx9CGUapcFMEEyByLv1B+v2+6DhAcw+Zr0nhQT7uwaZ7DiourxFEscghOR8e1aPLQw==",
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.15.0.tgz",
+ "integrity": "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==",
"license": "Apache-2.0",
"dependencies": {
"acorn": "^8.14.0",
@@ -1692,15 +1708,6 @@
"node": ">=0.8.19"
}
},
- "node_modules/indent-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/ini": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
@@ -1711,9 +1718,9 @@
}
},
"node_modules/ip-address": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
- "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==",
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
+ "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
"license": "MIT",
"engines": {
"node": ">= 12"
@@ -1743,12 +1750,6 @@
"node": ">=8"
}
},
- "node_modules/is-lambda": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
- "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
- "license": "MIT"
- },
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -1762,33 +1763,18 @@
}
},
"node_modules/isexe": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
- "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
- "license": "ISC",
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/jackspeak": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
- "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.2.tgz",
+ "integrity": "sha512-mIcis6w+JiQf3P7t7mg/35GKB4T1FQsBOtMIvuKw4YErj5RjtbhcTd5/I30fmkmGMwvI0WlzSNN+27K0QCMkAw==",
"license": "BlueOak-1.0.0",
- "dependencies": {
- "@isaacs/cliui": "^8.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- },
- "optionalDependencies": {
- "@pkgjs/parseargs": "^0.11.0"
+ "engines": {
+ "node": ">=20"
}
},
"node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
@@ -1805,12 +1791,12 @@
"license": "MIT"
},
"node_modules/json-parse-even-better-errors": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz",
- "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz",
+ "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==",
"license": "MIT",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/json-stringify-nice": {
@@ -1852,21 +1838,6 @@
"json-buffer": "3.0.1"
}
},
- "node_modules/locate-path": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
- "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
- "license": "MIT",
- "dependencies": {
- "p-locate": "^6.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
@@ -1889,32 +1860,41 @@
}
},
"node_modules/lru-cache": {
- "version": "10.4.3",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
- "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "version": "11.2.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz",
+ "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "devOptional": true,
"license": "ISC"
},
"node_modules/make-fetch-happen": {
- "version": "13.0.1",
- "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz",
- "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.3.tgz",
+ "integrity": "sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw==",
"license": "ISC",
"dependencies": {
- "@npmcli/agent": "^2.0.0",
- "cacache": "^18.0.0",
+ "@npmcli/agent": "^4.0.0",
+ "cacache": "^20.0.1",
"http-cache-semantics": "^4.1.1",
- "is-lambda": "^1.0.1",
"minipass": "^7.0.2",
- "minipass-fetch": "^3.0.0",
+ "minipass-fetch": "^5.0.0",
"minipass-flush": "^1.0.5",
"minipass-pipeline": "^1.2.4",
- "negotiator": "^0.6.3",
- "proc-log": "^4.2.0",
+ "negotiator": "^1.0.0",
+ "proc-log": "^6.0.0",
"promise-retry": "^2.0.1",
- "ssri": "^10.0.0"
+ "ssri": "^13.0.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/merge-stream": {
@@ -1942,15 +1922,15 @@
}
},
"node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "license": "ISC",
+ "version": "10.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
+ "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
+ "license": "BlueOak-1.0.0",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "@isaacs/brace-expansion": "^5.0.1"
},
"engines": {
- "node": ">=16 || 14 >=14.17"
+ "node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -1987,17 +1967,17 @@
}
},
"node_modules/minipass-fetch": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz",
- "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.1.tgz",
+ "integrity": "sha512-yHK8pb0iCGat0lDrs/D6RZmCdaBT64tULXjdxjSMAqoDi18Q3qKEUTHypHQZQd9+FYpIS+lkvpq6C/R6SbUeRw==",
"license": "MIT",
"dependencies": {
"minipass": "^7.0.3",
- "minipass-sized": "^1.0.3",
- "minizlib": "^2.1.2"
+ "minipass-sized": "^2.0.0",
+ "minizlib": "^3.0.1"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
},
"optionalDependencies": {
"encoding": "^0.1.13"
@@ -2027,6 +2007,12 @@
"node": ">=8"
}
},
+ "node_modules/minipass-flush/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "license": "ISC"
+ },
"node_modules/minipass-pipeline": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
@@ -2051,65 +2037,34 @@
"node": ">=8"
}
},
- "node_modules/minipass-sized": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz",
- "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==",
- "license": "ISC",
- "dependencies": {
- "minipass": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
+ "node_modules/minipass-pipeline/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "license": "ISC"
},
- "node_modules/minipass-sized/node_modules/minipass": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "node_modules/minipass-sized": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-2.0.0.tgz",
+ "integrity": "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==",
"license": "ISC",
"dependencies": {
- "yallist": "^4.0.0"
+ "minipass": "^7.1.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/minizlib": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
- "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
"license": "MIT",
"dependencies": {
- "minipass": "^3.0.0",
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/minizlib/node_modules/minipass": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
- "license": "ISC",
- "dependencies": {
- "yallist": "^4.0.0"
+ "minipass": "^7.1.2"
},
"engines": {
- "node": ">=8"
- }
- },
- "node_modules/mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "license": "MIT",
- "bin": {
- "mkdirp": "bin/cmd.js"
- },
- "engines": {
- "node": ">=10"
+ "node": ">= 18"
}
},
"node_modules/module-details-from-path": {
@@ -2125,51 +2080,51 @@
"license": "MIT"
},
"node_modules/negotiator": {
- "version": "0.6.4",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
- "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/node-gyp": {
- "version": "10.3.1",
- "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.3.1.tgz",
- "integrity": "sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==",
+ "version": "12.2.0",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.2.0.tgz",
+ "integrity": "sha512-q23WdzrQv48KozXlr0U1v9dwO/k59NHeSzn6loGcasyf0UnSrtzs8kRxM+mfwJSf0DkX0s43hcqgnSO4/VNthQ==",
"license": "MIT",
"dependencies": {
"env-paths": "^2.2.0",
"exponential-backoff": "^3.1.1",
- "glob": "^10.3.10",
"graceful-fs": "^4.2.6",
- "make-fetch-happen": "^13.0.0",
- "nopt": "^7.0.0",
- "proc-log": "^4.1.0",
+ "make-fetch-happen": "^15.0.0",
+ "nopt": "^9.0.0",
+ "proc-log": "^6.0.0",
"semver": "^7.3.5",
- "tar": "^6.2.1",
- "which": "^4.0.0"
+ "tar": "^7.5.4",
+ "tinyglobby": "^0.2.12",
+ "which": "^6.0.0"
},
"bin": {
"node-gyp": "bin/node-gyp.js"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/nopt": {
- "version": "7.2.1",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
- "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz",
+ "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==",
"license": "ISC",
"dependencies": {
- "abbrev": "^2.0.0"
+ "abbrev": "^4.0.0"
},
"bin": {
"nopt": "bin/nopt.js"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/normalize-package-data": {
@@ -2186,6 +2141,24 @@
"node": "^16.14.0 || >=18.0.0"
}
},
+ "node_modules/normalize-package-data/node_modules/hosted-git-info": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
+ "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^10.0.1"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
+ },
+ "node_modules/normalize-package-data/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC"
+ },
"node_modules/normalize-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
@@ -2199,97 +2172,98 @@
}
},
"node_modules/npm-bundled": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz",
- "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz",
+ "integrity": "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==",
"license": "ISC",
"dependencies": {
- "npm-normalize-package-bin": "^3.0.0"
+ "npm-normalize-package-bin": "^5.0.0"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm-install-checks": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz",
- "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz",
+ "integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==",
"license": "BSD-2-Clause",
"dependencies": {
"semver": "^7.1.1"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm-normalize-package-bin": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz",
- "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz",
+ "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==",
"license": "ISC",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm-package-arg": {
- "version": "11.0.3",
- "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz",
- "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==",
+ "version": "13.0.2",
+ "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz",
+ "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==",
"license": "ISC",
"dependencies": {
- "hosted-git-info": "^7.0.0",
- "proc-log": "^4.0.0",
+ "hosted-git-info": "^9.0.0",
+ "proc-log": "^6.0.0",
"semver": "^7.3.5",
- "validate-npm-package-name": "^5.0.0"
+ "validate-npm-package-name": "^7.0.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm-packlist": {
- "version": "8.0.2",
- "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz",
- "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==",
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.3.tgz",
+ "integrity": "sha512-zPukTwJMOu5X5uvm0fztwS5Zxyvmk38H/LfidkOMt3gbZVCyro2cD/ETzwzVPcWZA3JOyPznfUN/nkyFiyUbxg==",
"license": "ISC",
"dependencies": {
- "ignore-walk": "^6.0.4"
+ "ignore-walk": "^8.0.0",
+ "proc-log": "^6.0.0"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm-pick-manifest": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz",
- "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==",
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz",
+ "integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==",
"license": "ISC",
"dependencies": {
- "npm-install-checks": "^6.0.0",
- "npm-normalize-package-bin": "^3.0.0",
- "npm-package-arg": "^11.0.0",
+ "npm-install-checks": "^8.0.0",
+ "npm-normalize-package-bin": "^5.0.0",
+ "npm-package-arg": "^13.0.0",
"semver": "^7.3.5"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm-registry-fetch": {
- "version": "17.1.0",
- "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz",
- "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==",
+ "version": "19.1.1",
+ "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz",
+ "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==",
"license": "ISC",
"dependencies": {
- "@npmcli/redact": "^2.0.0",
+ "@npmcli/redact": "^4.0.0",
"jsonparse": "^1.3.1",
- "make-fetch-happen": "^13.0.0",
+ "make-fetch-happen": "^15.0.0",
"minipass": "^7.0.2",
- "minipass-fetch": "^3.0.0",
- "minizlib": "^2.1.2",
- "npm-package-arg": "^11.0.0",
- "proc-log": "^4.0.0"
+ "minipass-fetch": "^5.0.0",
+ "minizlib": "^3.0.1",
+ "npm-package-arg": "^13.0.0",
+ "proc-log": "^6.0.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/npm-run-path": {
@@ -2337,109 +2311,76 @@
"node": ">=8"
}
},
- "node_modules/p-limit": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
- "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+ "node_modules/p-map": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz",
+ "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==",
"license": "MIT",
- "dependencies": {
- "yocto-queue": "^1.0.0"
- },
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-locate": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
- "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
- "license": "MIT",
- "dependencies": {
- "p-limit": "^4.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-map": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
- "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "node_modules/package-directory": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/package-directory/-/package-directory-8.1.0.tgz",
+ "integrity": "sha512-qHKRW0pw3lYdZMQVkjDBqh8HlamH/LCww2PH7OWEp4Qrt3SFeYMNpnJrQzlSnGrDD5zGR51XqBh7FnNCdVNEHA==",
"license": "MIT",
"dependencies": {
- "aggregate-error": "^3.0.0"
+ "find-up-simple": "^1.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/package-json-from-dist": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
- "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
- "license": "BlueOak-1.0.0"
- },
"node_modules/pacote": {
- "version": "18.0.6",
- "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz",
- "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==",
+ "version": "21.2.0",
+ "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.2.0.tgz",
+ "integrity": "sha512-OwidJA8uHuGYxoZhe4DBv3JJqGg4ojjVV5dwvVxRKq+bOBpgYMbYd/onIvSU1sv5nQIsb+zp4/0uqv6giFQVjg==",
"license": "ISC",
"dependencies": {
- "@npmcli/git": "^5.0.0",
- "@npmcli/installed-package-contents": "^2.0.1",
- "@npmcli/package-json": "^5.1.0",
- "@npmcli/promise-spawn": "^7.0.0",
- "@npmcli/run-script": "^8.0.0",
- "cacache": "^18.0.0",
+ "@npmcli/git": "^7.0.0",
+ "@npmcli/installed-package-contents": "^4.0.0",
+ "@npmcli/package-json": "^7.0.0",
+ "@npmcli/promise-spawn": "^9.0.0",
+ "@npmcli/run-script": "^10.0.0",
+ "cacache": "^20.0.0",
"fs-minipass": "^3.0.0",
"minipass": "^7.0.2",
- "npm-package-arg": "^11.0.0",
- "npm-packlist": "^8.0.0",
- "npm-pick-manifest": "^9.0.0",
- "npm-registry-fetch": "^17.0.0",
- "proc-log": "^4.0.0",
+ "npm-package-arg": "^13.0.0",
+ "npm-packlist": "^10.0.1",
+ "npm-pick-manifest": "^11.0.1",
+ "npm-registry-fetch": "^19.0.0",
+ "proc-log": "^6.0.0",
"promise-retry": "^2.0.1",
- "sigstore": "^2.2.0",
- "ssri": "^10.0.0",
- "tar": "^6.1.11"
+ "sigstore": "^4.0.0",
+ "ssri": "^13.0.0",
+ "tar": "^7.4.3"
},
"bin": {
"pacote": "bin/index.js"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/parse-conflict-json": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz",
- "integrity": "sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-5.0.1.tgz",
+ "integrity": "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ==",
"license": "ISC",
"dependencies": {
- "json-parse-even-better-errors": "^3.0.0",
+ "json-parse-even-better-errors": "^5.0.0",
"just-diff": "^6.0.0",
"just-diff-apply": "^5.2.0"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
- }
- },
- "node_modules/path-exists": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
- "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
- "license": "MIT",
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/path-key": {
@@ -2458,16 +2399,16 @@
"license": "MIT"
},
"node_modules/path-scurry": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
- "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz",
+ "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==",
"license": "BlueOak-1.0.0",
"dependencies": {
- "lru-cache": "^10.2.0",
- "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ "lru-cache": "^11.0.0",
+ "minipass": "^7.1.2"
},
"engines": {
- "node": ">=16 || 14 >=14.18"
+ "node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -2485,50 +2426,51 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
- "node_modules/pkg-dir": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz",
- "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==",
+ "node_modules/postcss-selector-parser": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
+ "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
"license": "MIT",
"dependencies": {
- "find-up": "^6.3.0"
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
},
"engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">=4"
}
},
- "node_modules/postcss-selector-parser": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
- "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+ "node_modules/prettier": {
+ "version": "3.7.4",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
+ "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
+ "dev": true,
"license": "MIT",
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
+ "bin": {
+ "prettier": "bin/prettier.cjs"
},
"engines": {
- "node": ">=4"
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/proc-log": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz",
- "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+ "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
"license": "ISC",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/proggy": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/proggy/-/proggy-2.0.0.tgz",
- "integrity": "sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/proggy/-/proggy-4.0.0.tgz",
+ "integrity": "sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ==",
"license": "ISC",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/promise-all-reject-late": {
@@ -2549,12 +2491,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/promise-inflight": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
- "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==",
- "license": "ISC"
- },
"node_modules/promise-retry": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
@@ -2615,25 +2551,12 @@
}
},
"node_modules/read-cmd-shim": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz",
- "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==",
- "license": "ISC",
- "engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
- }
- },
- "node_modules/read-package-json-fast": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz",
- "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-6.0.0.tgz",
+ "integrity": "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A==",
"license": "ISC",
- "dependencies": {
- "json-parse-even-better-errors": "^3.0.0",
- "npm-normalize-package-bin": "^3.0.0"
- },
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/require-directory": {
@@ -2669,12 +2592,12 @@
}
},
"node_modules/resolve": {
- "version": "1.22.10",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
- "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "version": "1.22.11",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
+ "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
"license": "MIT",
"dependencies": {
- "is-core-module": "^2.16.0",
+ "is-core-module": "^2.16.1",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
@@ -2723,9 +2646,9 @@
"optional": true
},
"node_modules/semver": {
- "version": "7.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
- "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -2768,20 +2691,20 @@
"license": "ISC"
},
"node_modules/sigstore": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz",
- "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.0.tgz",
+ "integrity": "sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==",
"license": "Apache-2.0",
"dependencies": {
- "@sigstore/bundle": "^2.3.2",
- "@sigstore/core": "^1.0.0",
- "@sigstore/protobuf-specs": "^0.3.2",
- "@sigstore/sign": "^2.3.2",
- "@sigstore/tuf": "^2.3.4",
- "@sigstore/verify": "^1.2.1"
+ "@sigstore/bundle": "^4.0.0",
+ "@sigstore/core": "^3.1.0",
+ "@sigstore/protobuf-specs": "^0.5.0",
+ "@sigstore/sign": "^4.1.0",
+ "@sigstore/tuf": "^4.0.1",
+ "@sigstore/verify": "^3.1.0"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/smart-buffer": {
@@ -2880,111 +2803,15 @@
"license": "BSD-3-Clause"
},
"node_modules/ssri": {
- "version": "10.0.6",
- "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz",
- "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==",
+ "version": "13.0.0",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.0.tgz",
+ "integrity": "sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==",
"license": "ISC",
"dependencies": {
"minipass": "^7.0.3"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
- }
- },
- "node_modules/string-width": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
- "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
- "license": "MIT",
- "dependencies": {
- "eastasianwidth": "^0.2.0",
- "emoji-regex": "^9.2.2",
- "strip-ansi": "^7.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/string-width-cjs": {
- "name": "string-width",
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-width-cjs/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==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-width-cjs/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "license": "MIT"
- },
- "node_modules/string-width-cjs/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==",
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-ansi": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
- "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^6.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
- "node_modules/strip-ansi-cjs": {
- "name": "strip-ansi",
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-ansi-cjs/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==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/strip-final-newline": {
@@ -3009,53 +2836,47 @@
}
},
"node_modules/tar": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
- "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
- "license": "ISC",
+ "version": "7.5.7",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz",
+ "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==",
+ "license": "BlueOak-1.0.0",
"dependencies": {
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "minipass": "^5.0.0",
- "minizlib": "^2.1.1",
- "mkdirp": "^1.0.3",
- "yallist": "^4.0.0"
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.1.0",
+ "yallist": "^5.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=18"
}
},
- "node_modules/tar/node_modules/fs-minipass": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
- "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
- "license": "ISC",
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "license": "MIT",
"dependencies": {
- "minipass": "^3.0.0"
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
},
"engines": {
- "node": ">= 8"
- }
- },
- "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
- "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
- "license": "ISC",
- "dependencies": {
- "yallist": "^4.0.0"
+ "node": ">=12.0.0"
},
- "engines": {
- "node": ">=8"
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
}
},
- "node_modules/tar/node_modules/minipass": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
- "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
- "license": "ISC",
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "license": "MIT",
"engines": {
- "node": ">=8"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/tmp": {
@@ -3076,6 +2897,50 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
+ "node_modules/ts-node": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
+ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@@ -3083,23 +2948,23 @@
"license": "0BSD"
},
"node_modules/tuf-js": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz",
- "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-4.1.0.tgz",
+ "integrity": "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==",
"license": "MIT",
"dependencies": {
- "@tufjs/models": "2.0.1",
- "debug": "^4.3.4",
- "make-fetch-happen": "^13.0.1"
+ "@tufjs/models": "4.1.0",
+ "debug": "^4.4.3",
+ "make-fetch-happen": "^15.0.1"
},
"engines": {
- "node": "^16.14.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/typescript": {
- "version": "5.9.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
- "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
@@ -3117,27 +2982,27 @@
"license": "MIT"
},
"node_modules/unique-filename": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz",
- "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-5.0.0.tgz",
+ "integrity": "sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==",
"license": "ISC",
"dependencies": {
- "unique-slug": "^4.0.0"
+ "unique-slug": "^6.0.0"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/unique-slug": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz",
- "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-6.0.0.tgz",
+ "integrity": "sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==",
"license": "ISC",
"dependencies": {
"imurmurhash": "^0.1.4"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/upath": {
@@ -3156,6 +3021,13 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@@ -3167,24 +3039,27 @@
}
},
"node_modules/validate-npm-package-name": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz",
- "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==",
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz",
+ "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==",
"license": "ISC",
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/walk-up-path": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz",
- "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==",
- "license": "ISC"
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz",
+ "integrity": "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==",
+ "license": "ISC",
+ "engines": {
+ "node": "20 || >=22"
+ }
},
"node_modules/which": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
- "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz",
+ "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==",
"license": "ISC",
"dependencies": {
"isexe": "^3.1.1"
@@ -3193,98 +3068,7 @@
"node-which": "bin/which.js"
},
"engines": {
- "node": "^16.13.0 || >=18.0.0"
- }
- },
- "node_modules/wrap-ansi": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
- "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^6.1.0",
- "string-width": "^5.0.1",
- "strip-ansi": "^7.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/wrap-ansi-cjs": {
- "name": "wrap-ansi",
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/wrap-ansi-cjs/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==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "license": "MIT"
- },
- "node_modules/wrap-ansi-cjs/node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/wrap-ansi-cjs/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==",
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/wrappy": {
@@ -3294,16 +3078,16 @@
"license": "ISC"
},
"node_modules/write-file-atomic": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
- "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.0.tgz",
+ "integrity": "sha512-YnlPC6JqnZl6aO4uRc+dx5PHguiR9S6WeoLtpxNT9wIG+BDya7ZNE1q7KOjVgaA73hKhKLpVPgJ5QA9THQ5BRg==",
"license": "ISC",
"dependencies": {
"imurmurhash": "^0.1.4",
"signal-exit": "^4.0.1"
},
"engines": {
- "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/write-file-atomic/node_modules/signal-exit": {
@@ -3328,10 +3112,13 @@
}
},
"node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "license": "ISC"
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/yargs": {
"version": "17.7.2",
@@ -3401,16 +3188,14 @@
"node": ">=8"
}
},
- "node_modules/yocto-queue": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz",
- "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==",
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "devOptional": true,
"license": "MIT",
"engines": {
- "node": ">=12.20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">=6"
}
},
"sdks/googleworkspace": {
@@ -3425,9 +3210,9 @@
}
},
"sdks/googleworkspace/node_modules/@types/node": {
- "version": "18.19.127",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.127.tgz",
- "integrity": "sha512-gSjxjrnKXML/yo0BO099uPixMqfpJU0TKYjpfLU7TrtA2WWDki412Np/RSTPRil1saKBhvVVKzVx/p/6p94nVA==",
+ "version": "18.19.130",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
+ "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
"license": "MIT",
"dependencies": {
"undici-types": "~5.26.4"
diff --git a/package.json b/package.json
index fed8ef4..47aabb9 100644
--- a/package.json
+++ b/package.json
@@ -4,16 +4,24 @@
"description": "Infrastructure as Code for MCP access management",
"main": "src/index.ts",
"scripts": {
- "build": "tsc"
+ "build": "tsc",
+ "validate": "npx ts-node scripts/validate-config.ts",
+ "test": "npx ts-node scripts/test-config.ts",
+ "check": "npm run format:check && npm run validate && npm run test",
+ "format": "prettier --write .",
+ "format:check": "prettier --check ."
},
"license": "MIT",
"dependencies": {
- "@pulumi/github": "^6.7.3",
+ "@pulumi/github": "^6.11.0",
"@pulumi/googleworkspace": "file:sdks/googleworkspace",
- "@pulumi/pulumi": "^3.197.0"
+ "@pulumi/pulumi": "^3.218.0",
+ "@pulumi/random": "^4.14.0"
},
"devDependencies": {
"@types/node": "^22.18.6",
+ "prettier": "^3.7.2",
+ "ts-node": "^10.9.2",
"typescript": "^5.9.2"
}
}
diff --git a/scripts/test-config.ts b/scripts/test-config.ts
new file mode 100644
index 0000000..108e57e
--- /dev/null
+++ b/scripts/test-config.ts
@@ -0,0 +1,132 @@
+#!/usr/bin/env npx ts-node
+
+/**
+ * Tests the configuration structure without needing Pulumi credentials.
+ * Run with: npx ts-node scripts/test-config.ts
+ */
+
+import { ROLES, buildRoleLookup, getRolesForPlatform } from '../src/config/roles';
+import { ROLE_IDS, isValidRoleId } from '../src/config/roleIds';
+import { MEMBERS } from '../src/config/users';
+
+let passed = 0;
+let failed = 0;
+
+function test(name: string, fn: () => boolean) {
+ try {
+ if (fn()) {
+ console.log(`✓ ${name}`);
+ passed++;
+ } else {
+ console.log(`✗ ${name}`);
+ failed++;
+ }
+ } catch (e) {
+ console.log(`✗ ${name}: ${e}`);
+ failed++;
+ }
+}
+
+console.log('Testing role configuration...\n');
+
+// Test ROLE_IDS
+test('ROLE_IDS has entries', () => Object.keys(ROLE_IDS).length > 0);
+test('All ROLE_IDS values are valid', () =>
+ Object.values(ROLE_IDS).every((id) => isValidRoleId(id)));
+
+// Test ROLES
+test('ROLES array is not empty', () => ROLES.length > 0);
+test('All roles have id and description', () => ROLES.every((r) => r.id && r.description));
+test('All role IDs are unique', () => {
+ const ids = ROLES.map((r) => r.id);
+ return ids.length === new Set(ids).size;
+});
+
+// Test platform configs
+const githubRoles = getRolesForPlatform('github');
+const discordRoles = getRolesForPlatform('discord');
+const googleRoles = getRolesForPlatform('google');
+
+test('Has GitHub roles', () => githubRoles.length > 0);
+test('Has Discord roles', () => discordRoles.length > 0);
+test('Has Google roles', () => googleRoles.length > 0);
+
+test('GitHub roles have team names', () => githubRoles.every((r) => r.github?.team));
+test('Discord roles have role names', () => discordRoles.every((r) => r.discord?.role));
+test('Google roles have group names', () => googleRoles.every((r) => r.google?.group));
+
+// Test parent relationships
+const roleLookup = buildRoleLookup();
+test('All GitHub parent references are valid', () =>
+ githubRoles.every((r) => {
+ if (!r.github?.parent) return true;
+ const parent = roleLookup.get(r.github.parent);
+ return parent && parent.github;
+ }));
+
+// Test members
+test('MEMBERS array is not empty', () => MEMBERS.length > 0);
+test('All members have at least one identifier', () =>
+ MEMBERS.every((m) => m.github || m.email || m.discord));
+test('All member role references are valid', () =>
+ MEMBERS.every((m) => m.memberOf.every((id) => roleLookup.has(id))));
+
+// Test specific roles exist
+test('CORE_MAINTAINERS role exists', () => !!roleLookup.get(ROLE_IDS.CORE_MAINTAINERS));
+test('ADMINISTRATORS role exists (Discord-only)', () => {
+ const role = roleLookup.get(ROLE_IDS.ADMINISTRATORS);
+ return role !== undefined && role.discord !== undefined && role.github === undefined;
+});
+test('TYPESCRIPT_SDK_AUTH role exists (GitHub-only)', () => {
+ const role = roleLookup.get(ROLE_IDS.TYPESCRIPT_SDK_AUTH);
+ return role !== undefined && role.github !== undefined && role.discord === undefined;
+});
+
+// Test Google Workspace user provisioning
+test('Roles with provisionUser exist', () => {
+ const provisionRoles = ROLES.filter((r) => r.google?.provisionUser);
+ return provisionRoles.length > 0;
+});
+
+test('Members with googleEmailPrefix have firstName and lastName', () =>
+ MEMBERS.every((m) => {
+ if (!m.googleEmailPrefix) return true;
+ return !!m.firstName && !!m.lastName;
+ }));
+
+test('googleEmailPrefix values are unique', () => {
+ const prefixes = MEMBERS.filter((m) => m.googleEmailPrefix).map((m) => m.googleEmailPrefix);
+ return prefixes.length === new Set(prefixes).size;
+});
+
+test('skipGoogleUserProvisioning is only used in provisionUser roles and without fields', () => {
+ const provisionRoleIds = new Set(ROLES.filter((r) => r.google?.provisionUser).map((r) => r.id));
+ return MEMBERS.every((member) => {
+ const inProvisionRole = member.memberOf.some((id) => provisionRoleIds.has(id));
+ if (!inProvisionRole) return !member.skipGoogleUserProvisioning;
+
+ const hasProvisioningFields = !!(
+ member.firstName &&
+ member.lastName &&
+ member.googleEmailPrefix
+ );
+ return !(hasProvisioningFields && member.skipGoogleUserProvisioning);
+ });
+});
+
+test('Some members in provisionUser roles have Google user fields', () => {
+ const membersInProvisionRoles = MEMBERS.filter((m) =>
+ m.memberOf.some((id) => {
+ const role = roleLookup.get(id);
+ return role?.google?.provisionUser === true;
+ })
+ );
+ const provisioned = membersInProvisionRoles.filter(
+ (m) => m.firstName && m.lastName && m.googleEmailPrefix
+ );
+ return membersInProvisionRoles.length > 0 && provisioned.length > 0;
+});
+
+// Summary
+console.log(`\n${passed} passed, ${failed} failed`);
+process.exit(failed > 0 ? 1 : 0);
diff --git a/scripts/validate-config.ts b/scripts/validate-config.ts
new file mode 100644
index 0000000..168c00f
--- /dev/null
+++ b/scripts/validate-config.ts
@@ -0,0 +1,185 @@
+#!/usr/bin/env npx ts-node
+
+/**
+ * Validates that all references in the config are valid.
+ * Run with: npx ts-node scripts/validate-config.ts
+ */
+
+import { ROLES, buildRoleLookup } from '../src/config/roles';
+import { REPOSITORY_ACCESS } from '../src/config/repoAccess';
+import { MEMBERS } from '../src/config/users';
+import type { RoleId } from '../src/config/roleIds';
+
+const roleLookup = buildRoleLookup();
+
+// Get all GitHub team names (roles that have GitHub config)
+const githubTeamNames = new Set();
+// Get all role IDs (for member validation)
+const allRoleIds = new Set();
+
+for (const role of ROLES) {
+ allRoleIds.add(role.id);
+
+ if (role.github) {
+ githubTeamNames.add(role.github.team);
+ }
+}
+
+let hasErrors = false;
+
+// Validate team references in REPOSITORY_ACCESS
+console.log('Validating team references in repoAccess.ts...');
+for (const repo of REPOSITORY_ACCESS) {
+ if (!repo.teams) continue;
+
+ for (const teamRef of repo.teams) {
+ if (!githubTeamNames.has(teamRef.team)) {
+ console.error(
+ `ERROR: Repository "${repo.repository}" references team "${teamRef.team}" which does not exist in roles.ts`
+ );
+ hasErrors = true;
+ }
+ }
+}
+
+// Validate role references in MEMBERS (memberOf)
+console.log('Validating role references in users.ts...');
+for (const member of MEMBERS) {
+ for (const roleId of member.memberOf) {
+ if (!allRoleIds.has(roleId)) {
+ console.error(
+ `ERROR: Member "${member.github || member.email}" references role "${roleId}" which does not exist in roles.ts`
+ );
+ hasErrors = true;
+ }
+ }
+}
+
+// Validate member ordering in users.ts
+console.log('Validating member ordering in users.ts...');
+{
+ // Split members into github members and email-only members
+ const githubMembers: (typeof MEMBERS)[number][] = [];
+ const emailOnlyMembers: (typeof MEMBERS)[number][] = [];
+
+ for (const member of MEMBERS) {
+ if (member.github) {
+ githubMembers.push(member);
+ } else if (member.email) {
+ emailOnlyMembers.push(member);
+ }
+ }
+
+ // Check that github members come before email-only members
+ let foundEmailOnly = false;
+ for (const member of MEMBERS) {
+ if (!member.github && member.email) {
+ foundEmailOnly = true;
+ } else if (member.github && foundEmailOnly) {
+ console.error(
+ `ERROR: Member "${member.github}" appears after email-only members. GitHub members should come before email-only members.`
+ );
+ hasErrors = true;
+ break;
+ }
+ }
+
+ // Check that github members are sorted alphabetically (case-insensitive)
+ for (let i = 1; i < githubMembers.length; i++) {
+ const prev = githubMembers[i - 1].github!.toLowerCase();
+ const curr = githubMembers[i].github!.toLowerCase();
+ if (prev > curr) {
+ console.error(
+ `ERROR: Members are not sorted alphabetically. "${githubMembers[i - 1].github}" should come after "${githubMembers[i].github}".`
+ );
+ hasErrors = true;
+ break;
+ }
+ }
+}
+
+// Validate Google Workspace user provisioning fields
+console.log('Validating Google Workspace user provisioning fields...');
+{
+ const googleEmailPrefixes = new Map();
+
+ for (const member of MEMBERS) {
+ const memberId = member.github || member.email || 'unknown';
+
+ // Members with googleEmailPrefix must also have firstName and lastName
+ if (member.googleEmailPrefix) {
+ if (!member.firstName) {
+ console.error(`ERROR: Member "${memberId}" has googleEmailPrefix but is missing firstName`);
+ hasErrors = true;
+ }
+ if (!member.lastName) {
+ console.error(`ERROR: Member "${memberId}" has googleEmailPrefix but is missing lastName`);
+ hasErrors = true;
+ }
+
+ // Check uniqueness of googleEmailPrefix
+ const existing = googleEmailPrefixes.get(member.googleEmailPrefix);
+ if (existing) {
+ console.error(
+ `ERROR: googleEmailPrefix "${member.googleEmailPrefix}" is used by both "${existing}" and "${memberId}"`
+ );
+ hasErrors = true;
+ } else {
+ googleEmailPrefixes.set(member.googleEmailPrefix, memberId);
+ }
+ }
+
+ // Members in provisionUser roles without all three fields won't get a GWS account
+ const inProvisionUserRole = member.memberOf.some((roleId: RoleId) => {
+ const role = roleLookup.get(roleId);
+ return role?.google?.provisionUser === true;
+ });
+
+ const hasProvisioningFields = !!(
+ member.googleEmailPrefix &&
+ member.firstName &&
+ member.lastName
+ );
+
+ if (member.skipGoogleUserProvisioning && !inProvisionUserRole) {
+ console.error(
+ `ERROR: Member "${memberId}" has skipGoogleUserProvisioning=true but is not in a provisionUser role`
+ );
+ hasErrors = true;
+ }
+
+ if (inProvisionUserRole && hasProvisioningFields && member.skipGoogleUserProvisioning) {
+ console.error(
+ `ERROR: Member "${memberId}" has provisioning fields and skipGoogleUserProvisioning=true; pick one`
+ );
+ hasErrors = true;
+ }
+ }
+}
+
+// Validate parent role references in roles.ts
+console.log('Validating parent role references in roles.ts...');
+for (const role of ROLES) {
+ if (!role.github?.parent) continue;
+
+ const parentRole = roleLookup.get(role.github.parent);
+ if (!parentRole) {
+ console.error(
+ `ERROR: Role "${role.id}" has parent "${role.github.parent}" which does not exist in roles.ts`
+ );
+ hasErrors = true;
+ } else if (!parentRole.github) {
+ console.error(
+ `ERROR: Role "${role.id}" has parent "${role.github.parent}" which does not have GitHub config`
+ );
+ hasErrors = true;
+ }
+}
+
+if (hasErrors) {
+ console.error('\nValidation failed! Please fix the errors above.');
+ process.exit(1);
+} else {
+ console.log('\nAll references are valid.');
+ process.exit(0);
+}
diff --git a/src/config/groups.ts b/src/config/groups.ts
deleted file mode 100644
index c336f3a..0000000
--- a/src/config/groups.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { defineGroups } from './utils';
-
-// NOTE: For GitHub teams, only the first memberOf will be used as the parent team.
-// GitHub only supports one parent team per team.
-//
-// Email groups (isEmailGroup: true) accept emails from anyone (including external users)
-// and notify group members for each email.
-//
-// Groups are created on all platforms (GitHub and Google) by default.
-// To limit a group to specific platforms, set the onlyOnPlatforms array (e.g., onlyOnPlatforms: ['google']).
-export const GROUPS = defineGroups([
- {
- name: 'test-parent',
- description: 'All maintainers. Users should not be added directly to this group.',
- },
- {
- name: 'test-child',
- description: 'Registry maintainers',
- memberOf: ['test-parent'],
- },
- {
- name: 'test-email-group',
- description: 'Example email group that accepts external emails',
- isEmailGroup: true,
- },
- {
- name: 'antitrust',
- description: 'Antitrust compliance contacts',
- isEmailGroup: true,
- onlyOnPlatforms: ['google'],
- },
- {
- name: 'catch-all',
- description: 'Catch-all email group',
- isEmailGroup: true,
- onlyOnPlatforms: ['google'],
- },
-] as const);
\ No newline at end of file
diff --git a/src/config/orgRoles.ts b/src/config/orgRoles.ts
new file mode 100644
index 0000000..576ec51
--- /dev/null
+++ b/src/config/orgRoles.ts
@@ -0,0 +1,23 @@
+// GitHub organization-level role assignments.
+// These grant a base permission across ALL repositories in the org via GitHub's
+// pre-defined organization roles, independent of per-repo collaborators in repoAccess.ts.
+// See https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/using-organization-roles
+
+export type OrgRoleName =
+ | 'all_repo_read'
+ | 'all_repo_triage'
+ | 'all_repo_write'
+ | 'all_repo_maintain'
+ | 'all_repo_admin';
+
+export interface OrgRoleAssignment {
+ /** GitHub team slug */
+ team: string;
+ /** Pre-defined GitHub organization role name */
+ role: OrgRoleName;
+}
+
+export const ORG_ROLE_ASSIGNMENTS: OrgRoleAssignment[] = [
+ { team: 'lead-maintainers', role: 'all_repo_admin' },
+ { team: 'core-maintainers', role: 'all_repo_admin' },
+];
diff --git a/src/config/orgSettings.ts b/src/config/orgSettings.ts
new file mode 100644
index 0000000..18f9a13
--- /dev/null
+++ b/src/config/orgSettings.ts
@@ -0,0 +1,33 @@
+// GitHub organization-level settings.
+// Captured explicitly so changes go through review. Values mirror current state
+// except defaultRepositoryPermission, which is set to 'none' so private repos
+// (disclosures, community-moderators, GHSA forks) are not implicitly readable
+// by every org member. Explicit access flows from orgRoles.ts and repoAccess.ts.
+
+// billingEmail is required by the provider but intentionally omitted here so it
+// is not committed to a public repo. It is read from Pulumi config in github.ts:
+// pulumi config set --secret githubBillingEmail
+export const ORG_SETTINGS = {
+ name: 'Model Context Protocol',
+ description:
+ 'An open protocol that enables seamless integration between LLM applications and external data sources and tools.',
+ defaultRepositoryPermission: 'none',
+ hasOrganizationProjects: true,
+ hasRepositoryProjects: true,
+ membersCanCreateRepositories: false,
+ membersCanCreatePublicRepositories: false,
+ membersCanCreatePrivateRepositories: false,
+ membersCanCreatePages: false,
+ membersCanCreatePublicPages: false,
+ membersCanCreatePrivatePages: false,
+ membersCanForkPrivateRepositories: false,
+ webCommitSignoffRequired: false,
+ // Provider defaults the following to `false` if omitted, which would silently
+ // disable org-wide security features that are currently on.
+ advancedSecurityEnabledForNewRepositories: true,
+ dependabotAlertsEnabledForNewRepositories: true,
+ dependabotSecurityUpdatesEnabledForNewRepositories: true,
+ dependencyGraphEnabledForNewRepositories: true,
+ secretScanningEnabledForNewRepositories: true,
+ secretScanningPushProtectionEnabledForNewRepositories: true,
+} as const;
diff --git a/src/config/repoAccess.ts b/src/config/repoAccess.ts
new file mode 100644
index 0000000..ced3ac1
--- /dev/null
+++ b/src/config/repoAccess.ts
@@ -0,0 +1,402 @@
+// Repository access configuration
+// Each repository lists all teams and users that should have access and their permission level
+
+export interface RepositoryAccess {
+ repository: string;
+ teams?: Array<{
+ team: string; // Team slug
+ permission: 'pull' | 'triage' | 'push' | 'maintain' | 'admin';
+ }>;
+ users?: Array<{
+ username: string; // GitHub username
+ permission: 'pull' | 'triage' | 'push' | 'maintain' | 'admin';
+ }>;
+}
+
+export const REPOSITORY_ACCESS: RepositoryAccess[] = [
+ {
+ repository: 'docs',
+ teams: [
+ { team: 'auth-maintainers', permission: 'push' },
+ { team: 'core-maintainers', permission: 'maintain' },
+ { team: 'csharp-sdk', permission: 'push' },
+ { team: 'docs-maintainers', permission: 'push' },
+ { team: 'go-sdk', permission: 'push' },
+ { team: 'ig-financial-services', permission: 'push' },
+ { team: 'interest-groups', permission: 'push' },
+ { team: 'java-sdk', permission: 'push' },
+ { team: 'kotlin-sdk', permission: 'push' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'php-sdk', permission: 'push' },
+ { team: 'python-sdk', permission: 'push' },
+ { team: 'python-sdk-auth', permission: 'push' },
+ { team: 'registry-wg', permission: 'push' },
+ { team: 'ruby-sdk', permission: 'push' },
+ { team: 'rust-sdk', permission: 'push' },
+ { team: 'sdk-maintainers', permission: 'push' },
+ { team: 'security-wg', permission: 'admin' },
+ { team: 'steering-committee', permission: 'push' },
+ { team: 'swift-sdk', permission: 'push' },
+ { team: 'transport-wg', permission: 'push' },
+ { team: 'typescript-sdk', permission: 'push' },
+ { team: 'typescript-sdk-auth', permission: 'push' },
+ { team: 'working-groups', permission: 'push' },
+ ],
+ },
+ {
+ repository: '.github',
+ teams: [
+ { team: 'auth-maintainers', permission: 'triage' },
+ { team: 'core-maintainers', permission: 'maintain' },
+ { team: 'csharp-sdk', permission: 'triage' },
+ { team: 'docs-maintainers', permission: 'triage' },
+ { team: 'go-sdk', permission: 'triage' },
+ { team: 'ig-financial-services', permission: 'triage' },
+ { team: 'interest-groups', permission: 'triage' },
+ { team: 'java-sdk', permission: 'triage' },
+ { team: 'kotlin-sdk', permission: 'triage' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'php-sdk', permission: 'triage' },
+ { team: 'python-sdk', permission: 'triage' },
+ { team: 'python-sdk-auth', permission: 'triage' },
+ { team: 'registry-wg', permission: 'triage' },
+ { team: 'ruby-sdk', permission: 'triage' },
+ { team: 'rust-sdk', permission: 'triage' },
+ { team: 'sdk-maintainers', permission: 'triage' },
+ { team: 'security-wg', permission: 'admin' },
+ { team: 'steering-committee', permission: 'triage' },
+ { team: 'swift-sdk', permission: 'triage' },
+ { team: 'transport-wg', permission: 'triage' },
+ { team: 'typescript-sdk', permission: 'triage' },
+ { team: 'typescript-sdk-auth', permission: 'triage' },
+ { team: 'working-groups', permission: 'triage' },
+ ],
+ },
+ {
+ repository: 'inspector',
+ teams: [
+ { team: 'inspector-maintainers', permission: 'push' },
+ { team: 'auth-maintainers', permission: 'push' },
+ { team: 'core-maintainers', permission: 'maintain' },
+ { team: 'csharp-sdk', permission: 'push' },
+ { team: 'go-sdk', permission: 'push' },
+ { team: 'java-sdk', permission: 'push' },
+ { team: 'kotlin-sdk', permission: 'push' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'php-sdk', permission: 'push' },
+ { team: 'python-sdk', permission: 'push' },
+ { team: 'python-sdk-auth', permission: 'push' },
+ { team: 'registry-wg', permission: 'push' },
+ { team: 'ruby-sdk', permission: 'push' },
+ { team: 'rust-sdk', permission: 'push' },
+ { team: 'sdk-maintainers', permission: 'push' },
+ { team: 'security-wg', permission: 'admin' },
+ { team: 'steering-committee', permission: 'push' },
+ { team: 'swift-sdk', permission: 'push' },
+ { team: 'transport-wg', permission: 'push' },
+ { team: 'typescript-sdk', permission: 'push' },
+ { team: 'typescript-sdk-auth', permission: 'push' },
+ ],
+ },
+ {
+ repository: 'modelcontextprotocol',
+ teams: [
+ { team: 'auth-maintainers', permission: 'push' },
+ { team: 'core-maintainers', permission: 'maintain' },
+ { team: 'csharp-sdk', permission: 'triage' },
+ { team: 'docs-maintainers', permission: 'push' },
+ { team: 'go-sdk', permission: 'triage' },
+ { team: 'ig-financial-services', permission: 'triage' },
+ { team: 'interest-groups', permission: 'triage' },
+ { team: 'java-sdk', permission: 'triage' },
+ { team: 'kotlin-sdk', permission: 'triage' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'php-sdk', permission: 'triage' },
+ { team: 'python-sdk', permission: 'triage' },
+ { team: 'python-sdk-auth', permission: 'triage' },
+ { team: 'registry-wg', permission: 'triage' },
+ { team: 'ruby-sdk', permission: 'triage' },
+ { team: 'rust-sdk', permission: 'triage' },
+ { team: 'sdk-maintainers', permission: 'triage' },
+ { team: 'security-wg', permission: 'admin' },
+ { team: 'steering-committee', permission: 'triage' },
+ { team: 'swift-sdk', permission: 'triage' },
+ { team: 'transport-wg', permission: 'triage' },
+ { team: 'typescript-sdk', permission: 'triage' },
+ { team: 'typescript-sdk-auth', permission: 'triage' },
+ { team: 'working-groups', permission: 'triage' },
+ ],
+ },
+ {
+ repository: 'quickstart-resources',
+ teams: [
+ { team: 'auth-maintainers', permission: 'push' },
+ { team: 'core-maintainers', permission: 'maintain' },
+ { team: 'csharp-sdk', permission: 'push' },
+ { team: 'docs-maintainers', permission: 'push' },
+ { team: 'go-sdk', permission: 'push' },
+ { team: 'ig-financial-services', permission: 'push' },
+ { team: 'interest-groups', permission: 'push' },
+ { team: 'java-sdk', permission: 'push' },
+ { team: 'kotlin-sdk', permission: 'push' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'php-sdk', permission: 'push' },
+ { team: 'python-sdk', permission: 'push' },
+ { team: 'python-sdk-auth', permission: 'push' },
+ { team: 'registry-wg', permission: 'push' },
+ { team: 'ruby-sdk', permission: 'push' },
+ { team: 'rust-sdk', permission: 'push' },
+ { team: 'sdk-maintainers', permission: 'push' },
+ { team: 'security-wg', permission: 'admin' },
+ { team: 'steering-committee', permission: 'push' },
+ { team: 'swift-sdk', permission: 'push' },
+ { team: 'transport-wg', permission: 'push' },
+ { team: 'typescript-sdk', permission: 'push' },
+ { team: 'typescript-sdk-auth', permission: 'push' },
+ { team: 'working-groups', permission: 'push' },
+ ],
+ },
+ {
+ repository: 'servers',
+ teams: [
+ { team: 'reference-servers-maintainers', permission: 'admin' },
+ { team: 'auth-maintainers', permission: 'push' },
+ { team: 'core-maintainers', permission: 'admin' },
+ { team: 'csharp-sdk', permission: 'push' },
+ { team: 'docs-maintainers', permission: 'push' },
+ { team: 'go-sdk', permission: 'push' },
+ { team: 'java-sdk', permission: 'push' },
+ { team: 'kotlin-sdk', permission: 'push' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'php-sdk', permission: 'push' },
+ { team: 'python-sdk', permission: 'push' },
+ { team: 'python-sdk-auth', permission: 'push' },
+ { team: 'registry-wg', permission: 'push' },
+ { team: 'ruby-sdk', permission: 'push' },
+ { team: 'rust-sdk', permission: 'push' },
+ { team: 'sdk-maintainers', permission: 'push' },
+ { team: 'security-wg', permission: 'admin' },
+ { team: 'steering-committee', permission: 'push' },
+ { team: 'swift-sdk', permission: 'push' },
+ { team: 'transport-wg', permission: 'push' },
+ { team: 'typescript-sdk', permission: 'push' },
+ { team: 'typescript-sdk-auth', permission: 'push' },
+ ],
+ },
+ {
+ repository: 'csharp-sdk',
+ teams: [
+ { team: 'csharp-sdk-admin', permission: 'admin' },
+ { team: 'csharp-sdk', permission: 'maintain' },
+ ],
+ users: [{ username: 'PederHP', permission: 'triage' }],
+ },
+ {
+ repository: 'go-sdk',
+ teams: [{ team: 'go-sdk', permission: 'admin' }],
+ },
+ {
+ repository: 'java-sdk',
+ teams: [{ team: 'java-sdk', permission: 'admin' }],
+ },
+ {
+ repository: 'kotlin-sdk',
+ teams: [{ team: 'kotlin-sdk', permission: 'admin' }],
+ },
+ {
+ repository: 'php-sdk',
+ teams: [{ team: 'php-sdk', permission: 'admin' }],
+ },
+ {
+ repository: 'python-sdk',
+ teams: [
+ { team: 'python-sdk', permission: 'admin' },
+ { team: 'python-sdk-auth', permission: 'admin' },
+ ],
+ users: [
+ { username: 'ddworken', permission: 'admin' },
+ { username: 'OctavianGuzu', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'ruby-sdk',
+ teams: [{ team: 'ruby-sdk', permission: 'admin' }],
+ },
+ {
+ repository: 'rust-sdk',
+ teams: [{ team: 'rust-sdk', permission: 'admin' }],
+ },
+ {
+ repository: 'swift-sdk',
+ teams: [{ team: 'swift-sdk', permission: 'admin' }],
+ },
+ {
+ repository: 'typescript-sdk',
+ teams: [
+ { team: 'typescript-sdk', permission: 'admin' },
+ { team: 'typescript-sdk-auth', permission: 'admin' },
+ { team: 'typescript-sdk-collaborators', permission: 'push' },
+ ],
+ users: [
+ { username: 'ddworken', permission: 'admin' },
+ { username: 'OctavianGuzu', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'create-python-server',
+ teams: [
+ { team: 'python-sdk', permission: 'admin' },
+ { team: 'python-sdk-auth', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'create-typescript-server',
+ teams: [
+ { team: 'typescript-sdk', permission: 'admin' },
+ { team: 'typescript-sdk-auth', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'registry',
+ teams: [
+ { team: 'registry-wg', permission: 'admin' },
+ { team: 'registry-collaborators', permission: 'push' },
+ ],
+ },
+ {
+ repository: 'static',
+ teams: [{ team: 'registry-wg', permission: 'push' }],
+ },
+ {
+ repository: 'financial-services-interest-group',
+ teams: [{ team: 'ig-financial-services', permission: 'admin' }],
+ users: [
+ { username: 'aniabot', permission: 'pull' },
+ { username: 'imfing', permission: 'triage' },
+ { username: 'KengoA', permission: 'triage' },
+ { username: 'nitsanh', permission: 'pull' },
+ ],
+ },
+ {
+ repository: 'ext-auth',
+ teams: [{ team: 'auth-maintainers', permission: 'admin' }],
+ },
+ {
+ repository: 'ext-apps',
+ teams: [
+ { team: 'core-maintainers', permission: 'push' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'mcp-apps-wg', permission: 'push' },
+ { team: 'mcp-apps-sdk', permission: 'admin' },
+ ],
+ users: [
+ { username: 'ststrong', permission: 'admin' },
+ { username: 'martinalong', permission: 'push' },
+ { username: 'conorkel', permission: 'admin' },
+ { username: 'alexi-openai', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'use-mcp',
+ teams: [
+ { team: 'core-maintainers', permission: 'push' },
+ { team: 'moderators', permission: 'maintain' },
+ ],
+ users: [{ username: 'geelen', permission: 'admin' }],
+ },
+ {
+ repository: 'example-remote-client',
+ teams: [
+ { team: 'core-maintainers', permission: 'push' },
+ { team: 'moderators', permission: 'maintain' },
+ ],
+ users: [
+ { username: 'geelen', permission: 'push' },
+ { username: 'markyfyi', permission: 'push' },
+ { username: 'jerryhong1', permission: 'push' },
+ ],
+ },
+ {
+ repository: 'example-remote-server',
+ teams: [
+ { team: 'core-maintainers', permission: 'push' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'mcp-apps-wg', permission: 'push' },
+ { team: 'mcp-apps-sdk', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'experimental-ext-grouping',
+ teams: [
+ { team: 'core-maintainers', permission: 'admin' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'primitive-grouping-ig', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'experimental-ext-skills',
+ teams: [
+ { team: 'core-maintainers', permission: 'admin' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'skills-over-mcp-ig', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'experimental-ext-tool-annotations',
+ teams: [
+ { team: 'core-maintainers', permission: 'admin' },
+ { team: 'moderators', permission: 'triage' },
+ { team: 'tool-annotations-ig', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'experimental-ext-triggers-events',
+ teams: [
+ { team: 'core-maintainers', permission: 'admin' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'triggers-events-wg', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'experimental-ext-interceptors',
+ teams: [
+ { team: 'core-maintainers', permission: 'admin' },
+ { team: 'moderators', permission: 'triage' },
+ { team: 'interceptors-wg', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'ext-tasks',
+ teams: [
+ { team: 'core-maintainers', permission: 'admin' },
+ { team: 'moderators', permission: 'maintain' },
+ { team: 'agents-wg', permission: 'admin' },
+ ],
+ },
+ {
+ repository: 'maintainer-docs',
+ teams: [
+ { team: 'lead-maintainers', permission: 'maintain' },
+ { team: 'core-maintainers', permission: 'admin' },
+ { team: 'steering-committee', permission: 'maintain' },
+ ],
+ users: [{ username: 'sambhav', permission: 'admin' }],
+ },
+ {
+ repository: 'community-moderators',
+ teams: [
+ { team: 'core-maintainers', permission: 'admin' },
+ { team: 'moderators', permission: 'maintain' },
+ ],
+ },
+ {
+ repository: 'access',
+ users: [
+ { username: 'felixweinberger', permission: 'admin' },
+ { username: 'maxisbey', permission: 'admin' },
+ ],
+ },
+];
+
+// GitHub Projects V2 permissions are NOT managed by Pulumi - no support yet
+// See: https://github.com/pulumi/pulumi-github/issues/1006
diff --git a/src/config/roleIds.ts b/src/config/roleIds.ts
new file mode 100644
index 0000000..d47968d
--- /dev/null
+++ b/src/config/roleIds.ts
@@ -0,0 +1,96 @@
+/**
+ * Role ID constants for type-safe role references.
+ * Using constants prevents typos and enables autocomplete.
+ */
+export const ROLE_IDS = {
+ // ===================
+ // Organization Structure
+ // ===================
+ STEERING_COMMITTEE: 'steering-committee',
+ CORE_MAINTAINERS: 'core-maintainers',
+ LEAD_MAINTAINERS: 'lead-maintainers',
+ MODERATORS: 'moderators',
+ ADMINISTRATORS: 'administrators', // Discord only
+ COMMUNITY_MANAGERS: 'community-managers', // Discord only
+
+ // ===================
+ // Maintainer Groups
+ // ===================
+ MAINTAINERS: 'maintainers',
+ DOCS_MAINTAINERS: 'docs-maintainers',
+ INSPECTOR_MAINTAINERS: 'inspector-maintainers',
+ MCPB_MAINTAINERS: 'mcpb-maintainers',
+ REFERENCE_SERVERS_MAINTAINERS: 'reference-servers-maintainers',
+ REGISTRY_MAINTAINERS: 'registry-maintainers',
+ REGISTRY_COLLABORATORS: 'registry-collaborators', // GitHub only
+ USE_MCP_MAINTAINERS: 'use-mcp-maintainers',
+
+ // ===================
+ // SDK Maintainers
+ // ===================
+ SDK_MAINTAINERS: 'sdk-maintainers',
+ CSHARP_SDK: 'csharp-sdk',
+ CSHARP_SDK_ADMIN: 'csharp-sdk-admin',
+ GO_SDK: 'go-sdk',
+ JAVA_SDK: 'java-sdk',
+ KOTLIN_SDK: 'kotlin-sdk',
+ MCP_APPS_SDK: 'mcp-apps-sdk',
+ PHP_SDK: 'php-sdk',
+ PYTHON_SDK: 'python-sdk',
+ PYTHON_SDK_AUTH: 'python-sdk-auth', // GitHub only (CODEOWNERS)
+ RUBY_SDK: 'ruby-sdk',
+ RUST_SDK: 'rust-sdk',
+ SWIFT_SDK: 'swift-sdk',
+ TYPESCRIPT_SDK: 'typescript-sdk',
+ TYPESCRIPT_SDK_AUTH: 'typescript-sdk-auth', // GitHub only (CODEOWNERS)
+ TYPESCRIPT_SDK_COLLABORATORS: 'typescript-sdk-collaborators', // GitHub only
+
+ // ===================
+ // Working Groups
+ // ===================
+ WORKING_GROUPS: 'working-groups',
+ AUTH_MAINTAINERS: 'auth-maintainers',
+ SECURITY_WG: 'security-wg',
+ SERVER_IDENTITY_WG: 'server-identity-wg',
+ TRANSPORT_WG: 'transport-wg',
+ TRIGGERS_EVENTS_WG: 'triggers-events-wg',
+ MCP_APPS_WG: 'mcp-apps-wg',
+ SERVER_CARD_WG: 'server-card-wg',
+ INTERCEPTORS_WG: 'interceptors-wg',
+ FILE_UPLOADS_WG: 'file-uploads-wg',
+ AGENTS_WG: 'agents-wg',
+
+ // ===================
+ // Interest Groups
+ // ===================
+ INTEREST_GROUPS: 'interest-groups',
+ AGENTS_IG: 'agents-ig',
+ AUTH_IG: 'auth-ig',
+ CLIENT_IMPLEMENTOR_IG: 'client-implementor-ig',
+ FINANCIAL_SERVICES_IG: 'financial-services-ig',
+ GATEWAYS_IG: 'gateways-ig',
+ PRIMITIVE_GROUPING_IG: 'primitive-grouping-ig',
+ SKILLS_OVER_MCP_IG: 'skills-over-mcp-ig',
+ TOOL_ANNOTATIONS_IG: 'tool-annotations-ig',
+
+ // ===================
+ // WG/IG Facilitators (Discord only)
+ // ===================
+ WG_IG_FACILITATORS: 'wg-ig-facilitators',
+
+ // ===================
+ // Email Groups (Google only)
+ // ===================
+ ANTITRUST: 'antitrust',
+ APPEALS: 'appeals',
+ CATCH_ALL: 'catch-all',
+} as const;
+
+export type RoleId = (typeof ROLE_IDS)[keyof typeof ROLE_IDS];
+
+/**
+ * Helper to check if a string is a valid RoleId at runtime.
+ */
+export function isValidRoleId(id: string): id is RoleId {
+ return Object.values(ROLE_IDS).includes(id as RoleId);
+}
diff --git a/src/config/roles.ts b/src/config/roles.ts
new file mode 100644
index 0000000..df8ce6c
--- /dev/null
+++ b/src/config/roles.ts
@@ -0,0 +1,433 @@
+import { ROLE_IDS, type RoleId } from './roleIds';
+
+/**
+ * GitHub team configuration
+ */
+export interface GitHubConfig {
+ /** Team name (usually matches role ID) */
+ team: string;
+ /** Parent team role ID */
+ parent?: RoleId;
+}
+
+/**
+ * Discord role configuration
+ */
+export interface DiscordConfig {
+ /** Display name in Discord (can have spaces) */
+ role: string;
+}
+
+/**
+ * Google Workspace group configuration
+ */
+export interface GoogleConfig {
+ /** Group name (used as prefix for @modelcontextprotocol.io email) */
+ group: string;
+ /** If true, accepts emails from anyone including external users */
+ isEmailGroup?: boolean;
+ /** If true, members of this role get a Google Workspace user account */
+ provisionUser?: boolean;
+}
+
+/**
+ * Role definition with platform-specific configurations.
+ * A role only exists on platforms where it has a config key.
+ */
+export interface Role {
+ id: RoleId;
+ description: string;
+ github?: GitHubConfig;
+ discord?: DiscordConfig;
+ google?: GoogleConfig;
+ /**
+ * Roles that are implied for Discord membership.
+ * If a user has this role, they automatically get the implied roles' Discord roles too.
+ * This is separate from GitHub parent relationships and allows Discord-specific hierarchy.
+ */
+ discordImplies?: readonly RoleId[];
+}
+
+/**
+ * All roles in the MCP organization.
+ * Each role specifies which platforms it exists on via presence of config keys.
+ */
+export const ROLES: readonly Role[] = [
+ // ===================
+ // Organization Structure
+ // ===================
+ {
+ id: ROLE_IDS.STEERING_COMMITTEE,
+ description: 'MCP Steering Committee',
+ github: { team: 'steering-committee' },
+ // No discord - this is a GitHub-only organizational container
+ },
+ {
+ id: ROLE_IDS.ADMINISTRATORS,
+ description: 'Discord server administrators',
+ discord: { role: 'administrators (synced)' },
+ // Discord only - no GitHub equivalent
+ },
+ {
+ id: ROLE_IDS.COMMUNITY_MANAGERS,
+ description: 'Discord community managers',
+ discord: { role: 'community managers (synced)' },
+ // Discord only - no GitHub equivalent
+ },
+ {
+ id: ROLE_IDS.LEAD_MAINTAINERS,
+ description: 'Lead core maintainers',
+ github: { team: 'lead-maintainers', parent: ROLE_IDS.STEERING_COMMITTEE },
+ discord: { role: 'lead maintainers (synced)' },
+ google: { group: 'lead-maintainers', provisionUser: true },
+ },
+ {
+ id: ROLE_IDS.CORE_MAINTAINERS,
+ description: 'Core maintainers',
+ github: { team: 'core-maintainers', parent: ROLE_IDS.STEERING_COMMITTEE },
+ discord: { role: 'core maintainers (synced)' },
+ google: { group: 'core-maintainers', provisionUser: true },
+ },
+ {
+ id: ROLE_IDS.MODERATORS,
+ description: 'Community moderators',
+ github: { team: 'moderators', parent: ROLE_IDS.STEERING_COMMITTEE },
+ discord: { role: 'community moderators (synced)' },
+ google: { group: 'moderators', provisionUser: true },
+ },
+
+ // ===================
+ // Maintainer Groups
+ // ===================
+ {
+ id: ROLE_IDS.MAINTAINERS,
+ description: 'General maintainers',
+ discord: { role: 'maintainers (synced)' },
+ // GWS user accounts are opt-in: maintainers add firstName/lastName/googleEmailPrefix
+ // to their entry in users.ts via PR to get an @modelcontextprotocol.io account
+ google: { group: 'maintainers', provisionUser: true },
+ },
+ {
+ id: ROLE_IDS.DOCS_MAINTAINERS,
+ description: 'MCP docs maintainers',
+ github: { team: 'docs-maintainers', parent: ROLE_IDS.STEERING_COMMITTEE },
+ // No discord role for docs maintainers
+ },
+ {
+ id: ROLE_IDS.INSPECTOR_MAINTAINERS,
+ description: 'MCP Inspector maintainers',
+ github: { team: 'inspector-maintainers', parent: ROLE_IDS.STEERING_COMMITTEE },
+ discord: { role: 'inspector maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.MCPB_MAINTAINERS,
+ description: 'MCPB (Model Context Protocol Bundle) maintainers',
+ github: { team: 'mcpb-maintainers', parent: ROLE_IDS.STEERING_COMMITTEE },
+ // No discord role
+ },
+ {
+ id: ROLE_IDS.REFERENCE_SERVERS_MAINTAINERS,
+ description: 'Reference servers maintainers',
+ github: { team: 'reference-servers-maintainers' },
+ discord: { role: 'reference servers maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.REGISTRY_MAINTAINERS,
+ description: 'Official registry builders and maintainers',
+ github: { team: 'registry-wg', parent: ROLE_IDS.WORKING_GROUPS },
+ discord: { role: 'registry maintainers (synced)' },
+ google: { group: 'registry-wg', provisionUser: true },
+ },
+ {
+ id: ROLE_IDS.REGISTRY_COLLABORATORS,
+ description: 'Registry working group collaborators',
+ github: { team: 'registry-collaborators', parent: ROLE_IDS.REGISTRY_MAINTAINERS },
+ },
+ {
+ id: ROLE_IDS.USE_MCP_MAINTAINERS,
+ description: 'use-mcp maintainers',
+ discord: { role: 'use-mcp maintainers (synced)' },
+ // Discord only
+ },
+
+ // ===================
+ // SDK Maintainers
+ // ===================
+ {
+ id: ROLE_IDS.SDK_MAINTAINERS,
+ description: 'Authors and maintainers of official MCP SDKs',
+ github: { team: 'sdk-maintainers', parent: ROLE_IDS.STEERING_COMMITTEE },
+ discord: { role: 'sdk maintainers (synced)' },
+ discordImplies: [ROLE_IDS.MAINTAINERS], // SDK maintainers are also general maintainers
+ },
+ {
+ id: ROLE_IDS.CSHARP_SDK,
+ description: 'Official C# SDK maintainers',
+ github: { team: 'csharp-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'c# sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.CSHARP_SDK_ADMIN,
+ description: 'C# SDK repository admins',
+ github: { team: 'csharp-sdk-admin', parent: ROLE_IDS.CSHARP_SDK },
+ // GitHub only - for repo admin access
+ },
+ {
+ id: ROLE_IDS.GO_SDK,
+ description: 'The Go SDK Team',
+ github: { team: 'go-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'go sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.JAVA_SDK,
+ description: 'Official Java SDK maintainers',
+ github: { team: 'java-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'java sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.KOTLIN_SDK,
+ description: 'Official Kotlin SDK maintainers',
+ github: { team: 'kotlin-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'kotlin sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.MCP_APPS_SDK,
+ description: 'Official MCP Apps SDK maintainers',
+ github: { team: 'mcp-apps-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ // No Discord channel/role yet: #mcp-apps-sdk-dev in the future
+ },
+ {
+ id: ROLE_IDS.PHP_SDK,
+ description: 'Official PHP SDK maintainers',
+ github: { team: 'php-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'php sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.PYTHON_SDK,
+ description: 'Official Python SDK maintainers',
+ github: { team: 'python-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'python sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.PYTHON_SDK_AUTH,
+ description: 'Python SDK auth code owners',
+ github: { team: 'python-sdk-auth', parent: ROLE_IDS.PYTHON_SDK },
+ // GitHub only - for CODEOWNERS
+ },
+ {
+ id: ROLE_IDS.RUBY_SDK,
+ description: 'Official Ruby SDK maintainers',
+ github: { team: 'ruby-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'ruby sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.RUST_SDK,
+ description: 'Official Rust SDK maintainers',
+ github: { team: 'rust-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'rust sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.SWIFT_SDK,
+ description: 'Official Swift SDK maintainers',
+ github: { team: 'swift-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'swift sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.TYPESCRIPT_SDK,
+ description: 'Official TypeScript SDK',
+ github: { team: 'typescript-sdk', parent: ROLE_IDS.SDK_MAINTAINERS },
+ discord: { role: 'typescript sdk maintainers (synced)' },
+ },
+ {
+ id: ROLE_IDS.TYPESCRIPT_SDK_AUTH,
+ description: 'Code owners for auth in Typescript SDK',
+ github: { team: 'typescript-sdk-auth', parent: ROLE_IDS.TYPESCRIPT_SDK },
+ // GitHub only - for CODEOWNERS
+ },
+ {
+ id: ROLE_IDS.TYPESCRIPT_SDK_COLLABORATORS,
+ description: 'TypeScript SDK collaborators',
+ github: { team: 'typescript-sdk-collaborators', parent: ROLE_IDS.TYPESCRIPT_SDK },
+ // GitHub only
+ },
+
+ // ===================
+ // Working Groups
+ // ===================
+ {
+ id: ROLE_IDS.WORKING_GROUPS,
+ description: 'MCP Working Groups',
+ github: { team: 'working-groups', parent: ROLE_IDS.STEERING_COMMITTEE },
+ // No discord - organizational container
+ },
+ {
+ id: ROLE_IDS.AUTH_MAINTAINERS,
+ description: 'Auth Maintainers',
+ github: { team: 'auth-maintainers', parent: ROLE_IDS.WORKING_GROUPS },
+ // See AUTH_IG for Discord role
+ },
+ {
+ id: ROLE_IDS.SECURITY_WG,
+ description: 'Security Working Group',
+ github: { team: 'security-wg', parent: ROLE_IDS.WORKING_GROUPS },
+ // See interest group for Discord role
+ },
+ {
+ id: ROLE_IDS.SERVER_IDENTITY_WG,
+ description: 'Server Identity Working Group',
+ discord: { role: 'server identity working group (synced)' },
+ // Discord only for now
+ },
+ {
+ id: ROLE_IDS.TRANSPORT_WG,
+ description: 'Transport Working Group',
+ github: { team: 'transport-wg', parent: ROLE_IDS.WORKING_GROUPS },
+ discord: { role: 'transports working group (synced)' },
+ },
+ {
+ id: ROLE_IDS.TRIGGERS_EVENTS_WG,
+ description: 'Triggers & Events Working Group',
+ github: { team: 'triggers-events-wg', parent: ROLE_IDS.WORKING_GROUPS },
+ discord: { role: 'triggers & events working group (synced)' },
+ },
+ {
+ id: ROLE_IDS.MCP_APPS_WG,
+ description: 'MCP Apps Working Group',
+ github: { team: 'mcp-apps-wg', parent: ROLE_IDS.WORKING_GROUPS },
+ discord: { role: 'mcp apps working group (synced)' },
+ },
+ {
+ id: ROLE_IDS.SERVER_CARD_WG,
+ description: 'Server Card Working Group',
+ github: { team: 'server-card-wg', parent: ROLE_IDS.WORKING_GROUPS },
+ discord: { role: 'server card working group (synced)' },
+ },
+ {
+ id: ROLE_IDS.INTERCEPTORS_WG,
+ description: 'Interceptors Working Group',
+ github: { team: 'interceptors-wg', parent: ROLE_IDS.WORKING_GROUPS },
+ discord: { role: 'interceptors working group (synced)' },
+ },
+ {
+ id: ROLE_IDS.FILE_UPLOADS_WG,
+ description: 'File Uploads Working Group',
+ github: { team: 'file-uploads-wg', parent: ROLE_IDS.WORKING_GROUPS },
+ discord: { role: 'file uploads working group (synced)' },
+ },
+ {
+ id: ROLE_IDS.AGENTS_WG,
+ description: 'Agents Working Group',
+ github: { team: 'agents-wg', parent: ROLE_IDS.WORKING_GROUPS },
+ },
+
+ // ===================
+ // Interest Groups
+ // ===================
+ {
+ id: ROLE_IDS.INTEREST_GROUPS,
+ description: 'Interest Groups',
+ github: { team: 'interest-groups', parent: ROLE_IDS.STEERING_COMMITTEE },
+ // No discord - organizational container
+ },
+ {
+ id: ROLE_IDS.AGENTS_IG,
+ description: 'Agents Interest Group',
+ discord: { role: 'agents interest group (synced)' },
+ // Discord only
+ },
+ {
+ id: ROLE_IDS.AUTH_IG,
+ description: 'Auth Interest Group',
+ discord: { role: 'auth interest group (synced)' },
+ // Discord only - separate from AUTH_MAINTAINERS which is GitHub
+ },
+ {
+ id: ROLE_IDS.CLIENT_IMPLEMENTOR_IG,
+ description: 'Client Implementor Interest Group',
+ discord: { role: 'client implementor interest group (synced)' },
+ // Discord only
+ },
+ {
+ id: ROLE_IDS.FINANCIAL_SERVICES_IG,
+ description: 'Financial Services Interest Group',
+ github: { team: 'ig-financial-services', parent: ROLE_IDS.INTEREST_GROUPS },
+ discord: { role: 'financial services interest group (synced)' },
+ },
+ {
+ id: ROLE_IDS.GATEWAYS_IG,
+ description: 'Gateways Interest Group',
+ // No GitHub role yet
+ discord: { role: 'gateways interest group (synced)' },
+ },
+ {
+ id: ROLE_IDS.PRIMITIVE_GROUPING_IG,
+ description: 'Primitive Grouping Interest Group',
+ github: { team: 'primitive-grouping-ig', parent: ROLE_IDS.INTEREST_GROUPS },
+ discord: { role: 'primitive grouping interest group (synced)' },
+ },
+ {
+ id: ROLE_IDS.SKILLS_OVER_MCP_IG,
+ description: 'Skills Over MCP Interest Group',
+ github: { team: 'skills-over-mcp-ig', parent: ROLE_IDS.INTEREST_GROUPS },
+ discord: { role: 'skills over mcp interest group (synced)' },
+ },
+ {
+ id: ROLE_IDS.TOOL_ANNOTATIONS_IG,
+ description: 'Tool Annotations Interest Group',
+ github: { team: 'tool-annotations-ig', parent: ROLE_IDS.INTEREST_GROUPS },
+ discord: { role: 'tool annotations interest group (synced)' },
+ },
+
+ // ===================
+ // WG/IG Facilitators (Discord only)
+ // ===================
+ {
+ id: ROLE_IDS.WG_IG_FACILITATORS,
+ description: 'Working Group and Interest Group facilitators with calendar access',
+ discord: { role: 'wg/ig facilitators (synced)' },
+ // Discord only - grants meet.modelcontextprotocol.io calendar access
+ },
+
+ // ===================
+ // Email Groups (Google only)
+ // ===================
+ {
+ id: ROLE_IDS.ANTITRUST,
+ description: 'Antitrust compliance contacts',
+ google: { group: 'antitrust', isEmailGroup: true },
+ // Google only
+ },
+ {
+ id: ROLE_IDS.APPEALS,
+ description: 'Code of Conduct ban appeals inbox',
+ google: { group: 'appeals', isEmailGroup: true },
+ // Google only
+ },
+ {
+ id: ROLE_IDS.CATCH_ALL,
+ description: 'Catch-all email group',
+ google: { group: 'catch-all', isEmailGroup: true },
+ // Google only
+ },
+] as const;
+
+/**
+ * Get a role by ID
+ */
+export function getRole(id: RoleId): Role | undefined {
+ return ROLES.find((r) => r.id === id);
+}
+
+/**
+ * Get all roles that exist on a specific platform
+ */
+export function getRolesForPlatform(platform: 'github' | 'discord' | 'google'): Role[] {
+ return ROLES.filter((r) => r[platform] !== undefined);
+}
+
+/**
+ * Build a lookup map of roles by ID
+ */
+export function buildRoleLookup(): Map {
+ return new Map(ROLES.map((r) => [r.id, r]));
+}
diff --git a/src/config/users.ts b/src/config/users.ts
index 7eb78c4..7d7970e 100644
--- a/src/config/users.ts
+++ b/src/config/users.ts
@@ -1,25 +1,828 @@
import type { Member } from './utils';
+import { ROLE_IDS } from './roleIds';
export const MEMBERS: readonly Member[] = [
+ {
+ github: '000-000-000-000-000',
+ discord: '1360717264051241071',
+ firstName: 'Nick',
+ lastName: 'Aldridge',
+ googleEmailPrefix: 'nick',
+ memberOf: [ROLE_IDS.CORE_MAINTAINERS],
+ },
+ {
+ github: 'a-akimov',
+ discord: '1365254196621738116',
+ memberOf: [ROLE_IDS.DOCS_MAINTAINERS],
+ },
+ {
+ github: 'aaronpk',
+ discord: '324624369428987905',
+ memberOf: [ROLE_IDS.AUTH_MAINTAINERS, ROLE_IDS.MAINTAINERS],
+ },
+ {
+ github: 'alexhancock',
+ discord: '1325885093343924316',
+ memberOf: [ROLE_IDS.RUST_SDK],
+ },
+ {
+ github: 'an-dustin',
+ memberOf: [ROLE_IDS.SECURITY_WG],
+ },
+ {
+ github: 'antonpk1',
+ discord: '738474760480227358',
+ memberOf: [ROLE_IDS.MCP_APPS_SDK],
+ },
+ {
+ github: 'asklar',
+ discord: '633837375734153216',
+ memberOf: [ROLE_IDS.MCPB_MAINTAINERS],
+ },
+ {
+ github: 'atesgoral',
+ discord: '201179934775836672',
+ memberOf: [ROLE_IDS.RUBY_SDK],
+ },
+ {
+ github: 'baxen',
+ discord: '360224027769307136',
+ memberOf: [ROLE_IDS.RUST_SDK],
+ },
+ {
+ github: 'bhosmer-ant',
+ discord: '1272295077074567242',
+ memberOf: [
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.PYTHON_SDK,
+ ROLE_IDS.TRANSPORT_WG,
+ ROLE_IDS.TYPESCRIPT_SDK,
+ ],
+ },
+ {
+ github: 'BobDickinson',
+ email: 'bob.dickinson@gmail.com',
+ discord: '1175893001202045139',
+ skipGoogleUserProvisioning: true,
+ memberOf: [
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.INSPECTOR_MAINTAINERS,
+ ROLE_IDS.REGISTRY_MAINTAINERS,
+ ROLE_IDS.SKILLS_OVER_MCP_IG,
+ ],
+ },
+ {
+ github: 'bolinfest',
+ memberOf: [ROLE_IDS.RUST_SDK],
+ },
+ {
+ github: 'caitiem20',
+ email: 'caitie.mccaffrey@microsoft.com',
+ discord: '1425586366288494722',
+ firstName: 'Caitie',
+ lastName: 'McCaffrey',
+ googleEmailPrefix: 'caitie',
+ memberOf: [ROLE_IDS.CORE_MAINTAINERS, ROLE_IDS.TRANSPORT_WG, ROLE_IDS.AGENTS_WG],
+ },
+ {
+ github: 'caseychow-oai',
+ memberOf: [ROLE_IDS.FILE_UPLOADS_WG],
+ },
+ {
+ github: 'chemicL',
+ discord: '1346243721271971923',
+ memberOf: [ROLE_IDS.JAVA_SDK],
+ },
+ {
+ github: 'chr-hertel',
+ email: 'mail@christopher-hertel.de',
+ discord: '633566986827464704',
+ memberOf: [ROLE_IDS.PHP_SDK],
+ },
+ {
+ github: 'chughtapan',
+ email: 'chugh.tapan@gmail.com',
+ discord: '941245973357793340',
+ memberOf: [
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.INTEREST_GROUPS,
+ ROLE_IDS.PRIMITIVE_GROUPING_IG,
+ ROLE_IDS.WG_IG_FACILITATORS,
+ ],
+ },
+ {
+ github: 'clareliguori',
+ email: 'liguori@amazon.com',
+ discord: '1109135863843143700',
+ firstName: 'Clare',
+ lastName: 'Liguori',
+ googleEmailPrefix: 'clare',
+ memberOf: [ROLE_IDS.CORE_MAINTAINERS, ROLE_IDS.TRIGGERS_EVENTS_WG],
+ },
+ {
+ github: 'cliffhall',
+ email: 'cliff@futurescale.com',
+ discord: '501498061965754380',
+ firstName: 'Cliff',
+ lastName: 'Hall',
+ googleEmailPrefix: 'cliff',
+ existingGWSUser: true,
+ memberOf: [
+ ROLE_IDS.COMMUNITY_MANAGERS,
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.INSPECTOR_MAINTAINERS,
+ ROLE_IDS.PRIMITIVE_GROUPING_IG,
+ ROLE_IDS.REFERENCE_SERVERS_MAINTAINERS,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.SKILLS_OVER_MCP_IG,
+ ROLE_IDS.WORKING_GROUPS,
+ ROLE_IDS.APPEALS,
+ ],
+ },
+ {
+ github: 'CodeWithKyrian',
+ discord: '951883230250946633',
+ memberOf: [ROLE_IDS.PHP_SDK],
+ },
+ {
+ github: 'crondinini-ant',
+ memberOf: [],
+ },
+ {
+ github: 'D-McAdams',
+ discord: '1364696680980545697',
+ memberOf: [ROLE_IDS.AUTH_MAINTAINERS],
+ },
+ {
+ github: 'daleseo',
+ discord: '267646459187298305',
+ memberOf: [ROLE_IDS.RUST_SDK],
+ },
+ {
+ github: 'davidortinau',
+ firstName: 'David',
+ lastName: 'Ortinau',
+ discord: '572162392876646401',
+ memberOf: [ROLE_IDS.CSHARP_SDK, ROLE_IDS.CSHARP_SDK_ADMIN],
+ },
+ {
+ github: 'degiorgio',
+ email: 'degiorgiokurt@outlook.com',
+ firstName: 'Kurt',
+ lastName: 'Degiorgio',
+ discord: '602175181133316105',
+ memberOf: [ROLE_IDS.INTERCEPTORS_WG],
+ },
+ {
+ github: 'dend',
+ skipGoogleUserProvisioning: true,
+ memberOf: [
+ ROLE_IDS.AUTH_MAINTAINERS,
+ ROLE_IDS.CORE_MAINTAINERS,
+ ROLE_IDS.LEAD_MAINTAINERS,
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.CSHARP_SDK_ADMIN,
+ ROLE_IDS.ADMINISTRATORS,
+ ROLE_IDS.GO_SDK,
+ ROLE_IDS.FINANCIAL_SERVICES_IG,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.PHP_SDK,
+ ROLE_IDS.PYTHON_SDK,
+ ROLE_IDS.SECURITY_WG,
+ ROLE_IDS.TRANSPORT_WG,
+ ROLE_IDS.TYPESCRIPT_SDK,
+ ],
+ },
+ {
+ github: 'devcrocod',
+ memberOf: [ROLE_IDS.KOTLIN_SDK],
+ },
{
github: 'domdomegg',
email: 'adam@modelcontextprotocol.io',
- memberOf: ['test-child'],
+ discord: '102128241715716096',
+ firstName: 'Adam',
+ lastName: 'Jones',
+ googleEmailPrefix: 'adam',
+ existingGWSUser: true,
+ memberOf: [ROLE_IDS.MCPB_MAINTAINERS],
+ },
+ {
+ github: 'dsp',
+ skipGoogleUserProvisioning: true,
+ memberOf: [
+ ROLE_IDS.AUTH_MAINTAINERS,
+ ROLE_IDS.LEAD_MAINTAINERS,
+ ROLE_IDS.CORE_MAINTAINERS,
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.GO_SDK,
+ ROLE_IDS.FINANCIAL_SERVICES_IG,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.PHP_SDK,
+ ROLE_IDS.PYTHON_SDK,
+ ROLE_IDS.SECURITY_WG,
+ ROLE_IDS.TRANSPORT_WG,
+ ROLE_IDS.TYPESCRIPT_SDK,
+ ],
+ },
+ {
+ github: 'dsp-ant',
+ email: 'david@modelcontextprotocol.io',
+ discord: '166107790262272000',
+ firstName: 'David',
+ lastName: 'Soria Parra',
+ googleEmailPrefix: 'david',
+ existingGWSUser: true,
+ memberOf: [
+ ROLE_IDS.AUTH_MAINTAINERS,
+ ROLE_IDS.LEAD_MAINTAINERS,
+ ROLE_IDS.CORE_MAINTAINERS,
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.SERVER_CARD_WG,
+ ROLE_IDS.AGENTS_WG,
+ ROLE_IDS.APPEALS,
+ ],
+ },
+ {
+ github: 'e5l',
+ memberOf: [ROLE_IDS.KOTLIN_SDK],
+ },
+ {
+ github: 'eiriktsarpalis',
+ memberOf: [ROLE_IDS.CSHARP_SDK],
+ },
+ {
+ github: 'EmLauber',
+ discord: '1408222390361657426',
+ memberOf: [ROLE_IDS.WG_IG_FACILITATORS],
+ },
+ {
+ github: 'erain',
+ discord: '797226095874539539',
+ memberOf: [ROLE_IDS.SKILLS_OVER_MCP_IG],
+ },
+ {
+ github: 'ericstj',
+ memberOf: [ROLE_IDS.CSHARP_SDK],
+ },
+ {
+ github: 'evalstate',
+ discord: '779268016121577492',
+ firstName: 'Shaun',
+ lastName: 'Smith',
+ googleEmailPrefix: 'shaun.smith',
+ memberOf: [
+ ROLE_IDS.COMMUNITY_MANAGERS,
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.TRANSPORT_WG,
+ ROLE_IDS.APPEALS,
+ ],
+ },
+ {
+ github: 'fabpot',
+ memberOf: [ROLE_IDS.PHP_SDK],
+ },
+ {
+ github: 'felixrieseberg',
+ memberOf: [ROLE_IDS.MCPB_MAINTAINERS],
+ },
+ {
+ github: 'felixweinberger',
+ discord: '1377138523492057212',
+ firstName: 'Felix',
+ lastName: 'Weinberger',
+ googleEmailPrefix: 'felix',
+ memberOf: [
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.PYTHON_SDK,
+ ROLE_IDS.SECURITY_WG,
+ ROLE_IDS.TYPESCRIPT_SDK,
+ ],
+ },
+ {
+ github: 'findleyr',
+ discord: '776094836796424213',
+ memberOf: [ROLE_IDS.GO_SDK],
+ },
+ {
+ github: 'guglielmo-san',
+ discord: '1432786987072622613',
+ memberOf: [ROLE_IDS.GO_SDK],
+ },
+ {
+ github: 'halter73',
+ discord: '340718902096953344',
+ memberOf: [ROLE_IDS.CSHARP_SDK, ROLE_IDS.CSHARP_SDK_ADMIN],
+ },
+ {
+ github: 'herczyn',
+ discord: '1001427188068917279',
+ memberOf: [ROLE_IDS.GO_SDK],
+ },
+ {
+ github: 'idosal',
+ discord: '593070927202484244',
+ memberOf: [ROLE_IDS.WORKING_GROUPS, ROLE_IDS.MCP_APPS_WG, ROLE_IDS.MCP_APPS_SDK],
+ },
+ {
+ github: 'ignatov',
+ memberOf: [ROLE_IDS.KOTLIN_SDK],
+ },
+ {
+ github: 'ihrpr',
+ memberOf: [ROLE_IDS.DOCS_MAINTAINERS, ROLE_IDS.PYTHON_SDK, ROLE_IDS.TYPESCRIPT_SDK],
+ },
+ {
+ github: 'jamadeo',
+ memberOf: [ROLE_IDS.RUST_SDK],
+ },
+ {
+ github: 'JAORMX',
+ discord: '1185152774674055193',
+ memberOf: [ROLE_IDS.SKILLS_OVER_MCP_IG],
+ },
+ {
+ github: 'jba',
+ discord: '773276903364755518',
+ memberOf: [ROLE_IDS.GO_SDK],
+ },
+ {
+ github: 'jeffhandley',
+ memberOf: [ROLE_IDS.CSHARP_SDK, ROLE_IDS.CSHARP_SDK_ADMIN],
+ },
+ {
+ github: 'jenn-newton',
+ memberOf: [ROLE_IDS.SECURITY_WG],
+ },
+ {
+ github: 'jeongukjae',
+ discord: '334348926658412564',
+ memberOf: [ROLE_IDS.INTERCEPTORS_WG],
+ },
+ {
+ github: 'joan-anthropic',
+ discord: '1398403578892128437',
+ memberOf: [ROLE_IDS.MCPB_MAINTAINERS],
+ },
+ {
+ github: 'jokemanfire',
+ memberOf: [ROLE_IDS.RUST_SDK],
+ },
+ {
+ github: 'jonathanhefner',
+ discord: '1301960963087663186',
+ memberOf: [
+ ROLE_IDS.COMMUNITY_MANAGERS,
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.RUBY_SDK,
+ ROLE_IDS.MCP_APPS_SDK,
+ ROLE_IDS.TRANSPORT_WG,
+ ROLE_IDS.APPEALS,
+ ],
+ },
+ {
+ github: 'jozkee',
+ memberOf: [ROLE_IDS.CSHARP_SDK],
+ },
+ {
+ github: 'jspahrsummers',
+ email: 'justin@modelcontextprotocol.io',
+ firstName: 'Justin',
+ lastName: 'Spahr-Summers',
+ googleEmailPrefix: 'justin',
+ existingGWSUser: true,
+ memberOf: [ROLE_IDS.LEAD_MAINTAINERS, ROLE_IDS.CORE_MAINTAINERS],
+ },
+ {
+ github: 'kaxil',
+ discord: '757355088946921474',
+ memberOf: [ROLE_IDS.SKILLS_OVER_MCP_IG],
+ },
+ {
+ github: 'Kehrlann',
+ discord: '1112624611901837373',
+ memberOf: [ROLE_IDS.JAVA_SDK],
+ },
+ {
+ github: 'keithagroves',
+ discord: '321019863260987392',
+ memberOf: [ROLE_IDS.SKILLS_OVER_MCP_IG],
+ },
+ {
+ github: 'KKonstantinov',
+ discord: '390932438903422987',
+ memberOf: [ROLE_IDS.INSPECTOR_MAINTAINERS, ROLE_IDS.MAINTAINERS, ROLE_IDS.TYPESCRIPT_SDK],
+ firstName: 'Konstantin',
+ lastName: 'Konstantinov',
+ googleEmailPrefix: 'konstantin',
+ },
+ {
+ github: 'Kludex',
+ discord: '247021664624312322',
+ memberOf: [ROLE_IDS.PYTHON_SDK],
+ },
+ {
+ github: 'koic',
+ discord: '880937364208361483',
+ memberOf: [ROLE_IDS.RUBY_SDK],
+ },
+ {
+ github: 'kurtisvg',
+ discord: '1158458388917780590',
+ firstName: 'Kurtis',
+ lastName: 'Van Gent',
+ googleEmailPrefix: 'kvg',
+ memberOf: [ROLE_IDS.CORE_MAINTAINERS, ROLE_IDS.TRANSPORT_WG],
+ },
+ {
+ github: 'liady',
+ discord: '383565833768665088',
+ memberOf: [ROLE_IDS.WORKING_GROUPS, ROLE_IDS.MCP_APPS_WG, ROLE_IDS.MCP_APPS_SDK],
+ },
+ {
+ github: 'localden',
+ discord: '1351224014143754260',
+ firstName: 'Den',
+ lastName: 'Delimarsky',
+ googleEmailPrefix: 'den',
+ existingGWSUser: true,
+ memberOf: [
+ ROLE_IDS.AUTH_MAINTAINERS,
+ ROLE_IDS.CORE_MAINTAINERS,
+ ROLE_IDS.LEAD_MAINTAINERS,
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.CSHARP_SDK_ADMIN,
+ ROLE_IDS.ADMINISTRATORS,
+ ROLE_IDS.FILE_UPLOADS_WG,
+ ROLE_IDS.GO_SDK,
+ ROLE_IDS.FINANCIAL_SERVICES_IG,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.PHP_SDK,
+ ROLE_IDS.PYTHON_SDK,
+ ROLE_IDS.SECURITY_WG,
+ ROLE_IDS.TRANSPORT_WG,
+ ROLE_IDS.TYPESCRIPT_SDK,
+ ROLE_IDS.APPEALS,
+ ],
+ },
+ {
+ github: 'LucaButBoring',
+ discord: '1366470072729866252',
+ firstName: 'Luca',
+ lastName: 'Chang',
+ googleEmailPrefix: 'luca',
+ memberOf: [
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.AGENTS_IG,
+ ROLE_IDS.AGENTS_WG,
+ ROLE_IDS.WORKING_GROUPS,
+ ],
+ },
+ {
+ github: 'maciej-kisiel',
+ discord: '936242781733654588',
+ memberOf: [ROLE_IDS.GO_SDK],
+ },
+ {
+ github: 'macoughl',
+ discord: '740279257548193803',
+ memberOf: [ROLE_IDS.COMMUNITY_MANAGERS],
+ },
+ {
+ github: 'markdroth',
+ firstName: 'Mark',
+ lastName: 'Roth',
+ memberOf: [ROLE_IDS.TRANSPORT_WG],
+ },
+ {
+ github: 'markpollack',
+ memberOf: [ROLE_IDS.JAVA_SDK],
+ },
+ {
+ github: 'marshallofsound',
+ memberOf: [ROLE_IDS.MCPB_MAINTAINERS],
+ },
+ {
+ github: 'mattzcarey',
+ discord: '224878268275359744',
+ memberOf: [ROLE_IDS.TYPESCRIPT_SDK, ROLE_IDS.TOOL_ANNOTATIONS_IG, ROLE_IDS.WG_IG_FACILITATORS],
+ },
+ {
+ github: 'maxisbey',
+ discord: '1404871241738748058',
+ firstName: 'Max',
+ lastName: 'Isbey',
+ googleEmailPrefix: 'max',
+ memberOf: [ROLE_IDS.MAINTAINERS, ROLE_IDS.PYTHON_SDK, ROLE_IDS.TYPESCRIPT_SDK_COLLABORATORS],
+ },
+ {
+ github: 'michaelneale',
+ memberOf: [ROLE_IDS.RUST_SDK],
+ },
+ {
+ github: 'mikekistler',
+ discord: '915345005982408754',
+ memberOf: [ROLE_IDS.CSHARP_SDK, ROLE_IDS.CSHARP_SDK_ADMIN, ROLE_IDS.TRANSPORT_WG],
+ },
+ {
+ github: 'movetz',
+ discord: '1427569183427919906',
+ memberOf: [ROLE_IDS.SWIFT_SDK],
+ },
+ {
+ github: 'nahapetyan-serob',
+ discord: '1505852630692401314',
+ memberOf: [ROLE_IDS.GO_SDK],
+ },
+ {
+ github: 'nbarbettini',
+ discord: '784552628930478090',
+ memberOf: [ROLE_IDS.WG_IG_FACILITATORS],
+ },
+ {
+ github: 'nickcoai',
+ discord: '1153783469860732968',
+ firstName: 'Nick',
+ lastName: 'Cooper',
+ googleEmailPrefix: 'nickc',
+ memberOf: [ROLE_IDS.CORE_MAINTAINERS, ROLE_IDS.FILE_UPLOADS_WG, ROLE_IDS.SERVER_IDENTITY_WG],
+ },
+ {
+ github: 'nicolas-grekas',
+ memberOf: [ROLE_IDS.PHP_SDK],
+ },
+ {
+ github: 'Nyholm',
+ discord: '466593085984342016',
+ memberOf: [ROLE_IDS.PHP_SDK],
+ },
+ {
+ github: 'ochafik',
+ discord: '1004897332069925024',
+ memberOf: [
+ ROLE_IDS.FILE_UPLOADS_WG,
+ ROLE_IDS.MCP_APPS_SDK,
+ ROLE_IDS.PYTHON_SDK,
+ ROLE_IDS.PYTHON_SDK_AUTH,
+ ROLE_IDS.TYPESCRIPT_SDK,
+ ROLE_IDS.TYPESCRIPT_SDK_AUTH,
+ ],
+ },
+ {
+ github: 'og-ant',
+ memberOf: [ROLE_IDS.SECURITY_WG],
+ },
+ {
+ github: 'olaservo',
+ discord: '1079841769946095620',
+ firstName: 'Ola',
+ lastName: 'Hungerford',
+ googleEmailPrefix: 'ola',
+ memberOf: [
+ ROLE_IDS.COMMUNITY_MANAGERS,
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.INSPECTOR_MAINTAINERS,
+ ROLE_IDS.INTERCEPTORS_WG,
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.REFERENCE_SERVERS_MAINTAINERS,
+ ROLE_IDS.SKILLS_OVER_MCP_IG,
+ ROLE_IDS.WORKING_GROUPS,
+ ROLE_IDS.APPEALS,
+ ],
+ },
+ {
+ github: 'Ololoshechkin',
+ memberOf: [ROLE_IDS.KOTLIN_SDK],
+ },
+ {
+ github: 'pcarleton',
+ discord: '1354465170969067852',
+ firstName: 'Paul',
+ lastName: 'Carleton',
+ googleEmailPrefix: 'paul',
+ existingGWSUser: true,
+ memberOf: [
+ ROLE_IDS.CORE_MAINTAINERS,
+ ROLE_IDS.DOCS_MAINTAINERS,
+ ROLE_IDS.ADMINISTRATORS,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.PYTHON_SDK,
+ ROLE_IDS.PYTHON_SDK_AUTH,
+ ROLE_IDS.TYPESCRIPT_SDK,
+ ROLE_IDS.TYPESCRIPT_SDK_AUTH,
+ ROLE_IDS.AUTH_MAINTAINERS,
+ ],
+ },
+ {
+ github: 'pederhp',
+ discord: '166255967665651713',
+ memberOf: [
+ ROLE_IDS.COMMUNITY_MANAGERS,
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.FINANCIAL_SERVICES_IG,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.SKILLS_OVER_MCP_IG,
+ ROLE_IDS.INTERCEPTORS_WG,
+ ROLE_IDS.APPEALS,
+ ],
+ },
+ {
+ github: 'petery-ant',
+ memberOf: [ROLE_IDS.SECURITY_WG],
+ },
+ {
+ github: 'pja-ant',
+ discord: '328628782497923072',
+ firstName: 'Peter',
+ lastName: 'Alexander',
+ googleEmailPrefix: 'pja',
+ existingGWSUser: true,
+ memberOf: [
+ ROLE_IDS.CORE_MAINTAINERS,
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.SKILLS_OVER_MCP_IG,
+ ROLE_IDS.TRANSPORT_WG,
+ ROLE_IDS.TRIGGERS_EVENTS_WG,
+ ROLE_IDS.AGENTS_WG,
+ ],
+ },
+ {
+ github: 'poteat',
+ memberOf: [ROLE_IDS.TYPESCRIPT_SDK_COLLABORATORS],
+ },
+ {
+ github: 'PranavSenthilnathan',
+ email: 'pranas@microsoft.com',
+ firstName: 'Pranav',
+ lastName: 'Senthilnathan',
+ memberOf: [ROLE_IDS.CSHARP_SDK],
+ },
+ {
+ github: 'pree-dew',
+ discord: '1379733751315173376',
+ firstName: 'Preeti',
+ lastName: 'Dewani',
+ memberOf: [ROLE_IDS.REGISTRY_COLLABORATORS],
+ },
+ {
+ github: 'pronskiy',
+ memberOf: [ROLE_IDS.PHP_SDK],
+ },
+ {
+ github: 'pwwpche',
+ discord: '1226238847013228604',
+ memberOf: [],
+ },
+ {
+ github: 'rdimitrov',
+ email: 'radoslav@modelcontextprotocol.io',
+ discord: '1088231882979815424',
+ firstName: 'Radoslav',
+ lastName: 'Dimitrov',
+ googleEmailPrefix: 'radoslav',
+ existingGWSUser: true,
+ memberOf: [ROLE_IDS.MAINTAINERS, ROLE_IDS.REGISTRY_MAINTAINERS, ROLE_IDS.SKILLS_OVER_MCP_IG],
+ },
+ {
+ github: 'rreichel3',
+ discord: '1458485333757788273',
+ memberOf: [ROLE_IDS.TOOL_ANNOTATIONS_IG, ROLE_IDS.WG_IG_FACILITATORS],
+ },
+ {
+ github: 'sambhav',
+ email: 'sambhavs.email@gmail.com',
+ firstName: 'Sambhav',
+ lastName: 'Kothari',
+ googleEmailPrefix: 'sambhav',
+ discord: '840109459212206090',
+ memberOf: [
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.FINANCIAL_SERVICES_IG,
+ ROLE_IDS.INTERCEPTORS_WG,
+ ROLE_IDS.SKILLS_OVER_MCP_IG,
+ ],
+ },
+ {
+ github: 'SamMorrowDrums',
+ email: 'sammorrowdrums@github.com',
+ discord: '782948163694493696',
+ firstName: 'Sam',
+ lastName: 'Morrow',
+ googleEmailPrefix: 'sam',
+ memberOf: [
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.PRIMITIVE_GROUPING_IG,
+ ROLE_IDS.SERVER_CARD_WG,
+ ROLE_IDS.SKILLS_OVER_MCP_IG,
+ ROLE_IDS.TOOL_ANNOTATIONS_IG,
+ ROLE_IDS.WG_IG_FACILITATORS,
+ ],
+ },
+ {
+ github: 'sdubov',
+ memberOf: [ROLE_IDS.KOTLIN_SDK],
+ },
+ {
+ github: 'soyuka',
+ email: 'soyuka@gmail.com',
+ discord: '249323948842418186',
+ memberOf: [ROLE_IDS.PHP_SDK],
+ },
+ {
+ github: 'stallent',
+ discord: '1137898074086314136',
+ memberOf: [ROLE_IDS.SWIFT_SDK],
+ },
+ {
+ github: 'stephentoub',
+ memberOf: [ROLE_IDS.CSHARP_SDK, ROLE_IDS.CSHARP_SDK_ADMIN],
+ },
+ {
+ github: 'sunishsheth2009',
+ discord: '1414713222224941097',
+ memberOf: [ROLE_IDS.SKILLS_OVER_MCP_IG],
+ },
+ {
+ github: 'tadasant',
+ email: 'tadas@modelcontextprotocol.io',
+ discord: '400092503677599754',
+ firstName: 'Tadas',
+ lastName: 'Antanavicius',
+ googleEmailPrefix: 'tadas',
+ existingGWSUser: true,
+ memberOf: [
+ ROLE_IDS.COMMUNITY_MANAGERS,
+ ROLE_IDS.MODERATORS,
+ ROLE_IDS.MAINTAINERS,
+ ROLE_IDS.WORKING_GROUPS,
+ ROLE_IDS.INTEREST_GROUPS,
+ ROLE_IDS.REGISTRY_MAINTAINERS,
+ ROLE_IDS.ADMINISTRATORS,
+ ROLE_IDS.SERVER_CARD_WG,
+ ROLE_IDS.APPEALS,
+ ],
+ },
+ {
+ github: 'tarekgh',
+ memberOf: [ROLE_IDS.CSHARP_SDK],
+ },
+ {
+ github: 'tiginamaria',
+ memberOf: [ROLE_IDS.KOTLIN_SDK],
+ },
+ {
+ github: 'tobinsouth',
+ discord: '865072069779521556',
+ memberOf: [ROLE_IDS.REFERENCE_SERVERS_MAINTAINERS],
+ },
+ {
+ github: 'toby',
+ email: 'toby@modelcontextprotocol.io',
+ discord: '560155411777323048',
+ firstName: 'Toby',
+ lastName: 'Padilla',
+ googleEmailPrefix: 'toby',
+ existingGWSUser: true,
+ // Emeritus maintainer of the Registry
+ memberOf: [],
+ },
+ {
+ github: 'topherbullock',
+ discord: '1059910719124013168',
+ memberOf: [ROLE_IDS.RUBY_SDK],
+ },
+ {
+ github: 'tzolov',
+ discord: '1097924660055777290',
+ memberOf: [ROLE_IDS.DOCS_MAINTAINERS, ROLE_IDS.JAVA_SDK],
+ },
+ {
+ github: 'yarolegovich',
+ discord: '393296640141950977',
+ memberOf: [ROLE_IDS.GO_SDK],
},
{
email: 'adamj@anthropic.com',
- memberOf: ['catch-all'],
+ memberOf: [ROLE_IDS.CATCH_ALL],
},
{
email: 'davidsp@anthropic.com',
- memberOf: ['antitrust'],
+ memberOf: [ROLE_IDS.ANTITRUST],
},
{
email: 'mattsamuels@anthropic.com',
- memberOf: ['antitrust'],
+ memberOf: [ROLE_IDS.ANTITRUST],
},
{
email: 'davideramian@anthropic.com',
- memberOf: ['antitrust'],
+ memberOf: [ROLE_IDS.ANTITRUST],
},
-] as const;
\ No newline at end of file
+] as const;
diff --git a/src/config/utils.ts b/src/config/utils.ts
index 241b86f..6c84daf 100644
--- a/src/config/utils.ts
+++ b/src/config/utils.ts
@@ -1,43 +1,81 @@
-import type { GROUPS } from './groups';
+import type { RoleId } from './roleIds';
+import type { Role } from './roles';
-function isValidGroupName(name: string): boolean {
- return /^[a-z][a-z0-9-]*[a-z]$/.test(name);
+/**
+ * A member of the MCP organization.
+ * Members are assigned to roles via memberOf, and the role definitions
+ * determine which platforms (GitHub, Discord, Google) they get access to.
+ */
+export interface Member {
+ /** GitHub username */
+ github?: string;
+ /** Email address (for Google Workspace) */
+ email?: string;
+ /** Discord user ID (snowflake) */
+ discord?: string;
+ /** Roles this member belongs to */
+ memberOf: readonly RoleId[];
+ /** First name (required for Google Workspace user provisioning) */
+ firstName?: string;
+ /** Last name (required for Google Workspace user provisioning) */
+ lastName?: string;
+ /** Google Workspace email prefix (e.g., 'david' -> david@modelcontextprotocol.io) */
+ googleEmailPrefix?: string;
+ /** If true, this user already exists in Google Workspace and should be imported into Pulumi state */
+ existingGWSUser?: boolean;
+ /** Explicitly skip automatic GWS user provisioning for provisionUser roles */
+ skipGoogleUserProvisioning?: boolean;
}
-export type Platform = 'github' | 'google';
-
-export function defineGroups<
- const T extends readonly {
- name: Lowercase;
- description: string;
- memberOf?: readonly (T[number]['name'])[];
- isEmailGroup?: boolean;
- onlyOnPlatforms?: readonly Platform[];
- }[]
->(groups: T) {
- for (const group of groups) {
- if (!isValidGroupName(group.name)) {
- throw new Error(
- `Invalid group name: ${group.name}. Must be lowercase alphanumeric with dashes, starting with a letter.`
- );
+/**
+ * Sort roles by GitHub parent dependency (topological sort).
+ * Ensures parent teams are created before child teams.
+ *
+ * This is necessary because when creating GitHub teams, we need the parent
+ * team's ID. If we process roles in arbitrary order, a child team might be
+ * processed before its parent, resulting in undefined parentTeamId.
+ */
+export function sortRolesByGitHubDependency(
+ roles: readonly Role[],
+ roleLookup: Map
+): Role[] {
+ const result: Role[] = [];
+ const visited = new Set();
+
+ function visit(role: Role): void {
+ if (visited.has(role.id)) return;
+
+ // Only process roles with GitHub config
+ if (!role.github) {
+ visited.add(role.id);
+ return;
}
- }
- return groups;
-}
+ // Visit parent first if it exists and has GitHub config
+ if (role.github.parent) {
+ const parentRole = roleLookup.get(role.github.parent);
+ if (parentRole) {
+ visit(parentRole);
+ }
+ }
+
+ visited.add(role.id);
+ result.push(role);
+ }
-export type GroupKey = (typeof GROUPS)[number]['name'];
+ for (const role of roles) {
+ visit(role);
+ }
-export interface Group {
- name: GroupKey;
- description: string;
- memberOf?: readonly GroupKey[];
- isEmailGroup?: boolean;
- onlyOnPlatforms?: readonly Platform[];
+ return result;
}
-export interface Member {
- github?: string;
- email?: string;
- memberOf: readonly GroupKey[];
-}
\ No newline at end of file
+// Re-export for convenience
+export { ROLE_IDS, type RoleId } from './roleIds';
+export {
+ ROLES,
+ type Role,
+ type GitHubConfig,
+ type DiscordConfig,
+ type GoogleConfig,
+} from './roles';
diff --git a/src/discord.ts b/src/discord.ts
new file mode 100644
index 0000000..25b2018
--- /dev/null
+++ b/src/discord.ts
@@ -0,0 +1,551 @@
+import * as pulumi from '@pulumi/pulumi';
+import { ROLES, type Role, buildRoleLookup } from './config/roles';
+import { MEMBERS } from './config/users';
+import type { RoleId } from './config/roleIds';
+
+const config = new pulumi.Config('discord');
+// Discord integration is optional - only enabled if botToken and guildId are configured
+const DISCORD_BOT_TOKEN = config.getSecret('botToken');
+const DISCORD_GUILD_ID = config.get('guildId');
+const DISCORD_ENABLED = DISCORD_BOT_TOKEN !== undefined && DISCORD_GUILD_ID !== undefined;
+
+if (!DISCORD_ENABLED) {
+ pulumi.log.info('Discord integration disabled: botToken or guildId not configured');
+}
+
+const DISCORD_API_BASE = 'https://discord.com/api/v10';
+
+interface DiscordApiError {
+ code: number;
+ message: string;
+}
+
+interface DiscordRateLimitResponse {
+ message: string;
+ retry_after: number;
+ global: boolean;
+}
+
+function sleep(ms: number): Promise {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
+// Cloudflare 5xx and edge-level 429s return plain-text bodies ("upstream connect
+// error...", "error code: 1015") that crash a naive response.json().
+function tryParseJson(text: string): T | undefined {
+ try {
+ return JSON.parse(text) as T;
+ } catch {
+ return undefined;
+ }
+}
+
+async function discordFetch(
+ token: string,
+ endpoint: string,
+ options: RequestInit = {},
+ maxRetries = 10
+): Promise {
+ let lastError: Error | undefined;
+
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
+ const response = await fetch(`${DISCORD_API_BASE}${endpoint}`, {
+ ...options,
+ headers: {
+ Authorization: `Bot ${token}`,
+ 'Content-Type': 'application/json',
+ ...options.headers,
+ },
+ });
+
+ if (response.status === 429) {
+ const text = await response.text();
+ const body = tryParseJson(text);
+ const retryAfterSec = body?.retry_after ?? 1;
+ // Linearly increasing jitter de-syncs the thundering herd when many
+ // resources refresh in parallel and all receive the same retry_after.
+ const jitterMs = Math.random() * 1000 * (attempt + 1);
+ const retryAfterMs = Math.ceil(retryAfterSec * 1000) + jitterMs;
+ lastError = new Error(
+ `Discord API rate limited on ${endpoint} (retry_after=${retryAfterSec}s, global=${body?.global ?? false})`
+ );
+ if (attempt < maxRetries) {
+ await sleep(retryAfterMs);
+ continue;
+ }
+ throw lastError;
+ }
+
+ if (response.status >= 500 && response.status < 600) {
+ const text = await response.text();
+ lastError = new Error(`Discord API ${response.status} on ${endpoint}: ${text.slice(0, 200)}`);
+ if (attempt < maxRetries) {
+ await sleep(2 ** attempt * 500 + Math.random() * 1000);
+ continue;
+ }
+ throw lastError;
+ }
+
+ if (!response.ok) {
+ const text = await response.text();
+ const error = tryParseJson(text);
+ throw new Error(
+ error
+ ? `Discord API error: ${error.message} (code: ${error.code})`
+ : `Discord API ${response.status} on ${endpoint}: ${text.slice(0, 200)}`
+ );
+ }
+
+ // Handle 204 No Content
+ if (response.status === 204) {
+ return undefined as T;
+ }
+
+ return response.json() as Promise;
+ }
+
+ throw (
+ lastError ?? new Error(`Discord API request to ${endpoint} failed after ${maxRetries} retries`)
+ );
+}
+
+// Discord API response types
+interface DiscordRoleApiResponse {
+ id: string;
+ name: string;
+ position: number;
+ permissions: string;
+ managed: boolean;
+}
+
+interface DiscordGuildMemberApiResponse {
+ roles: string[];
+}
+
+// Discord Role Dynamic Provider
+interface DiscordRoleInputs {
+ guildId: string;
+ roleName: string;
+ token: string;
+}
+
+interface DiscordRoleOutputs extends DiscordRoleInputs {
+ roleId: string;
+}
+
+const discordRoleProvider: pulumi.dynamic.ResourceProvider = {
+ async create(
+ inputs: DiscordRoleInputs
+ ): Promise> {
+ const role = await discordFetch(
+ inputs.token,
+ `/guilds/${inputs.guildId}/roles`,
+ {
+ method: 'POST',
+ body: JSON.stringify({
+ name: inputs.roleName,
+ permissions: '0', // No special permissions - roles are for organization only
+ mentionable: false,
+ hoist: false,
+ }),
+ }
+ );
+
+ return {
+ id: role.id,
+ outs: {
+ ...inputs,
+ roleId: role.id,
+ },
+ };
+ },
+
+ async read(
+ id: string,
+ props: DiscordRoleOutputs
+ ): Promise> {
+ try {
+ const roles = await discordFetch(
+ props.token,
+ `/guilds/${props.guildId}/roles`
+ );
+
+ const role = roles.find((r) => r.id === id);
+ if (!role) {
+ // Role was deleted externally
+ throw new Error(`Role ${id} not found`);
+ }
+
+ return {
+ id,
+ props: {
+ ...props,
+ roleName: role.name,
+ roleId: role.id,
+ },
+ };
+ } catch (error) {
+ throw new Error(`Failed to read role ${id}: ${error}`);
+ }
+ },
+
+ async update(
+ id: string,
+ _olds: DiscordRoleOutputs,
+ news: DiscordRoleInputs
+ ): Promise> {
+ await discordFetch(news.token, `/guilds/${news.guildId}/roles/${id}`, {
+ method: 'PATCH',
+ body: JSON.stringify({
+ name: news.roleName,
+ }),
+ });
+
+ return {
+ outs: {
+ ...news,
+ roleId: id,
+ },
+ };
+ },
+
+ async delete(id: string, props: DiscordRoleOutputs): Promise {
+ try {
+ await discordFetch(props.token, `/guilds/${props.guildId}/roles/${id}`, {
+ method: 'DELETE',
+ });
+ } catch (error) {
+ // Ignore errors if role is already deleted
+ console.warn(`Failed to delete role ${id}: ${error}`);
+ }
+ },
+};
+
+class DiscordRole extends pulumi.dynamic.Resource {
+ public readonly roleId!: pulumi.Output;
+ public readonly roleName!: pulumi.Output;
+ public readonly guildId!: pulumi.Output;
+
+ constructor(
+ name: string,
+ args: {
+ guildId: pulumi.Input;
+ roleName: pulumi.Input;
+ token: pulumi.Input;
+ },
+ opts?: pulumi.CustomResourceOptions
+ ) {
+ super(
+ discordRoleProvider,
+ name,
+ {
+ roleId: undefined,
+ ...args,
+ },
+ opts
+ );
+ }
+}
+
+// Discord Member Role Sync Dynamic Provider
+// This provider reconciles a user's roles to match exactly what's defined in config
+// It adds missing roles AND removes extra roles (only for roles we manage)
+interface DiscordMemberRoleSyncInputs {
+ guildId: string;
+ userId: string;
+ /** Role IDs that this user SHOULD have (managed roles only) */
+ expectedRoleIds: string[];
+ /** All role IDs that we manage (to know which ones to potentially remove) */
+ managedRoleIds: string[];
+ token: string;
+}
+
+interface DiscordMemberRoleSyncOutputs extends DiscordMemberRoleSyncInputs {
+ /** Roles that were added during last sync */
+ addedRoles: string[];
+ /** Roles that were removed during last sync */
+ removedRoles: string[];
+ /** True if the member was not found on the Discord server */
+ memberNotFound: boolean;
+}
+
+async function syncMemberRoles(
+ inputs: DiscordMemberRoleSyncInputs
+): Promise<{ addedRoles: string[]; removedRoles: string[]; memberNotFound: boolean }> {
+ // Get the user's current roles
+ let member: DiscordGuildMemberApiResponse;
+ try {
+ member = await discordFetch(
+ inputs.token,
+ `/guilds/${inputs.guildId}/members/${inputs.userId}`
+ );
+ } catch (error) {
+ // If the member isn't on the server, skip gracefully
+ if (error instanceof Error && error.message.includes('code: 10007')) {
+ console.warn(
+ `Discord member ${inputs.userId} not found on server - skipping role sync. ` +
+ `They may have left the server or the Discord ID may be incorrect.`
+ );
+ return { addedRoles: [], removedRoles: [], memberNotFound: true };
+ }
+ throw error;
+ }
+
+ const currentRoles = new Set(member.roles);
+ const expectedRoles = new Set(inputs.expectedRoleIds);
+ const managedRoles = new Set(inputs.managedRoleIds);
+
+ const addedRoles: string[] = [];
+ const removedRoles: string[] = [];
+
+ // Add missing roles
+ for (const roleId of Array.from(expectedRoles)) {
+ if (!currentRoles.has(roleId)) {
+ await discordFetch(
+ inputs.token,
+ `/guilds/${inputs.guildId}/members/${inputs.userId}/roles/${roleId}`,
+ { method: 'PUT' }
+ );
+ addedRoles.push(roleId);
+ }
+ }
+
+ // Remove roles that the user has but shouldn't (only managed roles)
+ for (const roleId of Array.from(currentRoles)) {
+ if (managedRoles.has(roleId) && !expectedRoles.has(roleId)) {
+ await discordFetch(
+ inputs.token,
+ `/guilds/${inputs.guildId}/members/${inputs.userId}/roles/${roleId}`,
+ { method: 'DELETE' }
+ );
+ removedRoles.push(roleId);
+ }
+ }
+
+ return { addedRoles, removedRoles, memberNotFound: false };
+}
+
+const discordMemberRoleSyncProvider: pulumi.dynamic.ResourceProvider = {
+ async create(
+ inputs: DiscordMemberRoleSyncInputs
+ ): Promise> {
+ const { addedRoles, removedRoles, memberNotFound } = await syncMemberRoles(inputs);
+
+ return {
+ id: inputs.userId,
+ outs: {
+ ...inputs,
+ addedRoles,
+ removedRoles,
+ memberNotFound,
+ },
+ };
+ },
+
+ async read(
+ id: string,
+ props: DiscordMemberRoleSyncOutputs
+ ): Promise> {
+ let member: DiscordGuildMemberApiResponse;
+ try {
+ member = await discordFetch(
+ props.token,
+ `/guilds/${props.guildId}/members/${props.userId}`
+ );
+ } catch (error) {
+ // If the member isn't on the server, return state indicating they're not found
+ if (error instanceof Error && error.message.includes('code: 10007')) {
+ return {
+ id,
+ props: {
+ ...props,
+ addedRoles: [],
+ removedRoles: [],
+ memberNotFound: true,
+ },
+ };
+ }
+ throw new Error(`Failed to read member roles for ${id}: ${error}`);
+ }
+
+ const currentRoles = new Set(member.roles);
+ const expectedRoles = new Set(props.expectedRoleIds);
+ const managedRoles = new Set(props.managedRoleIds);
+
+ // Check if roles are in sync (only considering managed roles)
+ const outOfSync =
+ Array.from(expectedRoles).some((r) => !currentRoles.has(r)) ||
+ Array.from(currentRoles).some((r) => managedRoles.has(r) && !expectedRoles.has(r));
+
+ if (outOfSync) {
+ // Self-heal: apply the expected roles now. Without this, refresh would
+ // only observe drift, and since inputs are unchanged Pulumi would never
+ // trigger update() — leaving members who joined after create() stuck.
+ const { addedRoles, removedRoles, memberNotFound } = await syncMemberRoles(props);
+ return {
+ id,
+ props: {
+ ...props,
+ addedRoles,
+ removedRoles,
+ memberNotFound,
+ },
+ };
+ }
+
+ return { id, props: { ...props, memberNotFound: false } };
+ },
+
+ async update(
+ id: string,
+ _olds: DiscordMemberRoleSyncOutputs,
+ news: DiscordMemberRoleSyncInputs
+ ): Promise> {
+ const { addedRoles, removedRoles, memberNotFound } = await syncMemberRoles(news);
+
+ return {
+ outs: {
+ ...news,
+ addedRoles,
+ removedRoles,
+ memberNotFound,
+ },
+ };
+ },
+
+ async delete(id: string, props: DiscordMemberRoleSyncOutputs): Promise {
+ // When a user is removed from config, remove all their managed roles
+ for (const roleId of props.expectedRoleIds) {
+ try {
+ await discordFetch(
+ props.token,
+ `/guilds/${props.guildId}/members/${props.userId}/roles/${roleId}`,
+ { method: 'DELETE' }
+ );
+ } catch (error) {
+ console.warn(`Failed to remove role ${roleId} from user ${id}: ${error}`);
+ }
+ }
+ },
+};
+
+class DiscordMemberRoleSync extends pulumi.dynamic.Resource {
+ public readonly addedRoles!: pulumi.Output;
+ public readonly removedRoles!: pulumi.Output;
+ public readonly memberNotFound!: pulumi.Output;
+
+ constructor(
+ name: string,
+ args: {
+ guildId: pulumi.Input;
+ userId: pulumi.Input;
+ expectedRoleIds: pulumi.Input[]>;
+ managedRoleIds: pulumi.Input[]>;
+ token: pulumi.Input;
+ },
+ opts?: pulumi.CustomResourceOptions
+ ) {
+ super(
+ discordMemberRoleSyncProvider,
+ name,
+ {
+ addedRoles: undefined,
+ removedRoles: undefined,
+ memberNotFound: undefined,
+ ...args,
+ },
+ opts
+ );
+ }
+}
+
+const roleLookup = buildRoleLookup();
+// Discord roles keyed by Discord role name
+const roles: Record = {};
+
+/**
+ * Expand a set of role IDs to include all implied Discord roles.
+ * This traverses:
+ * 1. GitHub parent relationships (e.g., GO_SDK -> SDK_MAINTAINERS)
+ * 2. discordImplies relationships (e.g., SDK_MAINTAINERS -> MAINTAINERS)
+ */
+function expandDiscordRoles(roleIds: readonly RoleId[]): Set {
+ const expanded = new Set();
+ const toProcess = [...roleIds];
+
+ while (toProcess.length > 0) {
+ const roleId = toProcess.pop()!;
+ if (expanded.has(roleId)) continue;
+ expanded.add(roleId);
+
+ const role = roleLookup.get(roleId);
+ if (!role) continue;
+
+ // Follow GitHub parent relationship
+ if (role.github?.parent) {
+ toProcess.push(role.github.parent);
+ }
+
+ // Follow discordImplies relationships
+ if (role.discordImplies) {
+ toProcess.push(...role.discordImplies);
+ }
+ }
+
+ return expanded;
+}
+
+// Only create Discord resources if Discord is enabled
+if (DISCORD_ENABLED) {
+ // These are guaranteed to be defined when DISCORD_ENABLED is true
+ const guildId = DISCORD_GUILD_ID!;
+ const botToken = DISCORD_BOT_TOKEN!;
+
+ // Create Discord roles for roles that have Discord config
+ ROLES.forEach((role: Role) => {
+ if (!role.discord) return;
+
+ roles[role.discord.role] = new DiscordRole(`discord-role-${role.id}`, {
+ guildId,
+ roleName: role.discord.role,
+ token: botToken,
+ });
+ });
+
+ // Collect all managed role IDs (roles that have Discord config)
+ const allManagedRoleIds = ROLES.filter((r) => r.discord).map(
+ (r) => roles[r.discord!.role].roleId
+ );
+
+ // Sync roles for each member
+ MEMBERS.forEach((member) => {
+ if (!member.discord) return;
+
+ // Expand roles to include parents and implied roles
+ const expandedRoleIds = expandDiscordRoles(member.memberOf);
+
+ // Get the Discord role IDs this member should have
+ const expectedRoleIds = Array.from(expandedRoleIds)
+ .map((roleId: RoleId) => {
+ const role = roleLookup.get(roleId);
+ if (!role?.discord) return null;
+ return roles[role.discord.role].roleId;
+ })
+ .filter((id): id is pulumi.Output => id !== null);
+
+ // Create a sync resource for this member
+ new DiscordMemberRoleSync(
+ `discord-member-sync-${member.discord}`,
+ {
+ guildId,
+ userId: member.discord!,
+ expectedRoleIds,
+ managedRoleIds: allManagedRoleIds,
+ token: botToken,
+ },
+ { dependsOn: Object.values(roles) }
+ );
+ });
+}
+
+export { roles as discordRoles };
diff --git a/src/github.ts b/src/github.ts
index 6ec40be..7076caa 100644
--- a/src/github.ts
+++ b/src/github.ts
@@ -1,30 +1,104 @@
+import * as pulumi from '@pulumi/pulumi';
import * as github from '@pulumi/github';
-import { GROUPS } from './config/groups';
-import type { Group } from './config/utils';
+import { ROLES, type Role, buildRoleLookup } from './config/roles';
+import { REPOSITORY_ACCESS } from './config/repoAccess';
+import { ORG_ROLE_ASSIGNMENTS } from './config/orgRoles';
+import { ORG_SETTINGS } from './config/orgSettings';
import { MEMBERS } from './config/users';
+import { sortRolesByGitHubDependency } from './config/utils';
+import type { RoleId } from './config/roleIds';
+const config = new pulumi.Config();
+
+// The provider's Create for this resource is a PATCH on the existing org, so
+// no import is needed; first apply writes the values below directly.
+new github.OrganizationSettings(
+ 'org-settings',
+ {
+ ...ORG_SETTINGS,
+ billingEmail: config.requireSecret('githubBillingEmail'),
+ },
+ { additionalSecretOutputs: ['billingEmail'] }
+);
+
+const roleLookup = buildRoleLookup();
+// Teams keyed by GitHub team name (matches repoAccess.ts references)
const teams: Record = {};
-GROUPS.forEach((group: Group) => {
- // Skip groups that don't include github in their platforms
- if (group.onlyOnPlatforms && !group.onlyOnPlatforms.includes('github')) return;
+// Sort roles so parent teams are created before child teams
+const sortedRoles = sortRolesByGitHubDependency(ROLES, roleLookup);
+
+// Create GitHub teams for roles that have GitHub config
+sortedRoles.forEach((role: Role) => {
+ if (!role.github) return;
+
+ // Resolve parent team ID if specified
+ // Parent is guaranteed to exist in `teams` due to topological sort
+ let parentTeamId: github.Team['id'] | undefined;
+ if (role.github.parent) {
+ const parentRole = roleLookup.get(role.github.parent);
+ if (parentRole?.github) {
+ parentTeamId = teams[parentRole.github.team]?.id;
+ }
+ }
- teams[group.name] = new github.Team(group.name, {
- name: group.name,
- description: group.description + ' \n(Managed by github.com/modelcontextprotocol/access)',
+ teams[role.github.team] = new github.Team(role.github.team, {
+ name: role.github.team,
+ description: role.description + ' \n(Managed by github.com/modelcontextprotocol/access)',
privacy: 'closed',
- parentTeamId: group.memberOf?.[0] ? teams[group.memberOf[0]].id : undefined,
+ parentTeamId,
});
});
+// Create team memberships
MEMBERS.forEach((member) => {
if (!member.github) return;
- member.memberOf.forEach((teamKey) => {
- new github.TeamMembership(`${member.github}-${teamKey}`, {
- teamId: teams[teamKey].id,
+ member.memberOf.forEach((roleId: RoleId) => {
+ const role = roleLookup.get(roleId);
+ if (!role?.github) return; // Role doesn't have GitHub config
+
+ new github.TeamMembership(`${member.github}-${role.github.team}`, {
+ teamId: teams[role.github.team].id,
username: member.github!,
role: 'member',
});
});
});
+
+// Assign organization-level roles to teams (grants access across all repos)
+const orgRoles = github.getOrganizationRolesOutput();
+ORG_ROLE_ASSIGNMENTS.forEach((assignment) => {
+ const team = teams[assignment.team];
+ if (!team) {
+ throw new Error(
+ `orgRoles.ts references team '${assignment.team}' which is not managed in roles.ts`
+ );
+ }
+ const roleId = orgRoles.roles.apply((roles) => {
+ const match = roles.find((r) => r.name === assignment.role);
+ if (!match) throw new Error(`Organization role '${assignment.role}' not found`);
+ return match.roleId;
+ });
+ new github.OrganizationRoleTeam(`orgrole-${assignment.team}-${assignment.role}`, {
+ teamSlug: team.slug,
+ roleId,
+ });
+});
+
+// Configure repository access
+REPOSITORY_ACCESS.forEach((repo) => {
+ new github.RepositoryCollaborators(`repo-${repo.repository}`, {
+ repository: repo.repository,
+ teams: repo.teams?.map((t) => ({
+ teamId: teams[t.team]?.id,
+ permission: t.permission,
+ })),
+ users: repo.users?.map((u) => ({
+ username: u.username,
+ permission: u.permission,
+ })),
+ });
+});
+
+export { teams as githubTeams };
diff --git a/src/google.ts b/src/google.ts
index e257ff1..78e8a5b 100644
--- a/src/google.ts
+++ b/src/google.ts
@@ -1,63 +1,183 @@
+import * as crypto from 'crypto';
+import * as pulumi from '@pulumi/pulumi';
import * as gworkspace from '@pulumi/googleworkspace';
-import { GROUPS } from './config/groups';
-import type { Group } from './config/utils';
+import * as random from '@pulumi/random';
+import { ROLES, type Role, buildRoleLookup } from './config/roles';
import { MEMBERS } from './config/users';
+import type { RoleId } from './config/roleIds';
+const roleLookup = buildRoleLookup();
+// Groups keyed by Google group name
const groups: Record = {};
-GROUPS.forEach((group: Group) => {
- // Skip groups that don't include google in their platforms
- if (group.onlyOnPlatforms && !group.onlyOnPlatforms.includes('google')) return;
+// Create Google groups for roles that have Google config
+ROLES.forEach((role: Role) => {
+ if (!role.google) return;
- groups[group.name] = new gworkspace.Group(group.name, {
- email: `${group.name}@modelcontextprotocol.io`,
- name: group.name,
- description: group.description + ' \n(Managed by github.com/modelcontextprotocol/access)',
+ groups[role.google.group] = new gworkspace.Group(role.google.group, {
+ email: `${role.google.group}@modelcontextprotocol.io`,
+ name: role.google.group,
+ description: role.description + ' \n(Managed by github.com/modelcontextprotocol/access)',
});
- new gworkspace.GroupSettings(group.name, {
- email: groups[group.name].email,
-
- // Maximise visibility of group. It's visible in GitHub anyway
- whoCanViewMembership: 'ALL_IN_DOMAIN_CAN_VIEW',
-
- // This specifies who can add/remove members. We want this to only be via this IaC.
- whoCanModerateMembers: 'NONE',
- whoCanLeaveGroup: 'NONE_CAN_LEAVE',
- whoCanJoin: 'INVITED_CAN_JOIN',
-
- // Email groups allow anyone (including externals) to post
- // Non-email groups are not intended as mailing lists, so use the most restrictive settings
- // whoCanViewGroup is badly named, but actually means 'Permissions to view group messages'. See https://developers.google.com/workspace/admin/groups-settings/v1/reference/groups
- ...(group.isEmailGroup ? {
- whoCanPostMessage: 'ANYONE_CAN_POST',
- whoCanContactOwner: 'ALL_OWNERS_CAN_CONTACT',
- whoCanViewGroup: 'ALL_MEMBERS_CAN_VIEW',
- } : {
- whoCanPostMessage: 'ALL_OWNERS_CAN_POST',
- whoCanContactOwner: 'ALL_OWNERS_CAN_CONTACT',
- whoCanViewGroup: 'ALL_OWNERS_CAN_VIEW',
- }),
+ new gworkspace.GroupSettings(
+ role.google.group,
+ {
+ email: groups[role.google.group].email,
+ // Maximise visibility of group. It's visible in GitHub anyway
+ whoCanViewMembership: 'ALL_IN_DOMAIN_CAN_VIEW',
+
+ // This specifies who can add/remove members. We want this to only be via this IaC.
+ whoCanModerateMembers: 'NONE',
+ whoCanLeaveGroup: 'NONE_CAN_LEAVE',
+ whoCanJoin: 'INVITED_CAN_JOIN',
+
+ // Email groups allow anyone (including externals) to post
+ // Non-email groups are not intended as mailing lists, so use the most restrictive settings
+ // whoCanViewGroup is badly named, but actually means 'Permissions to view group messages'. See https://developers.google.com/workspace/admin/groups-settings/v1/reference/groups
+ ...(role.google.isEmailGroup
+ ? {
+ whoCanPostMessage: 'ANYONE_CAN_POST',
+ whoCanContactOwner: 'ALL_OWNERS_CAN_CONTACT',
+ whoCanViewGroup: 'ALL_MEMBERS_CAN_VIEW',
+ }
+ : {
+ whoCanPostMessage: 'ALL_OWNERS_CAN_POST',
+ whoCanContactOwner: 'ALL_OWNERS_CAN_CONTACT',
+ whoCanViewGroup: 'ALL_OWNERS_CAN_VIEW',
+ }),
+ },
+ { ignoreChanges: ['isArchived'] }
+ );
+});
+
+// Create the organizational unit for MCP users
+const mcpOrgUnit = new gworkspace.OrgUnit(
+ 'mcp-org-unit',
+ {
+ name: 'Model Context Protocol',
+ description: 'Model Context Protocol',
+ parentOrgUnitPath: '/',
+ },
+ { ignoreChanges: ['description'] }
+);
+
+// Provision Google Workspace user accounts for members in roles with provisionUser
+const provisionedUsersByEmail: Record = {};
+const newUserPasswords: Record> = {};
+
+MEMBERS.forEach((member) => {
+ if (
+ !member.firstName ||
+ !member.lastName ||
+ !member.googleEmailPrefix ||
+ member.skipGoogleUserProvisioning
+ )
+ return;
+
+ const needsUser = member.memberOf.some((roleId: RoleId) => {
+ const role = roleLookup.get(roleId);
+ return role?.google?.provisionUser === true;
});
+ if (!needsUser) return;
- group.memberOf?.forEach((parentGroupKey) => {
- new gworkspace.GroupMember(`${group.name}-in-${parentGroupKey}`, {
- groupId: groups[parentGroupKey].id,
- email: groups[group.name].email,
- role: 'MEMBER',
+ const primaryEmail = `${member.googleEmailPrefix}@modelcontextprotocol.io`;
+
+ if (member.existingGWSUser) {
+ // Existing GWS users are not managed by Pulumi — the GWS provider's import
+ // validation rejects empty email types that GWS itself sets on primary/alias
+ // emails, and there's no way to fix this at the provider level.
+ // Group memberships for these users are created without dependsOn since the
+ // user already exists in GWS.
+ return;
+ } else {
+ // Create new user with random password
+ const password = new random.RandomPassword(`gws-pwd-${member.googleEmailPrefix}`, {
+ length: 24,
+ special: true,
});
- });
+ const hashedPassword = password.result.apply((plaintext: string) =>
+ crypto.createHash('sha1').update(plaintext).digest('hex')
+ );
+
+ const user = new gworkspace.User(
+ `gws-user-${member.googleEmailPrefix}`,
+ {
+ primaryEmail,
+ name: { familyName: member.lastName!, givenName: member.firstName! },
+ password: hashedPassword,
+ hashFunction: 'SHA-1',
+ changePasswordAtNextLogin: true,
+ orgUnitPath: mcpOrgUnit.orgUnitPath,
+ },
+ {
+ dependsOn: [mcpOrgUnit],
+ ignoreChanges: [
+ 'recoveryEmail',
+ 'recoveryPhone',
+ 'password',
+ 'hashFunction',
+ 'changePasswordAtNextLogin',
+ 'orgUnitPath',
+ 'archived',
+ 'suspended',
+ 'isAdmin',
+ 'includeInGlobalAddressList',
+ 'ipAllowlist',
+ 'addresses',
+ 'aliases',
+ 'customSchemas',
+ 'emails',
+ 'externalIds',
+ 'ims',
+ 'keywords',
+ 'languages',
+ 'locations',
+ 'organizations',
+ 'phones',
+ 'posixAccounts',
+ 'relations',
+ 'sshPublicKeys',
+ 'websites',
+ 'name',
+ ],
+ }
+ );
+ provisionedUsersByEmail[primaryEmail] = user;
+
+ // Track password for export so an admin can retrieve it
+ newUserPasswords[primaryEmail] = password.result;
+ }
});
+// Create group memberships for users
MEMBERS.forEach((member) => {
- if (!member.email) return;
+ // Prefer the provisioned GWS email over the personal email for group memberships
+ const gwsEmail = member.googleEmailPrefix
+ ? `${member.googleEmailPrefix}@modelcontextprotocol.io`
+ : undefined;
+ const memberEmail = gwsEmail || member.email;
+ if (!memberEmail) return;
+ const provisionedUser = gwsEmail ? provisionedUsersByEmail[gwsEmail] : undefined;
- member.memberOf.forEach((teamKey) => {
- new gworkspace.GroupMember(`${member.email}-${teamKey}`, {
- groupId: groups[teamKey].id,
- email: member.email!,
- role: 'MEMBER',
- });
+ member.memberOf.forEach((roleId: RoleId) => {
+ const role = roleLookup.get(roleId);
+ if (!role?.google) return; // Role doesn't have Google config
+
+ new gworkspace.GroupMember(
+ `${memberEmail}-${role.google.group}`,
+ {
+ groupId: groups[role.google.group].id,
+ email: memberEmail,
+ role: 'MEMBER',
+ },
+ provisionedUser ? { dependsOn: [provisionedUser] } : undefined
+ );
});
});
+
+export { groups as googleGroups };
+// Export initial passwords as secrets so an admin can retrieve them with:
+// pulumi stack output --show-secrets newGWSUserPasswords
+export const newGWSUserPasswords = pulumi.secret(newUserPasswords);
diff --git a/src/index.ts b/src/index.ts
index 4fe06f1..c72d079 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,2 +1,3 @@
export * from './github';
export * from './google';
+export * from './discord';
diff --git a/tsconfig.json b/tsconfig.json
index 4b8e53f..09e8d66 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,4 +13,4 @@
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
-}
\ No newline at end of file
+}