diff --git a/.env.example b/.env.example index d98f7d4b9..7f8a45ee3 100644 --- a/.env.example +++ b/.env.example @@ -15,3 +15,27 @@ # Uncomment this to get GitHub comments for the Pull Request Workflow. # ENABLE_PR_COMMENT=true + +# ADMIN_REPO=safe-settings-config +CONFIG_PATH=.github +SETTINGS_FILE_PATH=settings.yml + +# Configuration support for Hub-Sync safe-settings feature +# SAFE_SETTINGS_HUB_REPO=safe-settings-config-master +# SAFE_SETTINGS_HUB_ORG=foo-training +# A subfolder under 'CONFIG_PATH' where the 'organizations//' structure is found +# SAFE_SETTINGS_HUB_PATH=safe-settings +# SAFE_SETTINGS_HUB_DIRECT_PUSH=true + + + +# ┌────────────── second (optional) +# │ ┌──────────── minute +# │ │ ┌────────── hour +# │ │ │ ┌──────── day of month +# │ │ │ │ ┌────── month +# │ │ │ │ │ ┌──── day of week +# │ │ │ │ │ │ +# │ │ │ │ │ │ +# * * * * * * +# CRON=* * * * * # Run every minute \ No newline at end of file diff --git a/docs/hubSyncHandler/README.md b/docs/hubSyncHandler/README.md new file mode 100644 index 000000000..1f35935c9 --- /dev/null +++ b/docs/hubSyncHandler/README.md @@ -0,0 +1,265 @@ +# Safe Settings Organization Sync & Dashboard + + This feature provides a centralized approach to managing the Safe-Settings Admin Repo, allowing Safe-Settings configurations to be sync'd across multiple ORGs. + +## Overview + +This adds the **hub‑and‑spoke synchronization capability** to Safe Settings. + +One central **master admin repository** (the hub) serves as the authoritative source of configuration ('Master' Admin Config Repo) which is automatically propagated to each organization’s **admin repository** (the spokes). + +**Note:** When something changes in the 'Master' repo (the hub), only those changed files are copied to each affected ORG’s admin repo, so everything stays in sync. + +## Sync Lifecycle (High Level) + +```mermaid +graph TD +A0(PR Closed Event) --> A1(HUB Admin Repo) +A1(HUB Admin Repo) --> B(ORG Admin Repo) +A1(HUB Admin Repo) --> C(ORG Admin Repo) +A1(HUB Admin Repo) --> D(ORG Admin Repo) +``` + +## Gettings Started + +>**Note:** for the standard setup lets assume that Safe-Settings configuration on the Admin Config Repos (Spokes) are stored in `.github/` + +These are the basic steps to setup the Enterprise-Level Safe-Settings, using **Hub-sync** support. + +### ✅ Step 1: Register the App +**Register the Safe-Settings App** in your Enterprise (Enterprise App) or in your Organization. + +For App "installation tragets" (Where can this GitHub App be installed?) +Choose ***Any account*** + +### ✅ Step 2: Install the App +**Install the Safe-Settings App** in any Organzation that you would like Safe-Settings to manage. + +### ✅ Step 3: Create the 'Org-Level' Safe-Settings Admin Config Repo (Spokes) +Create the Org-Level Repo that is your dedicated Safe-Settings Config Repo and will hold all Safe-Settings configurations for the Org. + +### ✅ Step 4: Create the 'Master' Safe-Settings Admin Config Repo (Hub) +Choose any Organization where the Safe-Settings App is installed and create a 'Master' Safe-Settings Admin Config Repo. + +The Repository requires a standard directory structure for storing the config data: +```bash +.github/ +└─ safe-settings/ + ├── globals/ + │ └── manifest.yml + └── organizations/ + ├── org1/ + │ └── ...yml + └── org2/ + └── ...yml +``` + +Notes: +- The `manifest.yml` is a required file, that defines rules for syncing **Global** Safe-Settings configurations. We will address the content format later. +- `org1` and `org2` are just examples and should be replaced with the real names of the Orgs that you want to manage with the **Hub-Sync**. + +### ✅ Step 5: Configure the 'Master' Safe-Settings Admin Config Repo (Hub) + +The **Hub-Sync** feature supports two options +1. **Organization Sync:** +Any settings file in the `organizations/` directory will be synced to the specific `` (Spoke) Admin config Repo subfolder (eg.: /.github/). Only updated files are sync'd to the ORG admin config Repo (spokes). +1. **Global Sync:** Any settings file in the `globals/` directory will be synced to the specific `` (Spoke) Admin config Repo subfolder (eg.: /.github/). + + :warning: The actual sync operation is based on the rules defined in the `globals/manifest.yml`. The rules provide fine grained control over the sync targets and sync strategy. + +These two options only require that you provide the files you would like to sync, in the correct sub-directory. + +#### ✅ Step 5.1: Configure the `manifest.yml` in the 'Master' Safe-Settings Admin Config Repo (Hub) + +The `manifest.yml` defines the sync rules for global settings distribution. +- Sample `manifest.yml` + + ``` + rules: + - name: global-defaults + # specify the target ORG(s) + targets: + - "*" + files: + - "*.yml" + + # mergeStrategy: merge | overwrite | preserve + # -------------------------------------------- + # merge = use a PR to sync files + # overwrite = sync all files to the target ORG(s) (no PR) + mergeStrategy: merge + + - name: security-policies + # specify the target ORG(s) + targets: + - "acme-*" + - "foo-bar" + files: + - settings.yml + mergeStrategy: overwrite + + # optional toggle, default true + # enabled: false + ``` + +### Example Rule Breakdown + +```yaml +- name: global-defaults + targets: + - "*" + files: + - "*.yml" + mergeStrategy: merge +``` +- **Purpose:** Sync all YAML files to all organizations, merging changes via PR. + +```yaml +- name: security-policies + targets: + - "acme-*" + - "foo-bar" + files: + - settings.yml + mergeStrategy: overwrite + enabled: false +``` + +- **Purpose:** Overwrite `settings.yml` in specific organizations, but currently disabled. + + +### `manifest.yml` Reference + +The `manifest.yml` file defines synchronization rules for Safe-Settings hub-and-spoke configuration management. Each rule specifies which organizations and files to target, and how to handle synchronization. + +### Top-Level Structure + +```yaml +rules: + - name: + targets: [, ...] + files: [, ...] + mergeStrategy: + enabled: # optional + # ...additional fields as needed +``` + +--- + +### Elements + +#### `rules` +- **Type:** Array of objects +- **Description:** List of synchronization rules. Each rule controls how specific files are synced to target organizations. + +#### Rule Object + +##### `name` +- **Type:** String +- **Description:** Unique identifier for the rule. Used for reference and logging. +- **Example:** `global-defaults`, `security-policies` + +##### `targets` +- **Type:** Array of strings +- **Description:** List of organization names or patterns to apply the rule to. + - `"*"`: All organizations + - `"acme-*"`: Organizations with names starting with `acme-` + - `"foo-bar"`: Specific organization +- **Example:** + ```yaml + targets: + - "*" + - "acme-*" + - "foo-bar" + ``` + +##### `files` +- **Type:** Array of strings +- **Description:** File patterns to sync. Supports wildcards. + - `"*.yml"`: All YAML files + - `"settings.yml"`: Specific file +- **Example:** + ```yaml + files: + - "*.yml" + - "settings.yml" + ``` + +##### `mergeStrategy` +- **Type:** String (`merge`, `overwrite`, `preserve`) +- **Description:** Determines how files are synced: + - `merge`: use a PR to sync files + - `overwrite`: Sync all files, replacing existing ones (direct commit, no PR) +- **Example:** + ```yaml + mergeStrategy: merge + ``` + +##### `enabled` +- **Type:** Boolean (optional) +- **Description:** Toggle to enable or disable the rule. Default is `true`. +- **Example:** + ```yaml + enabled: false + ``` + +--- + +### Environment Variables & Inputs Specific to the **Hub-Sync** feature + +| Name | Purpose | Default | +|------|---------|---------| +| `SAFE_SETTINGS_HUB_REPO` | Repo for master safe-settings contents | admin-master | +| `SAFE_SETTINGS_HUB_ORG` | Organization that hold the Repo | admin-master-org | +| `SAFE_SETTINGS_HUB_PATH` | source folder | .github/safe-settings | +| `SAFE_SETTINGS_HUB_DIRECT_PUSH` | Use a PR or direct commit | false | + + +--- +--- + +## Hub Sync Scenarios + +1. Sync the `Hub Admin Repo` changes to a `Safe-Settings Admin Repo` in **the same ORG** as the Hub Admin Repo. + +2. Sync the `Hub Admin changes` to a `Safe-Settings Admin Repo` in **a different ORG**. + +3. _`'Global'`_ `Hub Admin Repo` updates. +Changes will `applied to all Organization` + +--- + +## Safe-Settings Hub API endpoints + +### API Endpoints + +The following table summarizes the Safe Settings API endpoints: + +| Endpoint | Method | Purpose | Example Usage | +|------------------------------------------|--------|------------------------------------------------------|---------------| +| `/api/safe-settings/installation` | GET | Organization installation, repo, and sync status | Fetch org status | +| `/api/safe-settings/hub/content` | GET | List hub repo files/directories | List hub files | +| `/api/safe-settings/hub/content/*` | GET | Fetch specific file or directory from hub repo | Get file content | +| `/api/safe-settings/hub/import` | POST | Import settings from orgs into the hub | Import org settings | +| `/api/safe-settings/env` | GET | App environment/config variables | Get env vars | + +**Examples:** +- Fetch org installation status: + ```http + GET /api/safe-settings/installation + ``` +- Import settings from orgs: + ```http + POST /api/safe-settings/hub/import + Body: { "orgs": ["org1", "org2"] } + ``` +- List hub repo files: + ```http + GET /api/safe-settings/hub/content?ref=main&recursive=true + ``` +- Get environment variables: + ```http + GET /api/safe-settings/env + ``` + +--- \ No newline at end of file diff --git a/docs/sample-settings/settings.yml b/docs/sample-settings/settings.yml index 7e19d3354..f763e9997 100644 --- a/docs/sample-settings/settings.yml +++ b/docs/sample-settings/settings.yml @@ -237,18 +237,18 @@ rulesets: # The actors that can bypass the rules in this ruleset bypass_actors: - - actor_id: number - # type: The type of actor that can bypass a ruleset - # - RepositoryRole - # - Team - # - Integration - # - OrganizationAdmin - actor_type: Team - # When the specified actor can bypass the ruleset. `pull_request` - # means that an actor can only bypass rules on pull requests. - # - always - # - pull_request - bypass_mode: pull_request + # - actor_id: number + # # type: The type of actor that can bypass a ruleset + # - RepositoryRole + # - Team + # - Integration + # - OrganizationAdmin + # actor_type: Team + # # When the specified actor can bypass the ruleset. `pull_request` + # # means that an actor can only bypass rules on pull requests. + # - always + # - pull_request + # bypass_mode: pull_request - actor_id: 1 actor_type: OrganizationAdmin diff --git a/hubSyncHandler.log b/hubSyncHandler.log new file mode 100644 index 000000000..141449883 --- /dev/null +++ b/hubSyncHandler.log @@ -0,0 +1,1000 @@ +2026-05-06T21:33:39.184Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:39.184Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-159 +2026-05-06T21:33:39.184Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-159 +2026-05-06T21:33:39.520Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:39.520Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:40.568Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:40.568Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:41.153Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:41.153Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-160 +2026-05-06T21:33:41.153Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-160 +2026-05-06T21:33:41.311Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:41.310Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:42.592Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:42.592Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:43.244Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:43.245Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-161 +2026-05-06T21:33:43.245Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-161 +2026-05-06T21:33:43.401Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:43.401Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:44.679Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:44.679Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:45.190Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-162 +2026-05-06T21:33:45.190Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-162 +2026-05-06T21:33:45.190Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:45.310Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:45.310Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:46.540Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:46.540Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:47.174Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-163 +2026-05-06T21:33:47.175Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-163 +2026-05-06T21:33:47.174Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:47.288Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:47.288Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:48.525Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:48.525Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:49.183Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-164 +2026-05-06T21:33:49.183Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-164 +2026-05-06T21:33:49.183Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:49.463Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:49.463Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:50.442Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:50.442Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:51.134Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:51.134Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-166 +2026-05-06T21:33:51.134Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-166 +2026-05-06T21:33:51.400Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:51.400Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:52.528Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:52.528Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:53.073Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-168 +2026-05-06T21:33:53.073Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-168 +2026-05-06T21:33:53.073Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:53.418Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:53.418Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:54.559Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:54.559Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:55.325Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:55.325Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-169 +2026-05-06T21:33:55.325Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-169 +2026-05-06T21:33:55.430Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:55.430Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:56.585Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:56.585Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:57.375Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-167 +2026-05-06T21:33:57.375Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:57.375Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-167 +2026-05-06T21:33:57.716Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:57.716Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:58.535Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:58.535Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:33:59.175Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-165 +2026-05-06T21:33:59.175Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:33:59.175Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-165 +2026-05-06T21:33:59.404Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:33:59.404Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:34:00.506Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:34:00.506Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:34:00.690Z [TRACE] Fetching installations +2026-05-06T21:34:00.690Z [DEBUG] running a task every minute +2026-05-06T21:34:01.031Z [DEBUG] deploymentConfig is {"restrictedRepos":["admin",".github","safe-settings"]} +2026-05-06T21:34:01.125Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:34:01.125Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-170 +2026-05-06T21:34:01.125Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-170 +2026-05-06T21:34:01.308Z [DEBUG] config for ref undefined is {"restrictedRepos":["admin",".github","safe-settings"],"repository":{"description":"description of the repo","homepage":"https://example.github.io/","auto_init":true,"topics":["new-topic","another-topic"],"security":{"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true},"private":true,"visibility":"private","has_issues":true,"has_projects":true,"has_wiki":true,"default_branch":"main","gitignore_template":"node","license_template":"mit","allow_squash_merge":true,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_auto_merge":true,"delete_branch_on_merge":true,"allow_update_branch":true,"archived":false},"labels":{"include":[{"name":"bug","color":"CC0000","description":"An issue with the system"},{"name":"feature","color":"#336699","description":"New functionality."},{"name":"first-timers-only","oldname":"Help Wanted","color":"#326699"},{"name":"new-label","oldname":"Help Wanted","color":"#326699"}],"exclude":[{"name":"^release"}]},"milestones":[{"title":"milestone-title","description":"milestone-description","state":"open"}],"collaborators":[{"username":"regpaco","permission":"push"},{"username":"beetlejuice","permission":"pull","exclude":["actions-demo"]},{"username":"thor","permission":"push","include":["actions-demo","another-repo"]}],"teams":[{"name":"core","permission":"admin"},{"name":"docss","permission":"push"},{"name":"docs","permission":"pull"},{"name":"globalteam","permission":"push","visibility":"closed"}],"branches":[{"name":"default","protection":{"required_pull_request_reviews":{"required_approving_review_count":1,"dismiss_stale_reviews":true,"require_code_owner_reviews":true,"require_last_push_approval":true,"bypass_pull_request_allowances":{"apps":[],"users":[],"teams":[]},"dismissal_restrictions":{"users":[],"teams":[]}},"required_status_checks":{"strict":true,"contexts":[]},"enforce_admins":true,"restrictions":{"apps":[],"users":[],"teams":[]}}}],"custom_properties":[{"name":"test","value":"test"}],"autolinks":[{"key_prefix":"JIRA-","url_template":"https://jira.github.com/browse/JIRA-","is_alphanumeric":false},{"key_prefix":"MYLINK-","url_template":"https://mywebsite.com/"}],"validator":{"pattern":"[a-zA-Z0-9_-]+"},"rulesets":[{"name":"Template","target":"branch","enforcement":"active","bypass_actors":[{"actor_id":1,"actor_type":"OrganizationAdmin","bypass_mode":"always"},{"actor_id":7898,"actor_type":"RepositoryRole","bypass_mode":"always"},{"actor_id":210920,"actor_type":"Integration","bypass_mode":"always"}],"conditions":{"ref_name":{"include":["~DEFAULT_BRANCH"],"exclude":["refs/heads/oldmaster"]},"repository_name":{"include":["test*"],"exclude":["test","test1"],"protected":true}},"rules":[{"type":"creation"},{"type":"update","parameters":{"update_allows_fetch_and_merge":true}},{"type":"deletion"},{"type":"required_linear_history"},{"type":"required_signatures"},{"type":"required_deployments","parameters":{"required_deployment_environments":["staging"]}},{"type":"pull_request","parameters":{"dismiss_stale_reviews_on_push":true,"require_code_owner_review":true,"require_last_push_approval":true,"required_approving_review_count":1,"required_review_thread_resolution":true}},{"type":"required_status_checks","parameters":{"strict_required_status_checks_policy":true,"required_status_checks":[{"context":"CodeQL","integration_id":1234},{"context":"GHAS Compliance","integration_id":1234}]}},{"type":"workflows","parameters":{"workflows":[{"path":".github/workflows/example.yml","repository_id":123456,"ref":"refs/heads/main","sha":"1234567890abcdef"}]}},{"type":"commit_message_pattern","parameters":{"name":"test commit_message_pattern","negate":true,"operator":"starts_with","pattern":"skip*"}},{"type":"commit_author_email_pattern","parameters":{"name":"test commit_author_email_pattern","negate":false,"operator":"regex","pattern":"^.*@example.com$"}},{"type":"committer_email_pattern","parameters":{"name":"test committer_email_pattern","negate":false,"operator":"regex","pattern":"^.*@example.com$"}},{"type":"branch_name_pattern","parameters":{"name":"test branch_name_pattern","negate":false,"operator":"regex","pattern":".*/.*"}},{"type":"tag_name_pattern","parameters":{"name":"test tag_name_pattern","negate":false,"operator":"regex","pattern":".*/.*"}}]}]} +2026-05-06T21:34:01.308Z [DEBUG] In getSubOrgConfigMap {"repo":"safe-settings-config","owner":"jefeish-test1"} +2026-05-06T21:34:01.308Z [DEBUG] In loadConfigMap {"owner":"jefeish-test1","repo":"safe-settings-config","path":".github/suborgs"} +2026-05-06T21:34:01.325Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:34:01.325Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:34:01.567Z [DEBUG] Error getting settings {"owner":"jefeish-test1","repo":"safe-settings-config","path":".github/suborgs"} HttpError: Not Found - https://docs.github.com/rest/repos/contents#get-repository-content +2026-05-06T21:34:01.567Z [DEBUG] In getRepoConfigMap {"repo":"safe-settings-config","owner":"jefeish-test1"} +2026-05-06T21:34:01.801Z [DEBUG] repo configs = {} +2026-05-06T21:34:01.802Z [DEBUG] { + method: 'GET', + baseUrl: 'https://api.github.com', + headers: { + accept: 'application/vnd.github.v3+json', + 'user-agent': 'probot/13.4.4 octokit-core.js/5.2.0 Node.js/23', + 'x-github-api-version': '2022-11-28' + }, + mediaType: { format: '', previews: [] }, + request: { hook: [Function: bound bound register], retryCount: 1 }, + url: '/orgs/{org}/rulesets', + org: 'jefeish-test1' +} +2026-05-06T21:34:01.801Z [DEBUG] No repos directory in the safe-settings-config/.github +2026-05-06T21:34:01.802Z [DEBUG] Getting all rulesets for the org undefined +2026-05-06T21:34:02.123Z [DEBUG] [] + + [ + { + "name": "Template", + "target": "branch", + "enforcement": "active", + "bypass_actors": [ + { + "actor_id": 1, + "actor_type": "OrganizationAdmin", + "bypass_mode": "always" + }, + { + "actor_id": 7898, + "actor_type": "RepositoryRole", + "bypass_mode": "always" + }, + { + "actor_id": 210920, + "actor_type": "Integration", + "bypass_mode": "always" + } + ], + "conditions": { + "ref_name": { + "include": [ + "~DEFAULT_BRANCH" + ], + "exclude": [ + "refs/heads/oldmaster" + ] + }, + "repository_name": { + "include": [ + "test*" + ], + "exclude": [ + "test", + "test1" + ], + "protected": true + } + }, + "rules": [ + { + "type": "creation" + }, + { + "type": "update", + "parameters": { + "update_allows_fetch_and_merge": true + } + }, + { + "type": "deletion" + }, + { + "type": "required_linear_history" + }, + { + "type": "required_signatures" + }, + { + "type": "required_deployments", + "parameters": { + "required_deployment_environments": [ + "staging" + ] + } + }, + { + "type": "pull_request", + "parameters": { + "dismiss_stale_reviews_on_push": true, + "require_code_owner_review": true, + "require_last_push_approval": true, + "required_approving_review_count": 1, + "required_review_thread_resolution": true + } + }, + { + "type": "required_status_checks", + "parameters": { + "strict_required_status_checks_policy": true, + "required_status_checks": [ + { + "context": "CodeQL", + "integration_id": 1234 + }, + { + "context": "GHAS Compliance", + "integration_id": 1234 + } + ] + } + }, + { + "type": "workflows", + "parameters": { + "workflows": [ + { + "path": ".github/workflows/example.yml", + "repository_id": 123456, + "ref": "refs/heads/main", + "sha": "1234567890abcdef" + } + ] + } + }, + { + "type": "commit_message_pattern", + "parameters": { + "name": "test commit_message_pattern", + "negate": true, + "operator": "starts_with", + "pattern": "skip*" + } + }, + { + "type": "commit_author_email_pattern", + "parameters": { + "name": "test commit_author_email_pattern", + "negate": false, + "operator": "regex", + "pattern": "^.*@example.com$" + } + }, + { + "type": "committer_email_pattern", + "parameters": { + "name": "test committer_email_pattern", + "negate": false, + "operator": "regex", + "pattern": "^.*@example.com$" + } + }, + { + "type": "branch_name_pattern", + "parameters": { + "name": "test branch_name_pattern", + "negate": false, + "operator": "regex", + "pattern": ".*/.*" + } + }, + { + "type": "tag_name_pattern", + "parameters": { + "name": "test tag_name_pattern", + "negate": false, + "operator": "regex", + "pattern": ".*/.*" + } + } + ] + } +] +2026-05-06T21:34:02.124Z [DEBUG] Creating Rulesets with the following values { + "name": "Template", + "target": "branch", + "enforcement": "active", + "bypass_actors": [ + { + "actor_id": 1, + "actor_type": "OrganizationAdmin", + "bypass_mode": "always" + }, + { + "actor_id": 7898, + "actor_type": "RepositoryRole", + "bypass_mode": "always" + }, + { + "actor_id": 210920, + "actor_type": "Integration", + "bypass_mode": "always" + } + ], + "conditions": { + "ref_name": { + "include": [ + "~DEFAULT_BRANCH" + ], + "exclude": [ + "refs/heads/oldmaster" + ] + }, + "repository_name": { + "include": [ + "test*" + ], + "exclude": [ + "test", + "test1" + ], + "protected": true + } + }, + "rules": [ + { + "type": "creation" + }, + { + "type": "update", + "parameters": { + "update_allows_fetch_and_merge": true + } + }, + { + "type": "deletion" + }, + { + "type": "required_linear_history" + }, + { + "type": "required_signatures" + }, + { + "type": "required_deployments", + "parameters": { + "required_deployment_environments": [ + "staging" + ] + } + }, + { + "type": "pull_request", + "parameters": { + "dismiss_stale_reviews_on_push": true, + "require_code_owner_review": true, + "require_last_push_approval": true, + "required_approving_review_count": 1, + "required_review_thread_resolution": true + } + }, + { + "type": "required_status_checks", + "parameters": { + "strict_required_status_checks_policy": true, + "required_status_checks": [ + { + "context": "CodeQL", + "integration_id": 1234 + }, + { + "context": "GHAS Compliance", + "integration_id": 1234 + } + ] + } + }, + { + "type": "workflows", + "parameters": { + "workflows": [ + { + "path": ".github/workflows/example.yml", + "repository_id": 123456, + "ref": "refs/heads/main", + "sha": "1234567890abcdef" + } + ] + } + }, + { + "type": "commit_message_pattern", + "parameters": { + "name": "test commit_message_pattern", + "negate": true, + "operator": "starts_with", + "pattern": "skip*" + } + }, + { + "type": "commit_author_email_pattern", + "parameters": { + "name": "test commit_author_email_pattern", + "negate": false, + "operator": "regex", + "pattern": "^.*@example.com$" + } + }, + { + "type": "committer_email_pattern", + "parameters": { + "name": "test committer_email_pattern", + "negate": false, + "operator": "regex", + "pattern": "^.*@example.com$" + } + }, + { + "type": "branch_name_pattern", + "parameters": { + "name": "test branch_name_pattern", + "negate": false, + "operator": "regex", + "pattern": ".*/.*" + } + }, + { + "type": "tag_name_pattern", + "parameters": { + "name": "test tag_name_pattern", + "negate": false, + "operator": "regex", + "pattern": ".*/.*" + } + } + ] +} +2026-05-06T21:34:02.123Z [DEBUG] Results of comparing Rulesets diffable target [] with source [{"name":"Template","target":"branch","enforcement":"active","bypass_actors":[{"actor_id":1,"actor_type":"OrganizationAdmin","bypass_mode":"always"},{"actor_id":7898,"actor_type":"RepositoryRole","bypass_mode":"always"},{"actor_id":210920,"actor_type":"Integration","bypass_mode":"always"}],"conditions":{"ref_name":{"include":["~DEFAULT_BRANCH"],"exclude":["refs/heads/oldmaster"]},"repository_name":{"include":["test*"],"exclude":["test","test1"],"protected":true}},"rules":[{"type":"creation"},{"type":"update","parameters":{"update_allows_fetch_and_merge":true}},{"type":"deletion"},{"type":"required_linear_history"},{"type":"required_signatures"},{"type":"required_deployments","parameters":{"required_deployment_environments":["staging"]}},{"type":"pull_request","parameters":{"dismiss_stale_reviews_on_push":true,"require_code_owner_review":true,"require_last_push_approval":true,"required_approving_review_count":1,"required_review_thread_resolution":true}},{"type":"required_status_checks","parameters":{"strict_required_status_checks_policy":true,"required_status_checks":[{"context":"CodeQL","integration_id":1234},{"context":"GHAS Compliance","integration_id":1234}]}},{"type":"workflows","parameters":{"workflows":[{"path":".github/workflows/example.yml","repository_id":123456,"ref":"refs/heads/main","sha":"1234567890abcdef"}]}},{"type":"commit_message_pattern","parameters":{"name":"test commit_message_pattern","negate":true,"operator":"starts_with","pattern":"skip*"}},{"type":"commit_author_email_pattern","parameters":{"name":"test commit_author_email_pattern","negate":false,"operator":"regex","pattern":"^.*@example.com$"}},{"type":"committer_email_pattern","parameters":{"name":"test committer_email_pattern","negate":false,"operator":"regex","pattern":"^.*@example.com$"}},{"type":"branch_name_pattern","parameters":{"name":"test branch_name_pattern","negate":false,"operator":"regex","pattern":".*/.*"}},{"type":"tag_name_pattern","parameters":{"name":"test tag_name_pattern","negate":false,"operator":"regex","pattern":".*/.*"}}]}] is {"msg":"Changes found","additions":{"0":{"name":"Template","target":"branch","enforcement":"active","bypass_actors":[{"actor_id":1,"actor_type":"OrganizationAdmin","bypass_mode":"always"},{"actor_id":7898,"actor_type":"RepositoryRole","bypass_mode":"always"},{"actor_id":210920,"actor_type":"Integration","bypass_mode":"always"}],"conditions":{"ref_name":{"include":["~DEFAULT_BRANCH"],"exclude":["refs/heads/oldmaster"]},"repository_name":{"include":["test*"],"exclude":["test","test1"],"protected":true}},"rules":[{"type":"creation"},{"type":"update","parameters":{"update_allows_fetch_and_merge":true}},{"type":"deletion"},{"type":"required_linear_history"},{"type":"required_signatures"},{"type":"required_deployments","parameters":{"required_deployment_environments":["staging"]}},{"type":"pull_request","parameters":{"dismiss_stale_reviews_on_push":true,"require_code_owner_review":true,"require_last_push_approval":true,"required_approving_review_count":1,"required_review_thread_resolution":true}},{"type":"required_status_checks","parameters":{"strict_required_status_checks_policy":true,"required_status_checks":[{"context":"CodeQL","integration_id":1234},{"context":"GHAS Compliance","integration_id":1234}]}},{"type":"workflows","parameters":{"workflows":[{"path":".github/workflows/example.yml","repository_id":123456,"ref":"refs/heads/main","sha":"1234567890abcdef"}]}},{"type":"commit_message_pattern","parameters":{"name":"test commit_message_pattern","negate":true,"operator":"starts_with","pattern":"skip*"}},{"type":"commit_author_email_pattern","parameters":{"name":"test commit_author_email_pattern","negate":false,"operator":"regex","pattern":"^.*@example.com$"}},{"type":"committer_email_pattern","parameters":{"name":"test committer_email_pattern","negate":false,"operator":"regex","pattern":"^.*@example.com$"}},{"type":"branch_name_pattern","parameters":{"name":"test branch_name_pattern","negate":false,"operator":"regex","pattern":".*/.*"}},{"type":"tag_name_pattern","parameters":{"name":"test tag_name_pattern","negate":false,"operator":"regex","pattern":".*/.*"}}]}},"modifications":{}} +2026-05-06T21:34:02.438Z [ERROR] RequestError [HttpError]: Validation Failed: "Actor role must be part of the ruleset source or owner organization" - https://docs.github.com/rest/orgs/rules#create-an-organization-repository-ruleset + at /Users/jefeish/projects/safe-settings/node_modules/@octokit/request/dist-node/index.js:125:21 + at process.processTicksAndRejections (node:internal/process/task_queues:105:5) + at async sendRequestWithRetries (/Users/jefeish/projects/safe-settings/node_modules/octokit-auth-probot/node_modules/@octokit/auth-app/dist-node/index.js:411:12) + at async Job.doExecute (/Users/jefeish/projects/safe-settings/node_modules/bottleneck/light.js:405:18) { + status: 422, + response: { + url: 'https://api.github.com/orgs/jefeish-test1/rulesets', + status: 422, + headers: { + 'access-control-allow-origin': '*', + 'access-control-expose-headers': 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset', + 'content-length': '231', + 'content-security-policy': "default-src 'none'", + 'content-type': 'application/json; charset=utf-8', + date: 'Wed, 06 May 2026 21:34:02 GMT', + 'referrer-policy': 'origin-when-cross-origin, strict-origin-when-cross-origin', + server: 'github.com', + 'strict-transport-security': 'max-age=31536000; includeSubdomains; preload', + vary: 'Accept-Encoding, Accept, X-Requested-With', + 'x-accepted-github-permissions': 'organization_administration=write', + 'x-content-type-options': 'nosniff', + 'x-frame-options': 'deny', + 'x-github-api-version-selected': '2022-11-28', + 'x-github-media-type': 'github.v3; format=json', + 'x-github-request-id': 'F252:289F06:4575063:40C8A51:69FBB3CA', + 'x-ratelimit-limit': '15000', + 'x-ratelimit-remaining': '14869', + 'x-ratelimit-reset': '1778106601', + 'x-ratelimit-resource': 'core', + 'x-ratelimit-used': '131', + 'x-xss-protection': '0' + }, + data: { + message: 'Validation Failed', + errors: [Array], + documentation_url: 'https://docs.github.com/rest/orgs/rules#create-an-organization-repository-ruleset', + status: '422' + } + }, + request: { + method: 'POST', + url: 'https://api.github.com/orgs/jefeish-test1/rulesets', + headers: { + accept: 'application/vnd.github.v3+json', + 'user-agent': 'probot/13.4.4 octokit-core.js/5.2.0 Node.js/23', + 'x-github-api-version': '2022-11-28', + authorization: 'token [REDACTED]', + 'content-type': 'application/json; charset=utf-8' + }, + body: '{"name":"Template","target":"branch","enforcement":"active","bypass_actors":[{"actor_id":1,"actor_type":"OrganizationAdmin","bypass_mode":"always"},{"actor_id":7898,"actor_type":"RepositoryRole","bypass_mode":"always"},{"actor_id":210920,"actor_type":"Integration","bypass_mode":"always"}],"conditions":{"ref_name":{"include":["~DEFAULT_BRANCH"],"exclude":["refs/heads/oldmaster"]},"repository_name":{"include":["test*"],"exclude":["test","test1"],"protected":true}},"rules":[{"type":"creation"},{"type":"update","parameters":{"update_allows_fetch_and_merge":true}},{"type":"deletion"},{"type":"required_linear_history"},{"type":"required_signatures"},{"type":"required_deployments","parameters":{"required_deployment_environments":["staging"]}},{"type":"pull_request","parameters":{"dismiss_stale_reviews_on_push":true,"require_code_owner_review":true,"require_last_push_approval":true,"required_approving_review_count":1,"required_review_thread_resolution":true}},{"type":"required_status_checks","parameters":{"strict_required_status_checks_policy":true,"required_status_checks":[{"context":"CodeQL","integration_id":1234},{"context":"GHAS Compliance","integration_id":1234}]}},{"type":"workflows","parameters":{"workflows":[{"path":".github/workflows/example.yml","repository_id":123456,"ref":"refs/heads/main","sha":"1234567890abcdef"}]}},{"type":"commit_message_pattern","parameters":{"name":"test commit_message_pattern","negate":true,"operator":"starts_with","pattern":"skip*"}},{"type":"commit_author_email_pattern","parameters":{"name":"test commit_author_email_pattern","negate":false,"operator":"regex","pattern":"^.*@example.com$"}},{"type":"committer_email_pattern","parameters":{"name":"test committer_email_pattern","negate":false,"operator":"regex","pattern":"^.*@example.com$"}},{"type":"branch_name_pattern","parameters":{"name":"test branch_name_pattern","negate":false,"operator":"regex","pattern":".*/.*"}},{"type":"tag_name_pattern","parameters":{"name":"test tag_name_pattern","negate":false,"operator":"regex","pattern":".*/.*"}}]}', + request: { hook: [Function: bound bound register], retryCount: 1 } + } +} +2026-05-06T21:34:02.438Z [DEBUG] Fetching repositories +2026-05-06T21:34:02.522Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:34:02.522Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:34:02.789Z [DEBUG] Process normally... Not a SubOrg config change or SubOrg config was changed and this repo is part of it. {"owner":"jefeish-test1","repo":"safe-settings-config"} suborg config undefined +2026-05-06T21:34:02.789Z [DEBUG] consolidated config is {"restrictedRepos":["admin",".github","safe-settings"],"repository":{"description":"description of the repo","homepage":"https://example.github.io/","auto_init":true,"topics":["new-topic","another-topic"],"security":{"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true},"private":true,"visibility":"private","has_issues":true,"has_projects":true,"has_wiki":true,"default_branch":"main","gitignore_template":"node","license_template":"mit","allow_squash_merge":true,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_auto_merge":true,"delete_branch_on_merge":true,"allow_update_branch":true,"archived":false,"name":"safe-settings-config","org":"jefeish-test1"},"labels":{"include":[{"name":"bug","color":"CC0000","description":"An issue with the system"},{"name":"feature","color":"#336699","description":"New functionality."},{"name":"first-timers-only","oldname":"Help Wanted","color":"#326699"},{"name":"new-label","oldname":"Help Wanted","color":"#326699"}],"exclude":[{"name":"^release"}]},"milestones":[{"title":"milestone-title","description":"milestone-description","state":"open"}],"collaborators":[{"username":"regpaco","permission":"push"},{"username":"beetlejuice","permission":"pull","exclude":["actions-demo"]},{"username":"thor","permission":"push","include":["actions-demo","another-repo"]}],"teams":[{"name":"core","permission":"admin"},{"name":"docss","permission":"push"},{"name":"docs","permission":"pull"},{"name":"globalteam","permission":"push","visibility":"closed"}],"branches":[{"name":"default","protection":{"required_pull_request_reviews":{"required_approving_review_count":1,"dismiss_stale_reviews":true,"require_code_owner_reviews":true,"require_last_push_approval":true,"bypass_pull_request_allowances":{"apps":[],"users":[],"teams":[]},"dismissal_restrictions":{"users":[],"teams":[]}},"required_status_checks":{"strict":true,"contexts":[]},"enforce_admins":true,"restrictions":{"apps":[],"users":[],"teams":[]}}}],"custom_properties":[{"name":"test","value":"test"}],"autolinks":[{"key_prefix":"JIRA-","url_template":"https://jira.github.com/browse/JIRA-","is_alphanumeric":false},{"key_prefix":"MYLINK-","url_template":"https://mywebsite.com/"}],"validator":{"pattern":"[a-zA-Z0-9_-]+"}} +2026-05-06T21:34:02.789Z [DEBUG] safe-settings-config not in restricted repos admin,.github,safe-settings +2026-05-06T21:34:02.789Z [DEBUG] found a matching repoconfig for this repo {"description":"description of the repo","homepage":"https://example.github.io/","auto_init":true,"topics":["new-topic","another-topic"],"security":{"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true},"private":true,"visibility":"private","has_issues":true,"has_projects":true,"has_wiki":true,"default_branch":"main","gitignore_template":"node","license_template":"mit","allow_squash_merge":true,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_auto_merge":true,"delete_branch_on_merge":true,"allow_update_branch":true,"archived":false,"name":"safe-settings-config","org":"jefeish-test1"} +2026-05-06T21:34:02.789Z [DEBUG] Found section labels in the config. Creating plugin... +2026-05-06T21:34:02.789Z [DEBUG] Found section branches in the config. Creating plugin... +2026-05-06T21:34:02.789Z [DEBUG] Found section teams in the config. Creating plugin... +2026-05-06T21:34:02.789Z [DEBUG] suborg config for safe-settings-config is undefined +2026-05-06T21:34:02.789Z [DEBUG] Found section milestones in the config. Creating plugin... +2026-05-06T21:34:02.789Z [DEBUG] Found section autolinks in the config. Creating plugin... +2026-05-06T21:34:02.789Z [DEBUG] Found section collaborators in the config. Creating plugin... +2026-05-06T21:34:02.789Z [DEBUG] Found section validator in the config. Creating plugin... +2026-05-06T21:34:02.789Z [DEBUG] Syncing Repo safe-settings-config +2026-05-06T21:34:02.789Z [DEBUG] Found section custom_properties in the config. Creating plugin... +2026-05-06T21:34:03.108Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:34:03.108Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-171 +2026-05-06T21:34:03.108Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-171 +2026-05-06T21:34:03.183Z [DEBUG] Adding name for gitignore_template node +2026-05-06T21:34:03.183Z [DEBUG] Updating repo with settings ["new-topic","another-topic"] {"mediaType":{"previews":["nebula-preview"]},"description":"description of the repo","homepage":"https://example.github.io/","auto_init":true,"security":{"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true},"private":true,"visibility":"private","has_issues":true,"has_projects":true,"has_wiki":true,"default_branch":"main","gitignore_template":"node","license_template":"mit","allow_squash_merge":true,"allow_merge_commit":true,"allow_rebase_merge":true,"allow_auto_merge":true,"delete_branch_on_merge":true,"allow_update_branch":true,"archived":false,"name":"safe-settings-config","org":"jefeish-test1","owner":"jefeish-test1","repo":"safe-settings-config"} +2026-05-06T21:34:03.183Z [DEBUG] There are repo changes +2026-05-06T21:34:03.183Z [DEBUG] Result of comparing repo for changes = [object Object] +2026-05-06T21:34:03.183Z [DEBUG] Result of comparing topics for changes source ["another-topic","new-topic"] target ["new-topic","another-topic"] = [object Object] +2026-05-06T21:34:03.183Z [DEBUG] Adding name for license_template mit +2026-05-06T21:34:03.347Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:34:03.347Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:34:03.637Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:34:03.637Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test1 and repo safe-settings-config +2026-05-06T21:34:03.638Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test1 and repo safe-settings-config +2026-05-06T21:34:04.619Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:34:04.619Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:34:05.159Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:34:05.159Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-172 +2026-05-06T21:34:05.159Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-172 +2026-05-06T21:34:05.422Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:34:05.422Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:34:05.540Z [DEBUG] Finding labels for {"per_page":100,"owner":"jefeish-test1","repo":"safe-settings-config","headers":{"accept":"application/vnd.github.symmetra-preview+json"}} +2026-05-06T21:34:05.541Z [DEBUG] Finding teams for jefeish-test1/safe-settings-config +2026-05-06T21:34:05.541Z [DEBUG] Getting all custom properties for the repo jefeish-test1/safe-settings-config +2026-05-06T21:34:05.888Z [DEBUG] [ + { + "id": 14747418, + "key_prefix": "JIRA-", + "url_template": "https://jira.github.com/browse/JIRA-", + "is_alphanumeric": false + }, + { + "id": 14747419, + "key_prefix": "MYLINK-", + "url_template": "https://mywebsite.com/", + "is_alphanumeric": true + } +] + + [ + { + "key_prefix": "JIRA-", + "url_template": "https://jira.github.com/browse/JIRA-", + "is_alphanumeric": false + }, + { + "key_prefix": "MYLINK-", + "url_template": "https://mywebsite.com/" + } +] +2026-05-06T21:34:05.889Z [DEBUG] There are no changes for Autolinks for repo safe-settings-config. Skipping changes +2026-05-06T21:34:05.888Z [DEBUG] Results of comparing Autolinks diffable target [{"id":14747418,"key_prefix":"JIRA-","url_template":"https://jira.github.com/browse/JIRA-","is_alphanumeric":false},{"id":14747419,"key_prefix":"MYLINK-","url_template":"https://mywebsite.com/","is_alphanumeric":true}] with source [{"key_prefix":"JIRA-","url_template":"https://jira.github.com/browse/JIRA-","is_alphanumeric":false},{"key_prefix":"MYLINK-","url_template":"https://mywebsite.com/"}] is {"msg":"Changes found","additions":{},"modifications":{},"deletions":{}} +2026-05-06T21:34:05.948Z [DEBUG] [ + { + "url": "https://api.github.com/repos/jefeish-test1/safe-settings-config/milestones/1", + "html_url": "https://github.com/jefeish-test1/safe-settings-config/milestone/1", + "labels_url": "https://api.github.com/repos/jefeish-test1/safe-settings-config/milestones/1/labels", + "id": 15823110, + "node_id": "MI_kwDOPqtde84A8XEG", + "number": 1, + "title": "milestone-title", + "description": "milestone-description", + "creator": { + "login": "fabrikam-safe-settings[bot]", + "id": 223158109, + "node_id": "BOT_kgDODU0fXQ", + "avatar_url": "https://avatars.githubusercontent.com/b/5789?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D", + "html_url": "https://github.com/apps/fabrikam-safe-settings", + "followers_url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events", + "type": "Bot", + "user_view_type": "public", + "site_admin": false + }, + "open_issues": 0, + "closed_issues": 0, + "state": "open", + "created_at": "2026-05-06T21:30:07Z", + "updated_at": "2026-05-06T21:30:07Z", + "due_on": null, + "closed_at": null + } +] + + [ + { + "title": "milestone-title", + "description": "milestone-description", + "state": "open" + } +] +2026-05-06T21:34:05.948Z [DEBUG] There are no changes for Milestones for repo safe-settings-config. Skipping changes +2026-05-06T21:34:05.948Z [DEBUG] Results of comparing Milestones diffable target [{"url":"https://api.github.com/repos/jefeish-test1/safe-settings-config/milestones/1","html_url":"https://github.com/jefeish-test1/safe-settings-config/milestone/1","labels_url":"https://api.github.com/repos/jefeish-test1/safe-settings-config/milestones/1/labels","id":15823110,"node_id":"MI_kwDOPqtde84A8XEG","number":1,"title":"milestone-title","description":"milestone-description","creator":{"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false},"open_issues":0,"closed_issues":0,"state":"open","created_at":"2026-05-06T21:30:07Z","updated_at":"2026-05-06T21:30:07Z","due_on":null,"closed_at":null}] with source [{"title":"milestone-title","description":"milestone-description","state":"open"}] is {"msg":"Changes found","additions":{},"modifications":{},"deletions":{}} +2026-05-06T21:34:05.968Z [DEBUG] [] + + [ + { + "username": "regpaco", + "permission": "push" + }, + { + "username": "beetlejuice", + "permission": "pull" + } +] +2026-05-06T21:34:05.968Z [DEBUG] Results of comparing Collaborators diffable target [] with source [{"username":"regpaco","permission":"push"},{"username":"beetlejuice","permission":"pull"}] is {"msg":"Changes found","additions":{"0":{"username":"regpaco","permission":"push"},"1":{"username":"beetlejuice","permission":"pull"}},"modifications":{}} +2026-05-06T21:34:05.978Z [DEBUG] Found teams [{"name":"docss","id":17408360,"node_id":"T_kwDODb9_884BCaFo","slug":"docss","description":null,"privacy":"secret","notification_setting":"notifications_enabled","url":"https://api.github.com/organizations/230653939/team/17408360","html_url":"https://github.com/orgs/jefeish-test1/teams/docss","members_url":"https://api.github.com/organizations/230653939/team/17408360/members{/member}","repositories_url":"https://api.github.com/organizations/230653939/team/17408360/repos","type":"organization","organization_id":230653939,"permission":"push","permissions":{"admin":false,"maintain":false,"push":true,"triage":true,"pull":true},"parent":null},{"name":"globalteam","id":17408361,"node_id":"T_kwDODb9_884BCaFp","slug":"globalteam","description":null,"privacy":"secret","notification_setting":"notifications_enabled","url":"https://api.github.com/organizations/230653939/team/17408361","html_url":"https://github.com/orgs/jefeish-test1/teams/globalteam","members_url":"https://api.github.com/organizations/230653939/team/17408361/members{/member}","repositories_url":"https://api.github.com/organizations/230653939/team/17408361/repos","type":"organization","organization_id":230653939,"permission":"push","permissions":{"admin":false,"maintain":false,"push":true,"triage":true,"pull":true},"parent":null},{"name":"core","id":17408362,"node_id":"T_kwDODb9_884BCaFq","slug":"core","description":null,"privacy":"secret","notification_setting":"notifications_enabled","url":"https://api.github.com/organizations/230653939/team/17408362","html_url":"https://github.com/orgs/jefeish-test1/teams/core","members_url":"https://api.github.com/organizations/230653939/team/17408362/members{/member}","repositories_url":"https://api.github.com/organizations/230653939/team/17408362/repos","type":"organization","organization_id":230653939,"permission":"admin","permissions":{"admin":true,"maintain":true,"push":true,"triage":true,"pull":true},"parent":null},{"name":"docs","id":17408363,"node_id":"T_kwDODb9_884BCaFr","slug":"docs","description":null,"privacy":"secret","notification_setting":"notifications_enabled","url":"https://api.github.com/organizations/230653939/team/17408363","html_url":"https://github.com/orgs/jefeish-test1/teams/docs","members_url":"https://api.github.com/organizations/230653939/team/17408363/members{/member}","repositories_url":"https://api.github.com/organizations/230653939/team/17408363/repos","type":"organization","organization_id":230653939,"permission":"pull","permissions":{"admin":false,"maintain":false,"push":false,"triage":false,"pull":true},"parent":null}] +2026-05-06T21:34:05.978Z [DEBUG] Calling API to get security managers {"method":"GET","url":"https://api.github.com/orgs/jefeish-test1/security-managers","headers":{"accept":"application/vnd.github.v3+json","user-agent":"probot/13.4.4 octokit-core.js/5.2.0 Node.js/23"},"request":{"retryCount":1}} +2026-05-06T21:34:05.978Z [DEBUG] Removing all security manager teams since they should not be handled here +2026-05-06T21:34:06.021Z [DEBUG] [ + { + "name": "repository-is-cool", + "value": "true" + } +] + + [ + { + "name": "test", + "value": "test" + } +] +2026-05-06T21:34:06.021Z [DEBUG] Create Custom Property "test" for the repo jefeish-test1/safe-settings-config +2026-05-06T21:34:06.021Z [DEBUG] Results of comparing CustomProperties diffable target [{"name":"repository-is-cool","value":"true"}] with source [{"name":"test","value":"test"}] is {"msg":"Changes found","additions":[{"name":"test","value":"test"}],"modifications":{},"deletions":[{"name":"repository-is-cool","value":"true"}]} +2026-05-06T21:34:06.021Z [DEBUG] Delete Custom Property "repository-is-cool" for the repo jefeish-test1/safe-settings-config +2026-05-06T21:34:06.020Z [DEBUG] Found 1 custom properties +2026-05-06T21:34:06.042Z [DEBUG] Repo safe-settings-config Passed Validation for pattern [a-zA-Z0-9_-]+ +2026-05-06T21:34:06.214Z [DEBUG] Response from the call is [] +2026-05-06T21:34:06.214Z [DEBUG] Results of comparing Teams diffable target [{"name":"docss","id":17408360,"node_id":"T_kwDODb9_884BCaFo","slug":"docss","description":null,"privacy":"secret","notification_setting":"notifications_enabled","url":"https://api.github.com/organizations/230653939/team/17408360","html_url":"https://github.com/orgs/jefeish-test1/teams/docss","members_url":"https://api.github.com/organizations/230653939/team/17408360/members{/member}","repositories_url":"https://api.github.com/organizations/230653939/team/17408360/repos","type":"organization","organization_id":230653939,"permission":"push","permissions":{"admin":false,"maintain":false,"push":true,"triage":true,"pull":true},"parent":null},{"name":"globalteam","id":17408361,"node_id":"T_kwDODb9_884BCaFp","slug":"globalteam","description":null,"privacy":"secret","notification_setting":"notifications_enabled","url":"https://api.github.com/organizations/230653939/team/17408361","html_url":"https://github.com/orgs/jefeish-test1/teams/globalteam","members_url":"https://api.github.com/organizations/230653939/team/17408361/members{/member}","repositories_url":"https://api.github.com/organizations/230653939/team/17408361/repos","type":"organization","organization_id":230653939,"permission":"push","permissions":{"admin":false,"maintain":false,"push":true,"triage":true,"pull":true},"parent":null},{"name":"core","id":17408362,"node_id":"T_kwDODb9_884BCaFq","slug":"core","description":null,"privacy":"secret","notification_setting":"notifications_enabled","url":"https://api.github.com/organizations/230653939/team/17408362","html_url":"https://github.com/orgs/jefeish-test1/teams/core","members_url":"https://api.github.com/organizations/230653939/team/17408362/members{/member}","repositories_url":"https://api.github.com/organizations/230653939/team/17408362/repos","type":"organization","organization_id":230653939,"permission":"admin","permissions":{"admin":true,"maintain":true,"push":true,"triage":true,"pull":true},"parent":null},{"name":"docs","id":17408363,"node_id":"T_kwDODb9_884BCaFr","slug":"docs","description":null,"privacy":"secret","notification_setting":"notifications_enabled","url":"https://api.github.com/organizations/230653939/team/17408363","html_url":"https://github.com/orgs/jefeish-test1/teams/docs","members_url":"https://api.github.com/organizations/230653939/team/17408363/members{/member}","repositories_url":"https://api.github.com/organizations/230653939/team/17408363/repos","type":"organization","organization_id":230653939,"permission":"pull","permissions":{"admin":false,"maintain":false,"push":false,"triage":false,"pull":true},"parent":null}] with source [{"name":"core","permission":"admin"},{"name":"docss","permission":"push"},{"name":"docs","permission":"pull"},{"name":"globalteam","permission":"push","visibility":"closed"}] is {"msg":"Changes found","additions":{},"modifications":[{"visibility":{"0":"c","1":"l","2":"o","3":"s","4":"e","5":"d"},"name":"globalteam"}],"deletions":{}} +2026-05-06T21:34:06.214Z [DEBUG] Adding name for visibility closed +2026-05-06T21:34:06.214Z [DEBUG] [ + { + "name": "docss", + "id": 17408360, + "node_id": "T_kwDODb9_884BCaFo", + "slug": "docss", + "description": null, + "privacy": "secret", + "notification_setting": "notifications_enabled", + "url": "https://api.github.com/organizations/230653939/team/17408360", + "html_url": "https://github.com/orgs/jefeish-test1/teams/docss", + "members_url": "https://api.github.com/organizations/230653939/team/17408360/members{/member}", + "repositories_url": "https://api.github.com/organizations/230653939/team/17408360/repos", + "type": "organization", + "organization_id": 230653939, + "permission": "push", + "permissions": { + "admin": false, + "maintain": false, + "push": true, + "triage": true, + "pull": true + }, + "parent": null + }, + { + "name": "globalteam", + "id": 17408361, + "node_id": "T_kwDODb9_884BCaFp", + "slug": "globalteam", + "description": null, + "privacy": "secret", + "notification_setting": "notifications_enabled", + "url": "https://api.github.com/organizations/230653939/team/17408361", + "html_url": "https://github.com/orgs/jefeish-test1/teams/globalteam", + "members_url": "https://api.github.com/organizations/230653939/team/17408361/members{/member}", + "repositories_url": "https://api.github.com/organizations/230653939/team/17408361/repos", + "type": "organization", + "organization_id": 230653939, + "permission": "push", + "permissions": { + "admin": false, + "maintain": false, + "push": true, + "triage": true, + "pull": true + }, + "parent": null + }, + { + "name": "core", + "id": 17408362, + "node_id": "T_kwDODb9_884BCaFq", + "slug": "core", + "description": null, + "privacy": "secret", + "notification_setting": "notifications_enabled", + "url": "https://api.github.com/organizations/230653939/team/17408362", + "html_url": "https://github.com/orgs/jefeish-test1/teams/core", + "members_url": "https://api.github.com/organizations/230653939/team/17408362/members{/member}", + "repositories_url": "https://api.github.com/organizations/230653939/team/17408362/repos", + "type": "organization", + "organization_id": 230653939, + "permission": "admin", + "permissions": { + "admin": true, + "maintain": true, + "push": true, + "triage": true, + "pull": true + }, + "parent": null + }, + { + "name": "docs", + "id": 17408363, + "node_id": "T_kwDODb9_884BCaFr", + "slug": "docs", + "description": null, + "privacy": "secret", + "notification_setting": "notifications_enabled", + "url": "https://api.github.com/organizations/230653939/team/17408363", + "html_url": "https://github.com/orgs/jefeish-test1/teams/docs", + "members_url": "https://api.github.com/organizations/230653939/team/17408363/members{/member}", + "repositories_url": "https://api.github.com/organizations/230653939/team/17408363/repos", + "type": "organization", + "organization_id": 230653939, + "permission": "pull", + "permissions": { + "admin": false, + "maintain": false, + "push": false, + "triage": false, + "pull": true + }, + "parent": null + } +] + + [ + { + "name": "core", + "permission": "admin" + }, + { + "name": "docss", + "permission": "push" + }, + { + "name": "docs", + "permission": "pull" + }, + { + "name": "globalteam", + "permission": "push", + "visibility": "closed" + } +] +2026-05-06T21:34:06.389Z [DEBUG] There are no changes for branch {"owner":"jefeish-test1","repo":"safe-settings-config","branch":"main"}. Skipping branch protection changes +2026-05-06T21:34:06.388Z [DEBUG] Result of compareDeep = [object Object] +2026-05-06T21:34:06.421Z [DEBUG] [ + { + "id": 9233743419, + "node_id": "LA_kwDOPqtde88AAAACJl--Ow", + "url": "https://api.github.com/repos/jefeish-test1/safe-settings-config/labels/bug", + "name": "bug", + "color": "CC0000", + "default": true, + "description": "An issue with the system" + }, + { + "id": 10882892904, + "node_id": "LA_kwDOPqtde88AAAACiKvEaA", + "url": "https://api.github.com/repos/jefeish-test1/safe-settings-config/labels/feature", + "name": "feature", + "color": "336699", + "default": false, + "description": "New functionality." + }, + { + "id": 10882893036, + "node_id": "LA_kwDOPqtde88AAAACiKvE7A", + "url": "https://api.github.com/repos/jefeish-test1/safe-settings-config/labels/first-timers-only", + "name": "first-timers-only", + "color": "326699", + "default": false, + "description": null + }, + { + "id": 10882893129, + "node_id": "LA_kwDOPqtde88AAAACiKvFSQ", + "url": "https://api.github.com/repos/jefeish-test1/safe-settings-config/labels/new-label", + "name": "new-label", + "color": "326699", + "default": false, + "description": null + } +] + + [ + { + "name": "bug", + "color": "CC0000", + "description": "An issue with the system" + }, + { + "name": "feature", + "color": "336699", + "description": "New functionality." + }, + { + "name": "first-timers-only", + "oldname": "Help Wanted", + "color": "326699" + }, + { + "name": "new-label", + "oldname": "Help Wanted", + "color": "326699" + } +] +2026-05-06T21:34:06.421Z [DEBUG] Adding name for oldname Help Wanted +2026-05-06T21:34:06.421Z [DEBUG] Results of comparing Labels diffable target [{"id":9233743419,"node_id":"LA_kwDOPqtde88AAAACJl--Ow","url":"https://api.github.com/repos/jefeish-test1/safe-settings-config/labels/bug","name":"bug","color":"CC0000","default":true,"description":"An issue with the system"},{"id":10882892904,"node_id":"LA_kwDOPqtde88AAAACiKvEaA","url":"https://api.github.com/repos/jefeish-test1/safe-settings-config/labels/feature","name":"feature","color":"336699","default":false,"description":"New functionality."},{"id":10882893036,"node_id":"LA_kwDOPqtde88AAAACiKvE7A","url":"https://api.github.com/repos/jefeish-test1/safe-settings-config/labels/first-timers-only","name":"first-timers-only","color":"326699","default":false,"description":null},{"id":10882893129,"node_id":"LA_kwDOPqtde88AAAACiKvFSQ","url":"https://api.github.com/repos/jefeish-test1/safe-settings-config/labels/new-label","name":"new-label","color":"326699","default":false,"description":null}] with source [{"name":"bug","color":"CC0000","description":"An issue with the system"},{"name":"feature","color":"336699","description":"New functionality."},{"name":"first-timers-only","oldname":"Help Wanted","color":"326699"},{"name":"new-label","oldname":"Help Wanted","color":"326699"}] is {"msg":"Changes found","additions":{},"modifications":[{"oldname":{"0":"H","1":"e","2":"l","3":"p","4":" ","5":"W","6":"a","7":"n","8":"t","9":"e","10":"d"},"name":"first-timers-only"},{"oldname":{"0":"H","1":"e","2":"l","3":"p","4":" ","5":"W","6":"a","7":"n","8":"t","9":"e","10":"d"},"name":"new-label"}],"deletions":{}} +2026-05-06T21:34:06.421Z [DEBUG] Adding name for oldname Help Wanted +2026-05-06T21:34:06.422Z [DEBUG] Updating labels for { + "name": "first-timers-only", + "oldname": "Help Wanted", + "color": "326699" +} { + "owner": "jefeish-test1", + "repo": "safe-settings-config", + "branch": "main" +} +2026-05-06T21:34:06.422Z [DEBUG] Updating labels for { + "name": "new-label", + "oldname": "Help Wanted", + "color": "326699" +} { + "owner": "jefeish-test1", + "repo": "safe-settings-config", + "branch": "main" +} +2026-05-06T21:34:06.442Z [ERROR] Error HttpError: Validation Failed: "User is not a member of the enterprise." - https://docs.github.com/rest/reference/repos#add-a-repository-collaborator in Collaborators for repo: {"owner":"jefeish-test1","repo":"safe-settings-config","branch":"main"} entries [{"username":"regpaco","permission":"push"},{"username":"beetlejuice","permission":"pull","exclude":["actions-demo"]},{"username":"thor","permission":"push","include":["actions-demo","another-repo"]}] +2026-05-06T21:34:06.523Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:34:06.523Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:34:07.064Z [DEBUG] Found repo with security settings {"enableVulnerabilityAlerts":true,"enableAutomatedSecurityFixes":true} +2026-05-06T21:34:07.064Z [DEBUG] Enabling Dependabot alerts for owner: jefeish-test and repo repo-173 +2026-05-06T21:34:07.064Z [DEBUG] Enabling Dependabot security updates for owner: jefeish-test and repo repo-173 +2026-05-06T21:34:07.375Z [DEBUG] repository.edited payload from {"login":"fabrikam-safe-settings[bot]","id":223158109,"node_id":"BOT_kgDODU0fXQ","avatar_url":"https://avatars.githubusercontent.com/b/5789?v=4","gravatar_id":"","url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D","html_url":"https://github.com/apps/fabrikam-safe-settings","followers_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/followers","following_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/repos","events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/fabrikam-safe-settings%5Bbot%5D/received_events","type":"Bot","user_view_type":"public","site_admin":false} +2026-05-06T21:34:07.375Z [DEBUG] Repository Edited by a Bot +2026-05-06T21:34:24.193Z [ERROR] retrieveSettingsFromOrgs error: Not Found - https://docs.github.com/rest/git/refs#get-a-reference +2026-05-06T21:34:24.196Z [ERROR] RequestError [HttpError]: Not Found - https://docs.github.com/rest/git/refs#get-a-reference + at /Users/jefeish/projects/safe-settings/node_modules/@octokit/request/dist-node/index.js:125:21 + at process.processTicksAndRejections (node:internal/process/task_queues:105:5) + at async sendRequestWithRetries (/Users/jefeish/projects/safe-settings/node_modules/octokit-auth-probot/node_modules/@octokit/auth-app/dist-node/index.js:411:12) + at async Job.doExecute (/Users/jefeish/projects/safe-settings/node_modules/bottleneck/light.js:405:18) { + status: 404, + response: { + url: 'https://api.github.com/repos/jefeish-training/safe-settings-config-master/git/ref/heads%2Fmain', + status: 404, + headers: { + 'access-control-allow-origin': '*', + 'access-control-expose-headers': 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset', + 'content-encoding': 'gzip', + 'content-security-policy': "default-src 'none'", + 'content-type': 'application/json; charset=utf-8', + date: 'Wed, 06 May 2026 21:34:24 GMT', + 'referrer-policy': 'origin-when-cross-origin, strict-origin-when-cross-origin', + server: 'github.com', + 'strict-transport-security': 'max-age=31536000; includeSubdomains; preload', + 'transfer-encoding': 'chunked', + vary: 'Accept-Encoding, Accept, X-Requested-With', + 'x-accepted-github-permissions': 'contents=read', + 'x-content-type-options': 'nosniff', + 'x-frame-options': 'deny', + 'x-github-api-version-selected': '2022-11-28', + 'x-github-media-type': 'github.v3; format=json', + 'x-github-request-id': 'FBA4:202FF2:47C6D22:432FA07:69FBB3E0', + 'x-ratelimit-limit': '15000', + 'x-ratelimit-remaining': '14995', + 'x-ratelimit-reset': '1778106545', + 'x-ratelimit-resource': 'core', + 'x-ratelimit-used': '5', + 'x-xss-protection': '0' + }, + data: { + message: 'Not Found', + documentation_url: 'https://docs.github.com/rest/git/refs#get-a-reference', + status: '404' + } + }, + request: { + method: 'GET', + url: 'https://api.github.com/repos/jefeish-training/safe-settings-config-master/git/ref/heads%2Fmain', + headers: { + accept: 'application/vnd.github.v3+json', + 'user-agent': 'probot/13.4.4 octokit-core.js/5.2.0 Node.js/23', + authorization: 'token [REDACTED]' + }, + request: { hook: [Function: bound bound register] } + } +} +2026-05-06T21:40:04.044Z [ERROR] retrieveSettingsFromOrgs error: Hub repository jefeish-training/safe-settings-config-master or branch 'main' not found. Please ensure the repository exists and has a 'main' branch. +2026-05-06T21:40:04.046Z [ERROR] Error: Hub repository jefeish-training/safe-settings-config-master or branch 'main' not found. Please ensure the repository exists and has a 'main' branch. + at retrieveSettingsFromOrgs (/Users/jefeish/projects/safe-settings/lib/hubSyncHandler.js:521:15) + at async /Users/jefeish/projects/safe-settings/lib/routes.js:600:23 +2026-05-06T21:42:19.178Z [INFO] Starting commit and sync status fetch for copilot-for-emus,decyjphr-emu,decyjphr-training,jefeish-test,jefeish-test1,jefeish-training organizations... +2026-05-06T21:42:21.157Z [DEBUG] 2. [SYNC DEBUG] Hub file branch/ref for org jefeish-test: main +2026-05-06T21:42:21.157Z [DEBUG] 1. [SYNC DEBUG] Hub file path for org jefeish-test: .github/safe-settings/organizations/jefeish-test +2026-05-06T21:42:21.157Z [DEBUG] 3. [SYNC DEBUG] Org: jefeish-test +2026-05-06T21:42:21.372Z [DEBUG] 5. [SYNC DEBUG] Hub: jefeish-training +2026-05-06T21:42:21.372Z [DEBUG] 4. [SYNC DEBUG] Org orgFilesResp file names: settings.yml +2026-05-06T21:42:21.372Z [DEBUG] 5a. [SYNC DEBUG] Fetching hub files for: + owner: jefeish-training, + repo: safe-settings-config-master, + path: .github/safe-settings/organizations/jefeish-test, + ref: main +2026-05-06T21:42:21.595Z [ERROR] 6a. [SYNC DEBUG] Error fetching hub files: HttpError: Not Found - https://docs.github.com/rest/repos/contents#get-repository-content +2026-05-06T21:42:21.596Z [WARN] 6b. [SYNC DEBUG] File name mismatch for org jefeish-test +2026-05-06T21:42:22.328Z [DEBUG] 1. [SYNC DEBUG] Hub file path for org jefeish-test1: .github/safe-settings/organizations/jefeish-test1 +2026-05-06T21:42:22.328Z [DEBUG] 3. [SYNC DEBUG] Org: jefeish-test1 +2026-05-06T21:42:22.328Z [DEBUG] 2. [SYNC DEBUG] Hub file branch/ref for org jefeish-test1: main +2026-05-06T21:42:22.543Z [DEBUG] 4. [SYNC DEBUG] Org orgFilesResp file names: README.md, repo.yml, settings.yml, suborg.yml +2026-05-06T21:42:22.543Z [DEBUG] 5. [SYNC DEBUG] Hub: jefeish-training +2026-05-06T21:42:22.543Z [DEBUG] 5a. [SYNC DEBUG] Fetching hub files for: + owner: jefeish-training, + repo: safe-settings-config-master, + path: .github/safe-settings/organizations/jefeish-test1, + ref: main +2026-05-06T21:42:22.748Z [ERROR] 6a. [SYNC DEBUG] Error fetching hub files: HttpError: Not Found - https://docs.github.com/rest/repos/contents#get-repository-content +2026-05-06T21:42:22.748Z [WARN] 6b. [SYNC DEBUG] File name mismatch for org jefeish-test1 +2026-05-06T21:43:07.996Z [WARN] Hub repository jefeish-training/safe-settings-config-master or branch 'main' not found +2026-05-06T21:43:10.801Z [WARN] Hub repository jefeish-training/safe-settings-config-master or branch 'main' not found +2026-05-06T21:43:49.984Z [INFO] Starting commit and sync status fetch for copilot-for-emus,decyjphr-emu,decyjphr-training,jefeish-test,jefeish-test1,jefeish-training organizations... +2026-05-06T21:43:51.920Z [DEBUG] 3. [SYNC DEBUG] Org: jefeish-test +2026-05-06T21:43:51.920Z [DEBUG] 2. [SYNC DEBUG] Hub file branch/ref for org jefeish-test: main +2026-05-06T21:43:51.920Z [DEBUG] 1. [SYNC DEBUG] Hub file path for org jefeish-test: .github/safe-settings/organizations/jefeish-test +2026-05-06T21:43:52.137Z [DEBUG] 4. [SYNC DEBUG] Org orgFilesResp file names: settings.yml +2026-05-06T21:43:52.137Z [DEBUG] 5a. [SYNC DEBUG] Fetching hub files for: + owner: jefeish-training, + repo: safe-settings-config-master, + path: .github/safe-settings/organizations/jefeish-test, + ref: main +2026-05-06T21:43:52.137Z [DEBUG] 5. [SYNC DEBUG] Hub: jefeish-training +2026-05-06T21:43:52.368Z [WARN] 6b. [SYNC DEBUG] File name mismatch for org jefeish-test +2026-05-06T21:43:52.368Z [ERROR] 6a. [SYNC DEBUG] Error fetching hub files: HttpError: Not Found - https://docs.github.com/rest/repos/contents#get-repository-content +2026-05-06T21:43:52.756Z [INFO] Starting commit and sync status fetch for copilot-for-emus,decyjphr-emu,decyjphr-training,jefeish-test,jefeish-test1,jefeish-training organizations... +2026-05-06T21:43:53.091Z [DEBUG] 1. [SYNC DEBUG] Hub file path for org jefeish-test1: .github/safe-settings/organizations/jefeish-test1 +2026-05-06T21:43:53.091Z [DEBUG] 2. [SYNC DEBUG] Hub file branch/ref for org jefeish-test1: main +2026-05-06T21:43:53.091Z [DEBUG] 3. [SYNC DEBUG] Org: jefeish-test1 +2026-05-06T21:43:53.324Z [DEBUG] 5. [SYNC DEBUG] Hub: jefeish-training +2026-05-06T21:43:53.324Z [DEBUG] 5a. [SYNC DEBUG] Fetching hub files for: + owner: jefeish-training, + repo: safe-settings-config-master, + path: .github/safe-settings/organizations/jefeish-test1, + ref: main +2026-05-06T21:43:53.324Z [DEBUG] 4. [SYNC DEBUG] Org orgFilesResp file names: README.md, repo.yml, settings.yml, suborg.yml +2026-05-06T21:43:53.529Z [ERROR] 6a. [SYNC DEBUG] Error fetching hub files: HttpError: Not Found - https://docs.github.com/rest/repos/contents#get-repository-content +2026-05-06T21:43:53.530Z [WARN] 6b. [SYNC DEBUG] File name mismatch for org jefeish-test1 +2026-05-06T21:43:54.608Z [DEBUG] 2. [SYNC DEBUG] Hub file branch/ref for org jefeish-test: main +2026-05-06T21:43:54.608Z [DEBUG] 1. [SYNC DEBUG] Hub file path for org jefeish-test: .github/safe-settings/organizations/jefeish-test +2026-05-06T21:43:54.608Z [DEBUG] 3. [SYNC DEBUG] Org: jefeish-test +2026-05-06T21:43:54.822Z [DEBUG] 5. [SYNC DEBUG] Hub: jefeish-training +2026-05-06T21:43:54.821Z [DEBUG] 4. [SYNC DEBUG] Org orgFilesResp file names: settings.yml +2026-05-06T21:43:54.822Z [DEBUG] 5a. [SYNC DEBUG] Fetching hub files for: + owner: jefeish-training, + repo: safe-settings-config-master, + path: .github/safe-settings/organizations/jefeish-test, + ref: main +2026-05-06T21:43:55.019Z [ERROR] 6a. [SYNC DEBUG] Error fetching hub files: HttpError: Not Found - https://docs.github.com/rest/repos/contents#get-repository-content +2026-05-06T21:43:55.019Z [WARN] 6b. [SYNC DEBUG] File name mismatch for org jefeish-test +2026-05-06T21:43:55.675Z [DEBUG] 1. [SYNC DEBUG] Hub file path for org jefeish-test1: .github/safe-settings/organizations/jefeish-test1 +2026-05-06T21:43:55.675Z [DEBUG] 2. [SYNC DEBUG] Hub file branch/ref for org jefeish-test1: main +2026-05-06T21:43:55.675Z [DEBUG] 3. [SYNC DEBUG] Org: jefeish-test1 +2026-05-06T21:43:55.887Z [DEBUG] 5a. [SYNC DEBUG] Fetching hub files for: + owner: jefeish-training, + repo: safe-settings-config-master, + path: .github/safe-settings/organizations/jefeish-test1, + ref: main +2026-05-06T21:43:55.887Z [DEBUG] 5. [SYNC DEBUG] Hub: jefeish-training +2026-05-06T21:43:55.887Z [DEBUG] 4. [SYNC DEBUG] Org orgFilesResp file names: README.md, repo.yml, settings.yml, suborg.yml +2026-05-06T21:43:56.086Z [ERROR] 6a. [SYNC DEBUG] Error fetching hub files: HttpError: Not Found - https://docs.github.com/rest/repos/contents#get-repository-content +2026-05-06T21:43:56.086Z [WARN] 6b. [SYNC DEBUG] File name mismatch for org jefeish-test1 +2026-05-06T21:44:33.943Z [INFO] Starting commit and sync status fetch for copilot-for-emus,decyjphr-emu,decyjphr-training,jefeish-test,jefeish-test1,jefeish-training organizations... +2026-05-06T21:44:35.772Z [DEBUG] 3. [SYNC DEBUG] Org: jefeish-test +2026-05-06T21:44:35.772Z [DEBUG] 2. [SYNC DEBUG] Hub file branch/ref for org jefeish-test: main +2026-05-06T21:44:35.772Z [DEBUG] 1. [SYNC DEBUG] Hub file path for org jefeish-test: .github/safe-settings/organizations/jefeish-test +2026-05-06T21:44:35.979Z [DEBUG] 4. [SYNC DEBUG] Org orgFilesResp file names: settings.yml +2026-05-06T21:44:35.979Z [DEBUG] 5. [SYNC DEBUG] Hub: jefeish-training +2026-05-06T21:44:35.979Z [DEBUG] 5a. [SYNC DEBUG] Fetching hub files for: + owner: jefeish-training, + repo: safe-settings-config-master, + path: .github/safe-settings/organizations/jefeish-test, + ref: main +2026-05-06T21:44:36.178Z [ERROR] 6a. [SYNC DEBUG] Error fetching hub files: HttpError: Not Found - https://docs.github.com/rest/repos/contents#get-repository-content +2026-05-06T21:44:36.178Z [WARN] 6b. [SYNC DEBUG] File name mismatch for org jefeish-test +2026-05-06T21:44:36.845Z [DEBUG] 1. [SYNC DEBUG] Hub file path for org jefeish-test1: .github/safe-settings/organizations/jefeish-test1 +2026-05-06T21:44:36.845Z [DEBUG] 2. [SYNC DEBUG] Hub file branch/ref for org jefeish-test1: main +2026-05-06T21:44:36.845Z [DEBUG] 3. [SYNC DEBUG] Org: jefeish-test1 +2026-05-06T21:44:37.068Z [DEBUG] 5a. [SYNC DEBUG] Fetching hub files for: + owner: jefeish-training, + repo: safe-settings-config-master, + path: .github/safe-settings/organizations/jefeish-test1, + ref: main +2026-05-06T21:44:37.068Z [DEBUG] 5. [SYNC DEBUG] Hub: jefeish-training +2026-05-06T21:44:37.068Z [DEBUG] 4. [SYNC DEBUG] Org orgFilesResp file names: README.md, repo.yml, settings.yml, suborg.yml +2026-05-06T21:44:37.287Z [ERROR] 6a. [SYNC DEBUG] Error fetching hub files: HttpError: Not Found - https://docs.github.com/rest/repos/contents#get-repository-content +2026-05-06T21:44:37.287Z [WARN] 6b. [SYNC DEBUG] File name mismatch for org jefeish-test1 +2026-05-06T21:44:43.619Z [WARN] Hub repository jefeish-training/safe-settings-config-master or branch 'main' not found +2026-05-06T21:44:45.456Z [WARN] Hub repository jefeish-training/safe-settings-config-master or branch 'main' not found +2026-05-06T21:44:49.024Z [WARN] Hub repository jefeish-training/safe-settings-config-master or branch 'main' not found diff --git a/index.js b/index.js index f6af26b5a..265965183 100644 --- a/index.js +++ b/index.js @@ -6,11 +6,21 @@ const Glob = require('./lib/glob') const ConfigManager = require('./lib/configManager') const NopCommand = require('./lib/nopcommand') const env = require('./lib/env') +const { setupRoutes } = require('./lib/routes') +const { initCache } = require('./lib/installationCache') +const { hubSyncHandler } = require('./lib/hubSyncHandler') let deploymentConfig module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => { let appSlug = 'safe-settings' + + // Initialize all routes (static UI + API) via centralized module + setupRoutes(robot, getRouter) + + // Initialize installation cache (env-controlled prefetch) + initCache(robot) + async function syncAllSettings (nop, context, repo = context.repo(), ref) { try { deploymentConfig = await loadYamlFileSystem() @@ -521,6 +531,19 @@ module.exports = (robot, { getRouter }, Settings = require('./lib/settings')) => return createCheckRun(context, pull_request, payload.pull_request.head.sha, payload.pull_request.head.ref) }) + /** + * @description Handle pull_request.closed events to support hub synchronization + * @param {Object} context - The context object provided by Probot + */ + robot.on('pull_request.closed', async context => { + try { + await hubSyncHandler(robot, context) + } catch (err) { + robot.log.error(`pull_request.closed handler failed: ${err && err.message ? err.message : err}`) + } + return null + }) + robot.on(['check_suite.rerequested'], async context => { robot.log.debug('Check suite was rerequested!') return createCheckRun(context) diff --git a/lib/configManager.js b/lib/configManager.js index 58f5bb436..eb7c3710e 100644 --- a/lib/configManager.js +++ b/lib/configManager.js @@ -23,6 +23,11 @@ module.exports = class ConfigManager { this.log.error(`Error getting settings ${e}`) }) + // Return null if response is undefined (error occurred) + if (!response || !response.data) { + return null + } + // Ignore in case path is a folder // - https://developer.github.com/v3/repos/contents/#response-if-content-is-a-directory if (Array.isArray(response.data)) { diff --git a/lib/env.js b/lib/env.js index 94c0ea742..8bea61a73 100644 --- a/lib/env.js +++ b/lib/env.js @@ -1,5 +1,11 @@ module.exports = { ADMIN_REPO: process.env.ADMIN_REPO || 'admin', + SAFE_SETTINGS_HUB_REPO: process.env.SAFE_SETTINGS_HUB_REPO || 'admin-master', + SAFE_SETTINGS_HUB_ORG: process.env.SAFE_SETTINGS_HUB_ORG || 'admin-master-org', + SAFE_SETTINGS_HUB_DIRECT_PUSH: process.env.SAFE_SETTINGS_HUB_DIRECT_PUSH || 'false', + SAFE_SETTINGS_HUB_PATH: process.env.SAFE_SETTINGS_HUB_PATH || '.github/safe-settings', + APP_ID: process.env.APP_ID || null, + PRIVATE_KEY_PATH: process.env.PRIVATE_KEY_PATH || 'private-key.pem', CONFIG_PATH: process.env.CONFIG_PATH || '.github', SETTINGS_FILE_PATH: process.env.SETTINGS_FILE_PATH || 'settings.yml', DEPLOYMENT_CONFIG_FILE_PATH: process.env.DEPLOYMENT_CONFIG_FILE || 'deployment-settings.yml', diff --git a/lib/hubSyncHandler.js b/lib/hubSyncHandler.js new file mode 100644 index 000000000..621a36447 --- /dev/null +++ b/lib/hubSyncHandler.js @@ -0,0 +1,725 @@ +const { minimatch } = require('minimatch') +const env = require('./env') +const { getInstallations } = require('./installationCache') +const yaml = require('js-yaml') +const path = require('path') +const fs = require('fs') +const os = require('os') +const util = require('util') + +/** + * Attach a file-backed logger to robot.log that mirrors all log calls to a file. + * It preserves the original behavior and appends each log line to a file, trimming + * the file to the last `maxLines` entries (default 1000). + * + * Usage: call attachFileLogger(robot, { filePath: '/tmp/safe-settings.log', maxLines: 1000 }) + */ +function attachFileLogger (robot, options = {}) { + if (!robot || !robot.log) return + if (robot.log.__fileLoggerAttached) return + const filePath = options.filePath || process.env.SAFE_SETTINGS_LOG_FILE || path.join(process.cwd(), 'hubSyncHandler.log') + const maxLines = Number(options.maxLines || process.env.SAFE_SETTINGS_LOG_FILE_MAX_LINES || 1000) + const methods = ['info', 'warn', 'debug', 'error', 'fatal', 'trace', 'notice'] + + methods.forEach(method => { + const orig = (robot.log && robot.log[method]) ? robot.log[method].bind(robot.log) : (...args) => { /* no-op */ } + robot.log[method] = (...args) => { + // call original logger so console output still occurs + try { orig(...args) } catch (e) { /* swallow */ } + + // Build a single-line message representation + try { + const msg = args.map(a => (typeof a === 'string' ? a : util.inspect(a, { depth: 2 }))).join(' ') + const line = `${new Date().toISOString()} [${method.toUpperCase()}] ${msg}` + // append and then trim to last `maxLines` + fs.appendFile(filePath, line + os.EOL, err => { + if (err) { + try { orig(`Failed to append log to ${filePath}: ${err.message}`) } catch (e) { /* swallow */ } + return + } + // trim asynchronously + fs.promises.readFile(filePath, 'utf8').then(data => { + const lines = data.split(/\r?\n/) + // Remove a possible trailing empty line created by join + if (lines.length && lines[lines.length - 1] === '') lines.pop() + if (lines.length > maxLines) { + const tail = lines.slice(-maxLines) + return fs.promises.writeFile(filePath, tail.join(os.EOL) + os.EOL, 'utf8') + } + return Promise.resolve() + }).catch(() => { /* don't break logging on trim failures */ }) + }) + } catch (e) { + try { orig(`Failed to write log to ${filePath}: ${e && e.message ? e.message : e}`) } catch (e) { /* swallow */ } + } + } + }) + + robot.log.__fileLoggerAttached = true +} + +/** + * Get authenticated octokit client for an org installation + * @param {import('probot').Probot} robot + * @param {string} orgName + * @returns {Promise} Authenticated client or null + */ +async function getOrgInstallation (robot, orgName) { + const installs = await getInstallations(robot) + const install = installs.find(i => i.account && i.account.type === 'Organization' && i.account.login.toLowerCase() === orgName.toLowerCase()) + if (!install) { + return null + } + return await robot.auth(install.id) +} + + +// Helper to create a branch if not direct push +async function createBranchIfNeeded(githubClient, owner, repo, baseBranch, branchName, directPush, logger) { + if (!directPush) { + try { + const baseRef = await githubClient.rest.git.getRef({ owner, repo, ref: `heads/${baseBranch}` }) + const baseSha = baseRef.data.object.sha + await githubClient.rest.git.createRef({ owner, repo, ref: `refs/heads/${branchName}`, sha: baseSha }) + logger.info(`Created branch ${branchName} in ${owner}/${repo}`) + } catch (err) { + if (err.status === 422) { + logger.warn(`Branch ${branchName} already exists, continuing`) + } else { + throw err + } + } + } +} + +// Helper to create or update a file in a repo +async function createOrUpdateFile(githubClient, params, logger) { + try { + await githubClient.rest.repos.createOrUpdateFileContents(params) + logger.info(`Committed ${params.path} to ${params.owner}/${params.repo}@${params.branch}`) + } catch (err) { + logger.error(`Failed to sync file ${params.path}: ${err.message}`) + throw err + } +} + +/** + * Sync changed safe-settings organization files from the master admin PR + * into the target organization's admin repository. + * @param {import('probot').Probot} robot + * @param {import('probot').Context} context + * @param {string} orgName Destination organization login (also folder name under organizations/) + * @param {string} destRepo Destination repo name inside orgName (e.g. admin repo) + * @param {string} destinationFolder Base folder in destination repo where content lives (e.g. .github or .github/safe-settings) + */ +async function syncHubOrgUpdate (robot, context, orgName, destRepo, destinationFolder) { + attachFileLogger(robot) + try { + robot.log.info(`Syncing safe settings for organization: ${orgName}`) + robot.log.info(`Organization: ${orgName}, Destination Repo: ${destRepo}, Destination Folder: ${destinationFolder}`) + const pr = context.payload.pull_request + if (!pr) { + robot.log.warn('No pull_request payload found; aborting sync') + return + } + const { owner: srcOwner, repo: srcRepo } = context.repo() + const pull_number = pr.number + const configRoot = env.CONFIG_PATH || '.github/' + const sourceBase = (`${configRoot}/${env.SAFE_SETTINGS_HUB_PATH}/organizations`).replace(/\/$/, '') + robot.log.info(`DEBUG: sourceBase='${sourceBase}'`) + robot.log.info(`DEBUG: env.CONFIG_PATH='${env.CONFIG_PATH}', env.SAFE_SETTINGS_HUB_PATH='${env.SAFE_SETTINGS_HUB_PATH}'`) + const files = await context.octokit.paginate( + context.octokit.rest.pulls.listFiles, + { owner: srcOwner, repo: srcRepo, pull_number, per_page: 100 } + ) + robot.log.info(`DEBUG: PR #${pull_number} contains ${files.length} changed file(s)`) + if (files.length) robot.log.info(`DEBUG: files=${files.map(f => f.filename).join(', ')}`) + if (files.length) { + try { + robot.log.info(`DEBUG: first file object = ${JSON.stringify(files[0], null, 2)}`) + robot.log.info(`DEBUG: file[0] keys = ${Object.keys(files[0] || {}).join(', ')}`) + } catch (e) { + robot.log.info(`DEBUG: failed to stringify first file: ${e.message}`) + } + files.forEach((f, i) => { + try { + robot.log.info(`DEBUG: FILE[${i}] raw=${JSON.stringify(f)}`) + robot.log.info(`DEBUG: FILE[${i}] filename=${JSON.stringify(f.filename)} length=${(f.filename || '').length}`) + } catch (e) { + robot.log.info(`DEBUG: FILE[${i}] stringify error: ${e.message}`) + } + }) + } + const orgPrefix = `${sourceBase}/${orgName}/` + robot.log.info(`DEBUG: files=${files.map(f => f.filename).join(', ')}`) + robot.log.info(`DEBUG: Path ${sourceBase}/${orgName}`) + const relevant = files.filter(f => f.filename === `${sourceBase}/${orgName}` || f.filename.startsWith(orgPrefix)) + robot.log.info(`DEBUG: Found ${relevant.length} changed file(s) relevant to org ${orgName}`) + if (!relevant.length) { + robot.log.info(`No files for org ${orgName} in PR #${pull_number}`) + files.forEach(f => { + const exact = f.filename === `${sourceBase}/${orgName}` + const pref = f.filename.startsWith(orgPrefix) + robot.log.info(`MATCH CHECK: file='${f.filename}' exact=${exact} prefix=${pref}`) + }) + const altBase = `${(env.CONFIG_PATH || '.github').replace(/\/$/, '')}/organizations` + const altPrefix = `${altBase}/${orgName}/` + files.forEach(f => { + const exactAlt = f.filename === `${altBase}/${orgName}` + const prefAlt = f.filename.startsWith(altPrefix) + robot.log.info(`ALT CHECK: file='${f.filename}' exactAlt=${exactAlt} prefAlt=${prefAlt}`) + }) + return + } + const destOwner = orgName + const destBase = (destinationFolder || env.CONFIG_PATH || '.github').replace(/\/$/, '') + const destBaseBranch = 'main' + const directPush = (env.SAFE_SETTINGS_HUB_DIRECT_PUSH === 'true' || env.SAFE_SETTINGS_HUB_DIRECT_PUSH === '1') + const githubDest = await getOrgInstallation(robot, destOwner) + if (!githubDest) { + robot.log.warn(`Installation for destination org ${destOwner} not found; cannot sync`) + return + } + robot.log.info(`Syncing from ${srcOwner}/${srcRepo} PR #${pull_number} to ${destOwner}/${destRepo}@${destBaseBranch} under ${destBase} (directPush=${directPush})`) + const timestamp = Date.now() + const branchName = directPush ? destBaseBranch : `safe-settings-sync/pr-${pull_number}-${orgName}-${timestamp}` + await createBranchIfNeeded(githubDest, destOwner, destRepo, destBaseBranch, branchName, directPush, robot.log) + for (const f of relevant) { + let relative + if (f.filename === `${sourceBase}/${orgName}`) { + continue + } else { + relative = f.filename.slice(orgPrefix.length) + } + const destPath = `${destBase}/${relative}`.replace(/\/+/g, '/') + const srcContentResp = await context.octokit.rest.repos.getContent({ owner: srcOwner, repo: srcRepo, path: f.filename, ref: pr.head.sha }) + const data = srcContentResp.data + if (Array.isArray(data)) { + continue + } + const fileContent = Buffer.from(data.content, data.encoding).toString('utf8') + const encoded = Buffer.from(fileContent, 'utf8').toString('base64') + let existingSha + try { + const destGet = await githubDest.rest.repos.getContent({ owner: destOwner, repo: destRepo, path: destPath, ref: destBaseBranch }) + if (!Array.isArray(destGet.data)) existingSha = destGet.data.sha + } catch (getErr) { + if (getErr.status !== 404) throw getErr + } + await createOrUpdateFile(githubDest, { + owner: destOwner, + repo: destRepo, + path: destPath, + message: directPush ? `Direct sync safe-settings from ${srcOwner}/${srcRepo} PR #${pull_number}` : `Sync safe-settings from ${srcOwner}/${srcRepo} PR #${pull_number}`, + content: encoded, + branch: branchName, + sha: existingSha, + committer: { name: 'Safe Settings Bot', email: 'safe-settings-bot@example.com' }, + author: { name: 'Safe Settings Bot', email: 'safe-settings-bot@example.com' } + }, robot.log) + } + if (!directPush) { + try { + const prTitle = `Sync safe-settings from ${srcOwner}/${srcRepo} PR #${pull_number}` + const prBody = `Automated sync of safe-settings for ${orgName} from ${srcOwner}/${srcRepo} PR #${pull_number}.` + const created = await githubDest.rest.pulls.create({ owner: destOwner, repo: destRepo, title: prTitle, head: branchName, base: destBaseBranch, body: prBody }) + robot.log.info(`Created PR ${created.data.html_url} in ${destOwner}/${destRepo}`) + } catch (prErr) { + robot.log.error(`Failed to create PR in ${destOwner}/${destRepo}: ${prErr.message}`) + throw prErr + } + } else { + robot.log.info(`Changes pushed directly to ${destOwner}/${destRepo}@${destBaseBranch}`) + } + } catch (err) { + robot.log.error(`syncSafeSettingConfig error for org ${orgName}: ${err.message}`) + } +} + +/** + * Handle closed pull requests to sync safe-settings changes to target organizations. + * Focus on the organization and repository specified in the pull request and if they belong to the Safe-Settings Hub. + * @param {import('probot').Probot} robot + * @param {import('probot').Context} context + */ +async function hubSyncHandler (robot, context) { + attachFileLogger(robot) + const { payload } = context + const { repository, pull_request } = payload || {} + robot.log.info(`Received 'pull_request.closed' event: ${pull_request && pull_request.number}`) + try { + // Ensure the event is from the configured Safe-Settings Hub repo/org + const isMasterRepo = repository && repository.name === env.SAFE_SETTINGS_HUB_REPO + const isMasterOrg = repository && repository.owner && repository.owner.login === env.SAFE_SETTINGS_HUB_ORG + + if (!(isMasterRepo && isMasterOrg)) { + robot.log.info(`Pull request.closed is not from master admin repo/org (${env.SAFE_SETTINGS_HUB_ORG}/${env.SAFE_SETTINGS_HUB_REPO}), ignoring`) + return + } + + robot.log.info(`Pull request closed on Safe-Settings Hub: (${repository.full_name})`) + + // Get the PR details + const pr = pull_request + const { owner, repo } = context.repo() + const pull_number = pr.number + + // Paginate through all files changed in the PR + const files = await context.octokit.paginate( + context.octokit.rest.pulls.listFiles, + { owner, repo, pull_number, per_page: 100 } + ) + + robot.log.info(`Files changed in PR #${pull_number}: ${files.map(f => f.filename).join(', ')}`) + + // Routing logic: check for 'globals' or 'organizations' folder changes + const globalsChanged = files.some(f => /\/globals\//.test(f.filename)) + const orgsChanged = files.some(f => /\/organizations\//.test(f.filename)) + + if (globalsChanged) { + robot.log.debug('Detected changes in the globals folder. Routing to syncHubGlobalsUpdate(...).') + await module.exports.syncHubGlobalsUpdate(robot, context, files) + } + + if (orgsChanged) { + robot.log.debug('Detected changes in the organizations folder. Routing to syncHubOrgUpdate(...).') + // Only sync updates in organization subfolders, not files directly in organizations folder + const baseSettingsPath = `${(env.CONFIG_PATH || '.github').replace(/\/$/, '')}/${env.SAFE_SETTINGS_HUB_PATH}/organizations` + const normalizedBase = baseSettingsPath.replace(/\/$/, '') + const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + // Only match files in org subfolders: .../organizations//... + const orgSubfolderPattern = new RegExp(`^${escapeRegex(normalizedBase)}/([^/]+)/.+`) + const orgNamesSet = new Set() + files.forEach(f => { + const m = f.filename.match(orgSubfolderPattern) + if (m && m[1]) { + orgNamesSet.add(m[1]) + } + }) + const orgNames = Array.from(orgNamesSet) + robot.log.info(`Orgs updated in PR #${pull_number}: ${orgNames.join(', ')}`) + for (const orgName of orgNames) { + const destRepo = env.ADMIN_REPO + const destinationFolder = env.CONFIG_PATH || '.github' + await module.exports.syncHubOrgUpdate(robot, context, orgName, destRepo, destinationFolder) + } + } + } catch (err) { + robot.log.error(`Failed to sync safe settings: ${err && err.message ? err.message : err}`) + } +} + +/** + * Handle updates in the globals folder and sync to destinations defined in manifest.yml rules + * @param {import('probot').Probot} robot + * @param {import('probot').Context} context + * @param {Array} files - Array of changed file objects from PR + */ +async function syncHubGlobalsUpdate (robot, context, files) { + attachFileLogger(robot) + robot.log.info(`Syncing safe settings for 'globals/'.`) + const manifestPath = `${env.CONFIG_PATH}/${env.SAFE_SETTINGS_HUB_PATH}/globals/manifest.yml` + let manifest + try { + const resp = await context.octokit.repos.getContent({ + owner: env.SAFE_SETTINGS_HUB_ORG, + repo: env.SAFE_SETTINGS_HUB_REPO, + path: manifestPath, + ref: 'main' + }) + const manifestContent = Buffer.from(resp.data.content, resp.data.encoding).toString('utf8') + manifest = yaml.load(manifestContent) + robot.log.debug('Loaded manifest.yml rules from hub repo:' + JSON.stringify(manifest, null, 2)) + } catch (err) { + robot.log.error('Failed to load manifest.yml from hub repo:' + err.message) + return + } + const changedGlobals = files.filter(f => /\/globals\//.test(f.filename)) + if (!changedGlobals.length) { + robot.log.info('No changed files in globals folder.') + return + } + // Pre-filter rules for each file, and precompute orgs for each rule + const installs = await getInstallations(robot) + const orgLogins = installs.filter(i => i.account && i.account.type === 'Organization').map(i => i.account.login) + // Precompute matching rules for each fileName in changedGlobals + const fileNameToMatchingRules = {}; + for (const fileObj of changedGlobals) { + const fileName = fileObj.filename.split('/').pop(); + fileNameToMatchingRules[fileName] = (manifest.rules || []).filter(rule => + (rule.files || []).some(pattern => minimatch(fileName, pattern)) + ); + } + for (const fileObj of changedGlobals) { + const fileName = fileObj.filename.split('/').pop(); + if (fileName === 'manifest.yml') { + robot.log.debug(`Skipping sync for manifest.yml (should only exist in hub)`); + continue; + } + robot.log.debug(`Evaluating globals file: ${fileObj.filename}`); + // Use precomputed matching rules + const matchingRules = fileNameToMatchingRules[fileName]; + for (const rule of matchingRules) { + const mergeStrategy = rule.mergeStrategy || 'merge'; + // Precompute orgs to sync for each target pattern + let orgsToSync = []; + for (const orgPattern of rule.targets || []) { + if (orgPattern === '*') { + orgsToSync.push(...orgLogins); + } else if (orgPattern.endsWith('*')) { + const prefix = orgPattern.slice(0, -1); + orgsToSync.push(...orgLogins.filter(login => login.startsWith(prefix))); + } else { + orgsToSync.push(orgPattern); + } + } + // Remove duplicates + orgsToSync = Array.from(new Set(orgsToSync)); + robot.log.debug(`Rule '${rule.name}' matches file '${fileName}'. Targets: ${orgsToSync.join(', ')}`); + for (const orgName of orgsToSync) { + robot.log.debug(`Preparing to sync file '${fileName}' to org '${orgName}' with mergeStrategy='${mergeStrategy}'`); + const destRepo = env.ADMIN_REPO; + const githubDest = await getOrgInstallation(robot, orgName); + if (!githubDest) { + robot.log.info(`Skipping org ${orgName}: no installation found.`); + continue; + } + let repoExists = false; + try { + await githubDest.repos.get({ owner: orgName, repo: destRepo }); + repoExists = true; + } catch (err) { + if (err.status === 404) { + robot.log.info(`Skipping org ${orgName}: config repo '${destRepo}' does not exist.`); + continue; + } else { + throw err; + } + } + if (!repoExists) continue; + const destPath = `${env.CONFIG_PATH}/${fileName}`; + let exists = false; + let existingSha = undefined; + try { + robot.log.debug(`Checking existence of ${destPath} in ${orgName}/${destRepo}`); + const resp = await githubDest.repos.getContent({ + owner: orgName, + repo: destRepo, + path: destPath, + ref: 'main' + }); + if (!Array.isArray(resp.data)) { + robot.log.debug(`Found ${destPath} in ${orgName}/${destRepo}`); + exists = true; + existingSha = resp.data.sha; + } + } catch (err) { + if (err.status === 404) { + robot.log.info(`File ${destPath} not found in ${orgName}/${destRepo} (this is fine for both merge strategies)`); + exists = false; + existingSha = undefined; + } else { + robot.log.error(`Error checking ${destPath} in ${orgName}/${destRepo}: ${err.message}`); + throw err; + } + } + if (mergeStrategy === 'merge' && exists) { + robot.log.info(`Skipping sync of ${fileName} to ${orgName} (already exists & mergeStrategy=${mergeStrategy})`); + continue; + } + robot.log.info(`Syncing ${fileName} to ${orgName} (mergeStrategy=${mergeStrategy})`); + try { + let srcContentResp; + const pr = context.payload && context.payload.pull_request; + const srcRef = pr && pr.head && pr.head.sha ? pr.head.sha : 'main'; + srcContentResp = await context.octokit.repos.getContent({ + owner: env.SAFE_SETTINGS_HUB_ORG, + repo: env.SAFE_SETTINGS_HUB_REPO, + path: fileObj.filename, + ref: srcRef + }); + const data = srcContentResp.data; + if (Array.isArray(data)) { + robot.log.debug(`Skipping directory ${fileObj.filename}`); + continue; + } + const fileContent = Buffer.from(data.content, data.encoding).toString('utf8'); + const encoded = Buffer.from(fileContent, 'utf8').toString('base64'); + const destBaseBranch = 'main'; + const directPush = (env.SAFE_SETTINGS_HUB_DIRECT_PUSH === 'true' || env.SAFE_SETTINGS_HUB_DIRECT_PUSH === '1'); + const timestamp = Date.now(); + const branchName = directPush ? destBaseBranch : `safe-settings-globals-sync/${orgName}-${fileName}-${timestamp}`; + await createBranchIfNeeded(githubDest, orgName, destRepo, destBaseBranch, branchName, directPush, robot.log); + await createOrUpdateFile(githubDest, { + owner: orgName, + repo: destRepo, + path: destPath, + message: directPush ? `Direct sync globals file '${fileName}' from hub` : `Sync globals file '${fileName}' from hub`, + content: encoded, + branch: branchName, + sha: exists ? existingSha : undefined, + committer: { name: 'Safe Settings Bot', email: 'safe-settings-bot@example.com' }, + author: { name: 'Safe Settings Bot', email: 'safe-settings-bot@example.com' } + }, robot.log); + if (!directPush) { + try { + const prTitle = `Sync globals file '${fileName}' from hub`; + const prBody = `Automated sync of globals file '${fileName}' from hub to ${orgName}.`; + const created = await githubDest.rest.pulls.create({ owner: orgName, repo: destRepo, title: prTitle, head: branchName, base: destBaseBranch, body: prBody }); + robot.log.info(`Created PR ${created.data.html_url} in ${orgName}/${destRepo}`) + } catch (prErr) { + robot.log.error(`Failed to create PR in ${orgName}/${destRepo}: ${prErr.message}`) + throw prErr + } + } else { + robot.log.info(`Changes pushed directly to ${orgName}/${destRepo}@${destBaseBranch}`) + } + } catch (syncErr) { + robot.log.error(`Failed to sync globals file ${fileName} to ${orgName}: ${syncErr.message}`) + } + } + } + } +} + +/** + * Retrieve settings files from remote organization admin repositories, + * commit them into a branch in the hub repository, and open a pull request. + * @param {import('probot').Probot} robot + * @param {Array} orgNames Array of organization names to retrieve settings from + * @param {Object} options Options for the operation + * @param {string} options.baseBranch Base branch to create new branches from (default: 'main') + * @returns {Promise>} Results of the operation for each organization + */ +async function retrieveSettingsFromOrgs (robot, orgNames = [], options = {}) { + attachFileLogger(robot) + const results = [] + try { + if (!Array.isArray(orgNames) || orgNames.length === 0) return results + + const installs = await getInstallations(robot) + + const hubOwnerLogin = (env.SAFE_SETTINGS_HUB_ORG || '').toLowerCase() + const hubRepoName = env.SAFE_SETTINGS_HUB_REPO + if (!hubOwnerLogin || !hubRepoName) { + throw new Error('SAFE_SETTINGS_HUB_ORG and SAFE_SETTINGS_HUB_REPO must be configured') + } + + const hubInstall = installs.find(i => i.account && i.account.login && i.account.login.toLowerCase() === hubOwnerLogin) + if (!hubInstall) throw new Error(`Installation for hub org ${env.SAFE_SETTINGS_HUB_ORG} not found`) + + const githubHub = await robot.auth(hubInstall.id) + const baseBranch = options.baseBranch || 'main' + + // Resolve the base sha for creating branches + let baseRef, baseSha + try { + baseRef = await githubHub.rest.git.getRef({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: hubRepoName, ref: `heads/${baseBranch}` }) + baseSha = baseRef.data && baseRef.data.object && baseRef.data.object.sha + } catch (refErr) { + if (refErr && refErr.status === 404) { + // Hub repo doesn't exist - return N/A for all requested orgs + robot.log.warn(`Hub repository ${env.SAFE_SETTINGS_HUB_ORG}/${hubRepoName} or branch '${baseBranch}' not found`) + return orgNames.map(org => ({ org, status: 'N/A', reason: `hub_repo_not_found: ${env.SAFE_SETTINGS_HUB_ORG}/${hubRepoName}` })) + } + throw refErr + } + + // Helper: collect all files under a path in a repo (recursively) + async function collectFilesFromRepo (githubClient, owner, repo, dirPath, ref = 'main') { + const out = [] + + // First verify the repo exists by checking for the ref + try { + await githubClient.rest.git.getRef({ owner, repo, ref: `heads/${ref}` }) + } catch (repoCheckErr) { + if (repoCheckErr && repoCheckErr.status === 404) { + const err404 = new Error(`Repository ${owner}/${repo} or branch '${ref}' not found`) + err404.status = 404 + throw err404 + } + throw repoCheckErr + } + + async function walk (p) { + try { + const resp = await githubClient.repos.getContent({ owner, repo, path: p, ref }) + const data = resp.data + if (Array.isArray(data)) { + for (const item of data) { + if (item.type === 'file') { + try { + const fileResp = await githubClient.repos.getContent({ owner, repo, path: item.path, ref }) + if (!Array.isArray(fileResp.data) && typeof fileResp.data.content === 'string') { + const decoded = Buffer.from(fileResp.data.content, fileResp.data.encoding || 'base64').toString('utf8') + out.push({ path: fileResp.data.path, content: decoded }) + } + } catch (fe) { + // skip unreadable files, but log + robot.log && robot.log.warn && robot.log.warn(`collectFilesFromRepo: failed to fetch ${item.path} from ${owner}/${repo}: ${fe.message}`) + } + } else if (item.type === 'dir') { + await walk(item.path) + } else { + // skip other types (submodules, symlinks) + robot.log && robot.log.debug && robot.log.debug(`Skipping unsupported item type ${item.type} at ${item.path}`) + } + } + } else if (typeof data.content === 'string') { + const decoded = Buffer.from(data.content, data.encoding || 'base64').toString('utf8') + out.push({ path: data.path, content: decoded }) + } + } catch (e) { + if (e && e.status === 404) { + // path does not exist on repo -> no files + return + } + throw e + } + } + await walk(dirPath) + return out + } + + // Iterate requested orgs and import their CONFIG_PATH into the hub repo under the organizations/ tree + for (const orgName of orgNames) { + try { + if (!orgName) { results.push({ org: orgName, error: 'invalid org name' }); continue } + robot.log.info(`Retrieving settings from org: ${orgName}`) + + // fast existence check on the hub repo: skip if org folder already exists under CONFIG_PATH/SAFE_SETTINGS_HUB_PATH/organizations + try { + const destOrgPath = `${(env.CONFIG_PATH || '.github').replace(/\/$/, '')}/${env.SAFE_SETTINGS_HUB_PATH}/organizations/${orgName}` + try { + const destCheck = await githubHub.rest.repos.getContent({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: hubRepoName, path: destOrgPath, ref: baseBranch }) + if (Array.isArray(destCheck.data) && destCheck.data.length > 0) { + robot.log.info(`Skipping ${orgName}: already present in hub`) + results.push({ org: orgName, status: 'imported', reason: 'already_imported' }) + continue + } + } catch (probeErr) { + if (!(probeErr && probeErr.status === 404)) { + robot.log && robot.log.warn && robot.log.warn(`Failed to probe hub destination for ${orgName}: ${probeErr.message}`) + results.push({ org: orgName, error: `failed to check destination: ${probeErr.message}` }) + continue + } + + // 404 -> not present, proceed + } + } catch (e) { + robot.log && robot.log.warn && robot.log.warn(`Unexpected error while probing destination for ${orgName}: ${e.message}`) + results.push({ org: orgName, error: `probe error: ${e.message}` }) + continue + } + + const srcInstall = installs.find(i => i.account && i.account.login && i.account.login.toLowerCase() === orgName.toLowerCase()) + if (!srcInstall) { + results.push({ org: orgName, error: 'installation not found for org' }) + continue + } + + const githubSrc = await robot.auth(srcInstall.id) + const adminRepo = env.ADMIN_REPO + if (!adminRepo) { + results.push({ org: orgName, error: 'ADMIN_REPO is not configured' }) + continue + } + + const sourceBase = (env.CONFIG_PATH || '.github').replace(/\/$/, '') + // collect files from the source admin repo under CONFIG_PATH + let files + try { + files = await collectFilesFromRepo(githubSrc, orgName, adminRepo, sourceBase, 'main') + } catch (collectErr) { + if (collectErr && collectErr.status === 404) { + robot.log.info(`Skipping ${orgName}: admin repo '${adminRepo}' not found`) + results.push({ org: orgName, status: 'N/A', reason: `admin_repo_not_found: ${adminRepo}` }) + continue + } + throw collectErr + } + + if (!files || files.length === 0) { + results.push({ org: orgName, status: 'N/A', reason: 'no_files_at_config_path' }) + continue + } + + const timestamp = Date.now() + const branchName = `safe-settings-import/${orgName}/${timestamp}`.replace(/[^a-zA-Z0-9_\-./]/g, '-') + + // create branch in hub repo + try { + await githubHub.rest.git.createRef({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: hubRepoName, ref: `refs/heads/${branchName}`, sha: baseSha }) + } catch (createErr) { + if (createErr && createErr.status === 422) { + robot.log.info(`Branch ${branchName} already exists, continuing`) // continue + } else { + throw createErr + } + } + + // Instead of creating/updating files one-by-one, build a single tree and commit so the PR contains all files atomically + try { + const treeEntries = [] + for (const f of files) { + // relative path under the sourceBase + const rel = path.posix.relative(sourceBase, f.path) + // Destination should be: CONFIG_PATH/SAFE_SETTINGS_HUB_PATH/organizations// + const destBase = `${(env.CONFIG_PATH || '.github').replace(/\/$/, '')}/${env.SAFE_SETTINGS_HUB_PATH}` + const destPath = path.posix.join(destBase, 'organizations', orgName, rel).replace(/\/+/g, '/') + treeEntries.push({ path: destPath, mode: '100644', type: 'blob', content: f.content }) + } + + // Get base commit and tree + const baseCommitResp = await githubHub.rest.git.getCommit({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: hubRepoName, commit_sha: baseSha }) + const baseTreeSha = baseCommitResp.data && baseCommitResp.data.tree && baseCommitResp.data.tree.sha + + // Create a new tree rooted at the base tree + const createdTree = await githubHub.rest.git.createTree({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: hubRepoName, tree: treeEntries, base_tree: baseTreeSha }) + + // Create a commit that points to the new tree + const commitMessage = `Import safe-settings from ${orgName}` + const newCommit = await githubHub.rest.git.createCommit({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: hubRepoName, message: commitMessage, tree: createdTree.data.sha, parents: [baseSha] }) + + // Update the branch ref to point to the new commit + await githubHub.rest.git.updateRef({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: hubRepoName, ref: `heads/${branchName}`, sha: newCommit.data.sha }) + + robot.log.info(`Created commit ${newCommit.data.sha} on ${env.SAFE_SETTINGS_HUB_ORG}/${hubRepoName}@${branchName} with ${treeEntries.length} files`) + } catch (commitErr) { + robot.log.error(`Failed to create commit tree for ${orgName}: ${commitErr && commitErr.message ? commitErr.message : commitErr}`) + results.push({ org: orgName, error: `failed to commit files: ${commitErr && commitErr.message ? commitErr.message : String(commitErr)}` }) + continue + } + + // Create a PR in the hub repo for this branch + try { + const prTitle = `Import safe-settings from ${orgName}` + const prBody = `Automated import of settings from ${orgName} admin repo (${adminRepo}) into the hub.` + const created = await githubHub.rest.pulls.create({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: hubRepoName, title: prTitle, head: branchName, base: baseBranch, body: prBody }) + results.push({ org: orgName, pr: created.data && created.data.html_url }) + robot.log.info(`Created PR ${created.data && created.data.html_url} for ${orgName}`) + } catch (prErr) { + robot.log.error(`Failed to create PR for ${orgName}: ${prErr && prErr.message ? prErr.message : prErr}`) + results.push({ org: orgName, error: `failed to create PR: ${prErr && prErr.message ? prErr.message : String(prErr)}` }) + } + } catch (errInner) { + robot.log.error(`Error importing settings for org ${orgName}: ${errInner && errInner.message ? errInner.message : errInner}`) + results.push({ org: orgName, error: errInner && errInner.message ? errInner.message : String(errInner) }) + } + } + + return results + } catch (err) { + robot.log.error(`retrieveSettingsFromOrgs error: ${err && err.message ? err.message : err}`) + throw err + } +} + +// Export all internal functions for testability +module.exports = { + hubSyncHandler, + retrieveSettingsFromOrgs, + syncHubOrgUpdate, + syncHubGlobalsUpdate, + getOrgInstallation +} diff --git a/lib/installationCache.js b/lib/installationCache.js new file mode 100644 index 000000000..5ec98619e --- /dev/null +++ b/lib/installationCache.js @@ -0,0 +1,149 @@ +// Installation cache with TTL for GitHub App installations. +// Provides a hybrid approach: live refresh when stale, fast reads otherwise. + +let cachedInstallations = [] +let cachedOrgLogins = [] +let lastFetchedAt = null +let inFlightPromise = null + +/** + * Returns the TTL (time-to-live) in milliseconds for the installation cache. + * Reads from INSTALLATION_CACHE_TTL_MS env variable, defaults to 60s, minimum 5s. + */ +const DEFAULT_TTL_MS = 60_000 +function getTtlMs () { + const v = parseInt(process.env.INSTALLATION_CACHE_TTL_MS, 10) + return isNaN(v) || v < 5_000 ? DEFAULT_TTL_MS : v +} + +/** + * Fetches all GitHub App installations using the provided robot instance. + * Returns an array of installation objects. Uses pagination for large orgs. + * @param {Probot} robot - The Probot robot instance + * @param {Object} opts - Options (perPage) + * @returns {Promise} Array of installation objects + */ +async function fetchInstallations (robot, { perPage = 100 } = {}) { + const github = await robot.auth() + return github.paginate( + github.apps.listInstallations.endpoint.merge({ per_page: perPage }) + ) +} + +/** + * Refreshes the installation cache by fetching live installations from GitHub. + * Updates cachedInstallations, cachedOrgLogins, and lastFetchedAt. + * Ensures only one refresh is in flight at a time. + * @param {Probot} robot - The Probot robot instance + * @param {Object} opts - Options for fetchInstallations + * @returns {Promise} Array of installation objects + */ +async function refresh (robot, opts = {}) { + if (inFlightPromise) return inFlightPromise + inFlightPromise = (async () => { + try { + const installs = await fetchInstallations(robot, opts) + cachedInstallations = installs + cachedOrgLogins = installs + .filter(i => i.account && i.account.type === 'Organization') + .map(i => i.account.login) + .sort() + lastFetchedAt = new Date() + } catch (e) { + robot.log && robot.log.warn && robot.log.warn(`Installation cache refresh failed: ${e.message}`) + throw e + } finally { + inFlightPromise = null + } + return cachedInstallations + })() + return inFlightPromise +} + +/** + * Starts a prefetch of installations to warm up the cache at startup. + * Returns a promise for the refresh operation. + * @param {Probot} robot - The Probot robot instance + * @param {Object} opts - Options for refresh + * @returns {Promise} Array of installation objects + */ +function startPrefetch (robot, opts = {}) { + return refresh(robot, opts) +} + +/** + * Initialize cache (always prefetch once at startup) and log result. + */ + +/** + * Initializes the installation cache by prefetching installations at startup. + * Logs the result and returns true/false for success/failure. + * @param {Probot} robot - The Probot robot instance + * @returns {Promise} True if prefetch succeeded, false otherwise + */ +function initCache (robot) { + return startPrefetch(robot) + .then(installs => { + robot.log && robot.log.info && robot.log.info(`Installation cache prefetched ${installs.length} installs (${cachedOrgLogins.length} orgs) [TTL=${getTtlMs()}ms]`) + return true + }) + .catch(e => { + robot.log && robot.log.warn && robot.log.warn(`Installation cache prefetch failed: ${e.message}`) + return false + }) +} + +/** + * Ensures the cache is fresh by checking TTL and refreshing if stale. + * Called before serving cached installations to guarantee freshness. + * @param {Probot} robot - The Probot robot instance + */ +async function ensureFresh (robot) { + const ttl = getTtlMs() + if (!lastFetchedAt || (Date.now() - lastFetchedAt.getTime()) > ttl) { + try { await refresh(robot) } catch (_) { /* stale ok */ } + } +} + +/** + * Returns the cached installations, refreshing if the cache is stale. + * Always returns a copy of the cached array. + * @param {Probot} robot - The Probot robot instance + * @returns {Promise} Array of installation objects + */ +async function getInstallations (robot) { + await ensureFresh(robot) + return cachedInstallations.slice() +} + +/** + * Returns a copy of the cached organization logins (GitHub org names). + * @returns {Array} Array of org login strings + */ +function getOrgLogins () { return cachedOrgLogins.slice() } + +/** + * Returns the Date when installations were last fetched. + * @returns {Date|null} Last fetched date or null if never fetched + */ +function getLastFetchedAt () { return lastFetchedAt } + +/** + * Test-only helper: Forces the cache to appear stale on next access. + * Used for diagnostics and testing cache refresh logic. + */ +function __forceStale () { + lastFetchedAt = new Date(Date.now() - (getTtlMs() + 10_000)) +} + +module.exports = { + startPrefetch, + initCache, + refresh, + getInstallations, + getOrgLogins, + getLastFetchedAt, + // for tests / diagnostics + _debug: () => ({ size: cachedInstallations.length, lastFetchedAt }), + __forceStale +} diff --git a/lib/mergeDeep.js b/lib/mergeDeep.js index ab278e5c2..28938ba1d 100644 --- a/lib/mergeDeep.js +++ b/lib/mergeDeep.js @@ -92,8 +92,8 @@ class MergeDeep { // So any property in the target that is not in the source is not treated as a deletion for (const key in source) { // Skip prototype pollution vectors - if (key === "__proto__" || key === "constructor") { - continue; + if (key === '__proto__' || key === 'constructor') { + continue } // Logic specific for Github // API response includes urls for resources, or other ignorable fields; we can ignore them diff --git a/lib/plugins/archive.js b/lib/plugins/archive.js index a481029c7..eb3d25c1e 100644 --- a/lib/plugins/archive.js +++ b/lib/plugins/archive.js @@ -1,86 +1,79 @@ -const NopCommand = require('../nopcommand'); +const NopCommand = require('../nopcommand') -function returnValue(shouldContinue, nop) { - return { shouldContinue, nopCommands: nop }; +function returnValue (shouldContinue, nop) { + return { shouldContinue, nopCommands: nop } } module.exports = class Archive { - constructor(nop, github, repo, settings, log) { - this.github = github; - this.repo = repo; - this.settings = settings; - this.log = log; - this.nop = nop; + constructor (nop, github, repo, settings, log) { + this.github = github + this.repo = repo + this.settings = settings + this.log = log + this.nop = nop } // Returns true if plugin application should continue, false otherwise - async sync() { + async sync () { // Fetch repository details using REST API const { data: repoDetails } = await this.github.repos.get({ - owner: this.repo.owner, - repo: this.repo.repo - }); + owner: this.repo.owner, + repo: this.repo.repo + }) if (typeof this.settings?.archived !== 'undefined') { - this.log.debug(`Checking if ${this.repo.owner}/${this.repo.repo} is archived`); - - this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is ${repoDetails.archived ? 'archived' : 'not archived'}`); + this.log.debug(`Checking if ${this.repo.owner}/${this.repo.repo} is archived`) + + this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is ${repoDetails.archived ? 'archived' : 'not archived'}`) if (repoDetails.archived) { if (this.settings.archived) { - this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} already archived, inform other plugins should not run.`); - return returnValue(false); - } - else { - this.log.debug(`Unarchiving ${this.repo.owner}/${this.repo.repo}`); + this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} already archived, inform other plugins should not run.`) + return returnValue(false) + } else { + this.log.debug(`Unarchiving ${this.repo.owner}/${this.repo.repo}`) if (this.nop) { - return returnValue(true, [new NopCommand(this.constructor.name, this.repo, this.github.repos.update.endpoint(this.settings), 'will unarchive')]); - } - else { + return returnValue(true, [new NopCommand(this.constructor.name, this.repo, this.github.repos.update.endpoint(this.settings), 'will unarchive')]) + } else { // Unarchive the repository using REST API const updateResponse = await this.github.repos.update({ owner: this.repo.owner, repo: this.repo.repo, archived: false - }); - this.log.debug(`Unarchive result ${JSON.stringify(updateResponse)}`); + }) + this.log.debug(`Unarchive result ${JSON.stringify(updateResponse)}`) - return returnValue(true); + return returnValue(true) } } - } - else { + } else { if (this.settings.archived) { - this.log.debug(`Archiving ${this.repo.owner}/${this.repo.repo}`); + this.log.debug(`Archiving ${this.repo.owner}/${this.repo.repo}`) if (this.nop) { - return returnValue(false, [new NopCommand(this.constructor.name, this.repo, this.github.repos.update.endpoint(this.settings), 'will archive')]); - } - else { + return returnValue(false, [new NopCommand(this.constructor.name, this.repo, this.github.repos.update.endpoint(this.settings), 'will archive')]) + } else { // Archive the repository using REST API const updateResponse = await this.github.repos.update({ owner: this.repo.owner, repo: this.repo.repo, archived: true - }); - this.log.debug(`Archive result ${JSON.stringify(updateResponse)}`); + }) + this.log.debug(`Archive result ${JSON.stringify(updateResponse)}`) - return returnValue(false); + return returnValue(false) } - } - else { - this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is not archived, ignoring.`); - return returnValue(true); + } else { + this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is not archived, ignoring.`) + return returnValue(true) } } - } - else { - if (repoDetails.archived) { - this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is archived, ignoring.`); - return returnValue(false); - } - else { - this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is not archived, proceed as usual.`); - return returnValue(true); - } + } else { + if (repoDetails.archived) { + this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is archived, ignoring.`) + return returnValue(false) + } else { + this.log.debug(`Repo ${this.repo.owner}/${this.repo.repo} is not archived, proceed as usual.`) + return returnValue(true) + } } } -}; +} diff --git a/lib/plugins/branches.js b/lib/plugins/branches.js index d28e2f905..80a32fb8c 100644 --- a/lib/plugins/branches.js +++ b/lib/plugins/branches.js @@ -5,10 +5,10 @@ const Overrides = require('./overrides') const ignorableFields = [] const previewHeaders = { accept: 'application/vnd.github.hellcat-preview+json,application/vnd.github.luke-cage-preview+json,application/vnd.github.zzzax-preview+json' } const overrides = { - 'contexts': { - 'action': 'reset', - 'type': 'array' - }, + contexts: { + action: 'reset', + type: 'array' + } } module.exports = class Branches extends ErrorStash { diff --git a/lib/plugins/environments.js b/lib/plugins/environments.js index 73bef0e0f..5f8044bd3 100644 --- a/lib/plugins/environments.js +++ b/lib/plugins/environments.js @@ -23,7 +23,7 @@ module.exports = class Environments extends Diffable { policies.push({ name: policy, type: 'branch' }) } else if (typeof policy === 'object' && Array.isArray(policy.names)) { policy.names.forEach(name => { - policies.push({ name: name, type: policy.type }) + policies.push({ name, type: policy.type }) }) } }) diff --git a/lib/plugins/overrides.js b/lib/plugins/overrides.js index 0030b1246..b6d68942d 100644 --- a/lib/plugins/overrides.js +++ b/lib/plugins/overrides.js @@ -74,23 +74,23 @@ module.exports = class Overrides extends ErrorStash { // - The POST method for rulesets (create) allows for one override only. static removeOverrides (overrides, source, existing) { Object.entries(overrides).forEach(([override, props]) => { - let sourceRefs = Overrides.getObjectRef(source, override) - let data = JSON.stringify(sourceRefs) + const sourceRefs = Overrides.getObjectRef(source, override) + const data = JSON.stringify(sourceRefs) if (data.includes('{{EXTERNALLY_DEFINED}}')) { - let existingRefs = Overrides.getObjectRef(existing, override) + const existingRefs = Overrides.getObjectRef(existing, override) sourceRefs.forEach(sourceRef => { if (existingRefs[0]) { sourceRef[override] = existingRefs[0][override] - } else if (props['action'] === 'delete') { - Overrides.removeTopLevelParent(source, sourceRef[override], props['parents']) + } else if (props.action === 'delete') { + Overrides.removeTopLevelParent(source, sourceRef[override], props.parents) delete sourceRef[override] - } else if (props['type'] === 'array') { + } else if (props.type === 'array') { sourceRef[override] = [] - } else if (props['type'] === 'dict') { + } else if (props.type === 'dict') { sourceRef[override] = {} } else { - throw new Error(`Unknown type ${props['type']} for ${override}`) + throw new Error(`Unknown type ${props.type} for ${override}`) } }) } diff --git a/lib/plugins/rulesets.js b/lib/plugins/rulesets.js index b77ead1bd..e1de0905b 100644 --- a/lib/plugins/rulesets.js +++ b/lib/plugins/rulesets.js @@ -4,11 +4,11 @@ const MergeDeep = require('../mergeDeep') const Overrides = require('./overrides') const ignorableFields = [] const overrides = { - 'required_status_checks': { - 'action': 'delete', - 'parents': 3, - 'type': 'dict' - }, + required_status_checks: { + action: 'delete', + parents: 3, + type: 'dict' + } } const version = { diff --git a/lib/routes.js b/lib/routes.js new file mode 100644 index 000000000..e85f99ca8 --- /dev/null +++ b/lib/routes.js @@ -0,0 +1,680 @@ +/** + * Router setup for Safe Settings UI & API endpoints + * Centralizes Express/Next asset & API wiring away from core app logic. + * + * Exports: + * setupRoutes(robot, getRouter) -> configured router + * + * Responsibilities: + * - Serve static exported Next.js UI (from ui/out) + * - Dashboard HTML entry points + * - JSON API endpoints + * + * This version removes dependency on robot-level cached installation getters + * (`robot.getCachedInstallations`, `robot.getOrganizationLogins`) and instead + * fetches installations live per request. If performance becomes an issue, + * a lightweight in-module memoization layer with short TTL can be reintroduced. + */ + +const path = require('path') +const util = require('util') +const fs = require('fs') +const express = require('express') +const env = require('./env') +const { getInstallations: cacheGetInstallations, getOrgLogins, getLastFetchedAt } = require('./installationCache') + +// Lightweight commit metadata cache (path+ref -> meta) with TTL to avoid +// repeated GitHub commit lookups across requests. +const COMMIT_META_TTL_MS = parseInt(process.env.COMMIT_META_TTL_MS || '300000') // 5m default +const _commitMetaCache = new Map() // key => { meta, expiresAt } +function getCachedCommitMeta (key) { + const entry = _commitMetaCache.get(key) + if (!entry) return null + if (Date.now() > entry.expiresAt) { _commitMetaCache.delete(key); return null } + return entry.meta +} +function setCachedCommitMeta (key, meta) { + _commitMetaCache.set(key, { meta, expiresAt: Date.now() + COMMIT_META_TTL_MS }) +} + +function setupRoutes (robot, getRouter) { + // Root-level mount + const router = getRouter('/') + + // Ensure JSON/urlencoded body parsing is enabled for API endpoints + router.use(express.json({ limit: '1mb' })) + router.use(express.urlencoded({ extended: true })) + + // Static assets: produced by Next export/build step (ui/out) + const rootDir = path.join(__dirname, '..') // lib -> project root + const uiPath = path.join(rootDir, 'ui', 'out') + router.use(express.static(uiPath)) + + // HTML entrypoints (exported files). Adjust if you move/rename pages. + // Redirect root route to /dashboard + router.get('/', (req, res) => { + res.sendFile(path.join(uiPath, 'dashboard.html')) + }) + + router.get('/dashboard', (req, res) => { + res.sendFile(path.join(uiPath, 'dashboard.html')) + }) + + router.get('/dashboard/organizations', (req, res) => { + res.sendFile(path.join(uiPath, 'dashboard', 'organizations.html')) + }) + + router.get('/dashboard/settings', (req, res) => { + res.sendFile(path.join(uiPath, 'dashboard', 'settings.html')) + }) + + router.get('/dashboard/safe-settings-hub', (req, res) => { + res.sendFile(path.join(uiPath, 'dashboard', 'safe-settings-hub.html')) + }) + + router.get('/dashboard/env', (req, res) => { + res.sendFile(path.join(uiPath, 'dashboard', 'env.html')) + }) + + router.get('/dashboard/help', (req, res) => { + res.sendFile(path.join(uiPath, 'dashboard', 'help.html')) + }) + + // Apple touch icon (silence 404s). Replace file logic if you add a real 180x180 asset. + const APPLE_TOUCH_ICON_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAALQAAAC0CAQAAAA9zQYyAAAAC0lEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==' // 180x180 transparent PNG + router.get('/apple-touch-icon.png', (req, res) => { + // If a real file exists at project root, serve it; otherwise fallback to embedded transparent PNG. + const filePath = path.join(rootDir, 'apple-touch-icon.png') + fs.access(filePath, fs.constants.R_OK, (err) => { + if (!err) { + return res.sendFile(filePath) + } + const buf = Buffer.from(APPLE_TOUCH_ICON_BASE64, 'base64') + res.setHeader('Content-Type', 'image/png') + res.setHeader('Cache-Control', 'public, max-age=86400, immutable') + res.send(buf) + }) + }) + + /** + * GET /api/safe-settings/installation + * Returns live organization installation metadata + optional last commit info. + * Query param: disableActivity=true to skip commit lookups (faster). + */ + router.get('/api/safe-settings/installation', async (req, res) => { + const disableActivity = req.query.disableActivity === 'true' + const includeActivity = !disableActivity + + const crypto = require('crypto') + function hashContent (str) { + return crypto.createHash('sha256').update(str || '').digest('hex') + } + + try { + const installs = await cacheGetInstallations(robot) + const orgLogins = getOrgLogins() + const orgInstalls = installs.filter(i => i.account && i.account.type === 'Organization') + const lastCommits = {} + const syncStatus = {} + let installationDtos + + if (includeActivity && env.ADMIN_REPO) { + const orgs = orgLogins + const limit = 1 // reduce concurrency for API rate safety + const queue = [...orgs] + robot.log.info(`Starting commit and sync status fetch for ${queue} organizations...`) + + const runners = [] + const runNext = async () => { + while (queue.length) { + const org = queue.shift() + try { + const install = installs.find(i => i.account && i.account.login.toLowerCase() === org.toLowerCase()) + if (!install) { + lastCommits[org] = { na: true, hasConfigRepo: false } + syncStatus[org] = false + continue + } + const githubOrg = await robot.auth(install.id) + let hasConfigRepo = false + try { + await githubOrg.repos.get({ owner: org, repo: env.ADMIN_REPO }) + hasConfigRepo = true + } catch (repoErr) { + if (repoErr.status === 404) { + hasConfigRepo = false + } else { + robot.log.warn(`Repo existence check error for ${org}/${env.ADMIN_REPO}: ${repoErr.message}`) + } + } + // --- SYNC CHECK --- + let isInSync = false + if (hasConfigRepo) { + try { + const hubOrgDir = `${env.CONFIG_PATH}/${env.SAFE_SETTINGS_HUB_PATH}/organizations/${org}` + const hubRef = 'main' + robot.log.debug(`1. [SYNC DEBUG] Hub file path for org ${org}: ${hubOrgDir}`) + robot.log.debug(`2. [SYNC DEBUG] Hub file branch/ref for org ${org}: ${hubRef}`) + let orgFilesResp, hubFilesResp + try { + robot.log.debug(`3. [SYNC DEBUG] Org: ${org}`) + orgFilesResp = await githubOrg.repos.getContent({ owner: org, repo: env.ADMIN_REPO, path: env.CONFIG_PATH }) + const orgNames = Array.isArray(orgFilesResp.data) + ? orgFilesResp.data.map(f => f.name).join(', ') + : (orgFilesResp.data && orgFilesResp.data.name ? orgFilesResp.data.name : '') + robot.log.debug(`4. [SYNC DEBUG] Org orgFilesResp file names: ${orgNames}`) + } catch (fetchErr) { + robot.log.error(`4a. [SYNC DEBUG] Error fetching org files: ${fetchErr.message}`) + orgFilesResp = { data: [] } + } + + try { + robot.log.debug(`5. [SYNC DEBUG] Hub: ${env.SAFE_SETTINGS_HUB_ORG}`) + robot.log.debug(`5a. [SYNC DEBUG] Fetching hub files for: \n owner: ${env.SAFE_SETTINGS_HUB_ORG}, \n repo: ${env.SAFE_SETTINGS_HUB_REPO}, \n path: ${hubOrgDir}, \n ref: ${hubRef}`) + hubFilesResp = await githubOrg.repos.getContent({ + owner: env.SAFE_SETTINGS_HUB_ORG, + repo: env.SAFE_SETTINGS_HUB_REPO, + path: hubOrgDir, + ref: hubRef + }) + const hubNames = Array.isArray(hubFilesResp.data) + ? hubFilesResp.data.map(f => f.name).join(', ') + : (hubFilesResp.data && hubFilesResp.data.name ? hubFilesResp.data.name : '') + robot.log.debug(`6. [SYNC DEBUG] Hub hubFilesResp file names: ${hubNames}`) + } catch (fetchErr) { + robot.log.error(`6a. [SYNC DEBUG] Error fetching hub files: ${fetchErr}`) + hubFilesResp = { data: [] } + } + + const orgFiles = Array.isArray(orgFilesResp.data) ? orgFilesResp.data.filter(f => f.type === 'file') : [] + const hubFiles = Array.isArray(hubFilesResp.data) ? hubFilesResp.data.filter(f => f.type === 'file') : ['a', 'b'] + + // Compare file names + const orgFileNames = orgFiles.map(f => f.name).sort() + const hubFileNames = hubFiles.map(f => f.name).sort() + + if (orgFileNames.length !== hubFileNames.length || orgFileNames.some((n, i) => n !== hubFileNames[i])) { + robot.log.warn(`6b. [SYNC DEBUG] File name mismatch for org ${org}`) + isInSync = false + } else { + // Compare file hashes + let allMatch = true + for (let i = 0; i < orgFiles.length; i++) { + const orgFile = orgFiles[i] + const hubFile = hubFiles[i] + robot.log.debug(`7. [SYNC DEBUG] Fetching file contents for org: ${org}, orgFile: ${orgFile.path}, hubFile: ${hubFile.path}`) + let orgContentResp, hubContentResp + try { + orgContentResp = await githubOrg.repos.getContent({ owner: org, repo: env.ADMIN_REPO, path: orgFile.path }).catch((e) => { robot.log.warn(`9. [SYNC DEBUG] Error fetching org file ${orgFile.path}: ${e.message}`); return { data: {} } }) + } catch (fetchErr) { + robot.log.error(`7a. [SYNC DEBUG] Error fetching org file ${orgFile.path}: ${fetchErr.message}`) + allMatch = false + break + } + try { + hubContentResp = await githubOrg.repos.getContent({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: env.SAFE_SETTINGS_HUB_REPO, path: hubFile.path }).catch((e) => { robot.log.warn(`10.[SYNC DEBUG] Error fetching hub file ${hubFile.path}: ${e.message}`); return { data: {} } }) + } catch (fetchErr) { + robot.log.error(`7b. [SYNC DEBUG] Error fetching hub file ${hubFile.path}: ${fetchErr.message}`) + allMatch = false + break + } + const orgContent = orgContentResp.data.content ? Buffer.from(orgContentResp.data.content, orgContentResp.data.encoding || 'base64').toString('utf8') : '' + const hubContent = hubContentResp.data.content ? Buffer.from(hubContentResp.data.content, hubContentResp.data.encoding || 'base64').toString('utf8') : '' + const orgHash = hashContent(orgContent) + const hubHash = hashContent(hubContent) + robot.log.debug(`8. [SYNC DEBUG] Comparing file: ${orgFile.name}`) + robot.log.debug(`9. [SYNC DEBUG] Org hash: ${orgHash}`) + robot.log.debug(`10. [SYNC DEBUG] Hub hash: ${hubHash}`) + if (orgHash !== hubHash) { + robot.log.debug(`11. [SYNC DEBUG] Hash mismatch for file ${orgFile.name} in org ${org}`) + allMatch = false + break + } + } + isInSync = allMatch + } + } catch (syncErr) { + robot.log.error(`[SYNC DEBUG] Sync check error for org ${org}: ${syncErr.message}`) + isInSync = false + } + } + syncStatus[org] = isInSync + // --- END SYNC CHECK --- + // Commit info (unchanged) + let commits + try { + const pathPrefix = `${env.CONFIG_PATH.replace(/\/$/, '')}/organizations/${org}` + commits = await githubOrg.repos.listCommits({ owner: org, repo: env.ADMIN_REPO, per_page: 1, path: pathPrefix }) + } catch (err) { + if (err.status === 404) { + lastCommits[org] = { na: true, hasConfigRepo } + continue + } + if (err.status === 409) { // empty repo + lastCommits[org] = { hasConfigRepo } + continue + } + robot.log.warn(`Commit lookup error for ${org}/${env.ADMIN_REPO}: ${err.message}`) + lastCommits[org] = { hasConfigRepo } + continue + } + if (Array.isArray(commits.data) && commits.data.length) { + const c = commits.data[0] + const committedAt = (c.commit && c.commit.author && c.commit.author.date) || null + const ageSeconds = committedAt ? Math.floor((Date.now() - new Date(committedAt).getTime()) / 1000) : null + lastCommits[org] = { sha: c.sha, committed_at: committedAt, message: c.commit && c.commit.message ? c.commit.message.split('\n')[0] : null, age_seconds: ageSeconds, hasConfigRepo } + } else { + lastCommits[org] = { hasConfigRepo } + } + } catch (loopErr) { + robot.log.warn(`Unexpected error gathering commit for org ${org}: ${loopErr.message}`) + lastCommits[org] = { hasConfigRepo: false } + syncStatus[org] = false + } + } + } + for (let i = 0; i < limit; i++) runners.push(runNext()) + await Promise.all(runners) + } + + // Now that lastCommits and syncStatus are populated, build installationDtos + installationDtos = orgInstalls.map(i => { + const orgKey = i.account.login + const commitInfo = lastCommits[orgKey] || {} + return { + id: i.id, + account: orgKey, + type: i.account.type, + created_at: i.created_at, + name: orgKey, + sha: commitInfo.sha, + committed_at: commitInfo.committed_at, + message: commitInfo.message, + age_seconds: commitInfo.age_seconds, + hasConfigRepo: typeof commitInfo.hasConfigRepo === 'boolean' ? commitInfo.hasConfigRepo : false, + isInSync: typeof syncStatus[orgKey] === 'boolean' ? syncStatus[orgKey] : false + } + }) + return res.json({ updatedAt: new Date().toISOString(), installations: installationDtos }) + } catch (e) { + robot.log && robot.log.error && robot.log.error(e) + res.status(500).json({ error: e.message || 'unexpected error' }) + } + }) + + /** + * GET /api/safe-settings/hub/contents/* + * Fetches a file or directory listing from the SAFE_SETTINGS_HUB_ORG / SAFE_SETTINGS_HUB_REPO + * under the configured CONFIG_PATH (default .github). + * + * Examples: + * /api/safe-settings/hub/contents/ -> list CONFIG_PATH root + * /api/safe-settings/hub/contents/repos/foo.yml -> get specific file + * /api/safe-settings/hub/contents/repos?ref=main -> list directory at ref + * /api/safe-settings/hub/contents?recursive=true&maxDepth=2&fetchContent=false -> recursive listing without file bodies + * Note: recursive now defaults to true. Pass recursive=false for single-level listing. + */ + async function hubContent (req, res) { + let fullPath, ref + try { + // Use cached installations (TTL-based freshness) + const installs = await cacheGetInstallations(robot) + const install = installs.find(i => i.account && i.account.type === 'Organization' && i.account.login.toLowerCase() === env.SAFE_SETTINGS_HUB_ORG.toLowerCase()) + if (!install) { + return res.status(404).json({ error: `Installation for org ${env.SAFE_SETTINGS_HUB_ORG} not found` }) + } + + const github = await robot.auth(install.id) + const wildcardPath = req.params[0] || '' // from the * in the route + ref = req.query.ref || 'main' + fullPath = wildcardPath ? path.posix.join(env.CONFIG_PATH, wildcardPath) : env.CONFIG_PATH + // recursive defaults to true unless explicitly disabled with recursive=false + const recursive = req.query.recursive !== 'false' + let maxDepth = parseInt(req.query.maxDepth, 5) + if (isNaN(maxDepth) || maxDepth < 1) maxDepth = 5 // safety default + if (maxDepth > 8) maxDepth = 5 // hard cap to avoid abuse + // Unified flag: fetchContent (default true). No other legacy params supported. + const fetchContent = req.query.fetchContent !== 'false' + + // Commit metadata fetch with global shared cache + per-request memoization + const perRequestCommitCache = new Map() + const fetchCommitMeta = async (p) => { + if (perRequestCommitCache.has(p)) return perRequestCommitCache.get(p) + const cacheKey = `${ref}::${p}` + const cached = getCachedCommitMeta(cacheKey) + if (cached) { perRequestCommitCache.set(p, cached); return cached } + let meta + try { + const commits = await github.repos.listCommits({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: env.SAFE_SETTINGS_HUB_REPO, per_page: 1, path: p }) + .then(r => Array.isArray(r.data) ? r.data : []) + if (commits.length) { + const c = commits[0] + const committedAt = c.commit && c.commit.author && c.commit.author.date + const ageSeconds = committedAt ? Math.floor((Date.now() - new Date(committedAt).getTime()) / 1000) : null + meta = { + lastCommitSha: c.sha, + lastCommitAt: committedAt, + lastCommitMessage: c.commit && c.commit.message ? c.commit.message.split('\n')[0] : null, + lastCommitAgeSeconds: ageSeconds + } + } else { + meta = { lastCommitSha: null, lastCommitAt: null, lastCommitMessage: null, lastCommitAgeSeconds: null } + } + } catch { + meta = { lastCommitSha: null, lastCommitAt: null, lastCommitMessage: null, lastCommitAgeSeconds: null } + } + setCachedCommitMeta(cacheKey, meta) + perRequestCommitCache.set(p, meta) + return meta + } + + // Helper to fetch a single file (returns null on failure) + const fetchFile = async (p) => { + try { + const fileResp = await github.repos.getContent({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: env.SAFE_SETTINGS_HUB_REPO, path: p, ref }) + if (Array.isArray(fileResp.data)) return null + // file + const commitMeta = await fetchCommitMeta(fileResp.data.path) + if (fetchContent && typeof fileResp.data.content === 'string') { + const decoded = Buffer.from(fileResp.data.content, fileResp.data.encoding || 'base64').toString('utf8') + return { + type: fileResp.data.type, + name: path.posix.basename(p), + path: fileResp.data.path, + sha: fileResp.data.sha, + size: fileResp.data.size, + encoding: 'utf8', + content: decoded, + originalEncoding: fileResp.data.encoding || 'base64', + ...commitMeta + } + } + // metadata-only response + return { + type: fileResp.data.type, + name: path.posix.basename(p), + path: fileResp.data.path, + sha: fileResp.data.sha, + size: fileResp.data.size, + content: null, + originalEncoding: fileResp.data.encoding || 'base64', + ...commitMeta + } + } catch (e) { + robot.log.warn(`Failed to fetch file ${p}: ${e.message}`) + return null + } + } + + // Recursive traversal with depth limiting and basic cycle protection + const seen = new Set() + // Concurrency limiter for directory entry processing + const MAX_DIR_CONCURRENCY = parseInt(process.env.DIR_ENTRY_CONCURRENCY || '6') + async function mapWithLimit (items, mapper) { + const out = [] + let i = 0 + const running = new Set() + async function run () { + if (i >= items.length) return + const idx = i++ + const p = Promise.resolve(mapper(items[idx], idx)).then(r => { out[idx] = r; running.delete(p) }) + running.add(p) + if (running.size >= MAX_DIR_CONCURRENCY) await Promise.race(running) + return run() + } + await run() + await Promise.all([...running]) + return out + } + + const traverseDir = async (dirPath, depth = 0) => { + if (depth >= maxDepth) { + const commitMeta = await fetchCommitMeta(dirPath) + return { type: 'dir', name: path.posix.basename(dirPath), path: dirPath, depth, truncated: true, entries: [], ...commitMeta } + } + if (seen.has(dirPath)) { + const commitMeta = await fetchCommitMeta(dirPath) + return { type: 'dir', name: path.posix.basename(dirPath), path: dirPath, depth, cycle: true, entries: [], ...commitMeta } + } + seen.add(dirPath) + let listing + try { + const resp = await github.repos.getContent({ owner: env.SAFE_SETTINGS_HUB_ORG, repo: env.SAFE_SETTINGS_HUB_REPO, path: dirPath, ref }) + if (!Array.isArray(resp.data)) { + // Not a directory; fetch as file instead + const f = await fetchFile(dirPath) + return f || { type: 'file', path: dirPath, error: 'unreadable' } + } + listing = resp.data + } catch (e) { + const commitMeta = await fetchCommitMeta(dirPath) + return { type: 'dir', name: path.posix.basename(dirPath), path: dirPath, error: e.status === 404 ? 'not_found' : e.message, entries: [], ...commitMeta } + } + + const entries = await mapWithLimit(listing, async (item) => { + if (item.type === 'file') { + if (fetchContent) { + const f = await fetchFile(item.path) + if (f) return f + const commitMeta = await fetchCommitMeta(item.path) + return { type: 'file', name: item.name, path: item.path, sha: item.sha, size: item.size, content: null, ...commitMeta } + } + const commitMeta = await fetchCommitMeta(item.path) + return { type: 'file', name: item.name, path: item.path, sha: item.sha, size: item.size, content: null, ...commitMeta } + } else if (item.type === 'dir') { + return traverseDir(item.path, depth + 1) + } + const commitMeta = await fetchCommitMeta(item.path) + return { type: item.type, name: item.name, path: item.path, unsupported: true, ...commitMeta } + }) + const commitMeta = await fetchCommitMeta(dirPath) + return { type: 'dir', name: path.posix.basename(dirPath), path: dirPath, depth, entries, ...commitMeta } + } + + let response + try { + response = await github.repos.getContent({ + owner: env.SAFE_SETTINGS_HUB_ORG, + repo: env.SAFE_SETTINGS_HUB_REPO, + path: fullPath, + ref + }) + } catch (apiError) { + robot.log.error(`GitHub API error details: status=${apiError.status}, message=${apiError.message}`) + if (apiError.response && apiError.response.data) { + robot.log.error(`GitHub API response: ${JSON.stringify(apiError.response.data)}`) + } + throw apiError + } + + const data = response.data + if (Array.isArray(data)) { + if (recursive) { + const tree = await traverseDir(fullPath, 0) + return res.json({ + recursive: true, + maxDepth, + ref, + fetchContent, + ...tree + }) + } else { + // non-recursive (original behavior) + const entries = await Promise.all(data.map(async d => { + if (d.type === 'file') { + if (fetchContent) { + const f = await fetchFile(d.path) + if (f) return f + } + return { + name: d.name, + path: d.path, + type: d.type, + sha: d.sha, + size: d.size, + content: null + } + } + return { + name: d.name, + path: d.path, + type: d.type, + sha: d.sha, + size: d.size, + content: null + } + })) + return res.json({ + type: 'dir', + path: fullPath, + entries, + ref, + fetchContent + }) + } + } + + if (typeof data.content === 'string') { + if (fetchContent) { + const decoded = Buffer.from(data.content, data.encoding || 'base64').toString('utf8') + return res.json({ + type: data.type, + path: data.path, + sha: data.sha, + size: data.size, + encoding: 'utf8', + content: decoded, + originalEncoding: data.encoding || 'base64', + ref, + fetchContent: true + }) + } + return res.json({ + type: data.type, + path: data.path, + sha: data.sha, + size: data.size, + content: null, + ref, + fetchContent: false + }) + } + // Unsupported type (symlink, submodule, etc.) + return res.status(415).json({ error: 'Unsupported content type returned by GitHub API' }) + } catch (e) { + if (e.status === 404) { + robot.log.error(`Hub content 404: ${env.SAFE_SETTINGS_HUB_ORG}/${env.SAFE_SETTINGS_HUB_REPO} path=${fullPath} ref=${ref}`) + return res.status(404).json({ + error: 'Not found', + details: { + org: env.SAFE_SETTINGS_HUB_ORG, + repo: env.SAFE_SETTINGS_HUB_REPO, + path: fullPath, + ref + } + }) + } + robot.log && robot.log.error && robot.log.error(e) + return res.status(500).json({ error: e.message || 'unexpected error' }) + } + } + + router.get('/api/safe-settings/hub/content', hubContent) + router.get('/api/safe-settings/hub/content/*', hubContent) + + /** + * GET /api/safe-settings/app/env + * Returns key/value pairs parsed from the project .env file excluding + * standard GitHub App infrastructure variables. + * Query params: + * includeInfra=true -> include normally excluded infrastructure vars + */ + router.get('/api/safe-settings/app/env', (req, res) => { + try { + // Define a blacklist of sensitive environment variable keys to exclude + const ENV_BLACKLIST = ['PRIVATE_KEY_PATH']; + const variables = Object.entries(env) + .filter(([key]) => !ENV_BLACKLIST.includes(key)) + .map(([key, value]) => ({ key, value })) + .sort((a, b) => a.key.localeCompare(b.key)); + return res.json({ updatedAt: new Date().toISOString(), count: variables.length, variables }); + } catch (e) { + robot.log && robot.log.error && robot.log.error(e); + return res.status(500).json({ error: e.message || 'unexpected error' }); + } + }) + + + // POST /api/safe-settings/hub/import + // Body: { orgs: ['org1','org2'] } + router.post('/api/safe-settings/hub/import', async (req, res) => { + try { + const body = req.body || {} + const orgs = Array.isArray(body.orgs) ? body.orgs : (body.org ? [body.org] : null) + if (!orgs || !orgs.length) { + return res.status(400).json({ error: 'Missing orgs in request body. Expected JSON { orgs: ["org1","org2"] }' }) + } + // lazy-require to avoid circular require issues during module load + const { retrieveSettingsFromOrgs } = require('./hubSyncHandler') + const results = await retrieveSettingsFromOrgs(robot, orgs) + // Always return 200 with results, even if some/all orgs failed + return res.json({ ok: true, results }) + } catch (e) { + robot.log && robot.log.error && robot.log.error(e) + // Return 200 with error indicator for UI instead of 500 + return res.status(200).json({ ok: false, error: e.message || 'unexpected error', results: [] }) + } + }) + + + // GET /api/safe-settings/hub/log + // Returns parsed log entries (JSON): [{ timestamp, level, message }, ...] + router.get('/api/safe-settings/hub/log', async (req, res) => { + const lines = parseInt(req.query.lines || process.env.SAFE_SETTINGS_LOG_FILE_MAX_LINES || '1000', 10) + const levelsQuery = req.query.levels // comma-separated e.g. 'ERROR,WARN' + const allowedLevels = levelsQuery ? new Set(String(levelsQuery).split(',').map(s => s.trim().toUpperCase()).filter(Boolean)) : null + + const candidates = [] + if (process.env.SAFE_SETTINGS_LOG_FILE) candidates.push(process.env.SAFE_SETTINGS_LOG_FILE) + candidates.push(path.join(rootDir, 'safe-settings.log')) + candidates.push(path.join(rootDir, '..', 'safe-settings.log')) + candidates.push(path.join(rootDir, 'ui', 'safe-settings.log')) + + let found = null + for (const p of candidates) { + if (!p) continue + try { + const st = await fs.promises.stat(p) + if (st && st.isFile()) { found = p; break } + } catch (e) { + // ignore + } + } + if (!found) return res.status(404).json({ error: 'Log file not found' }) + + try { + const data = await fs.promises.readFile(found, 'utf8') + const arr = data.split(/\r?\n/).filter(Boolean) + const tail = arr.slice(-lines) + const parsed = tail.map(line => { + // Expecting format: 2025-09-10T12:34:56.789Z [INFO] message + const m = line.match(/^(\d{4}-\d{2}-\d{2}T[^\s]+)\s+\[([A-Z]+)\]\s+(.*)$/) + if (m) { + return { timestamp: m[1], level: m[2], message: m[3], raw: line } + } + // fallback: try to extract level in brackets + const m2 = line.match(/\[([A-Z]+)\]\s*(.*)$/) + if (m2) return { timestamp: null, level: m2[1], message: m2[2], raw: line } + return { timestamp: null, level: 'UNKNOWN', message: line, raw: line } + }) + const filtered = allowedLevels ? parsed.filter(p => allowedLevels.has(String(p.level).toUpperCase())) : parsed + return res.json({ count: filtered.length, entries: filtered }) + } catch (err) { + return res.status(500).json({ error: err && err.message ? err.message : String(err) }) + } + }) + + return router +} + +module.exports = { setupRoutes } diff --git a/lib/settings.js b/lib/settings.js index 20e711672..47e3201ae 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -10,10 +10,10 @@ const env = require('./env') const CONFIG_PATH = env.CONFIG_PATH const eta = new Eta({ views: path.join(__dirname) }) const SCOPE = { ORG: 'org', REPO: 'repo' } // Determine if the setting is a org setting or repo setting -const yaml = require('js-yaml'); +const yaml = require('js-yaml') class Settings { - static fileCache = {}; + static fileCache = {} static async syncAll (nop, context, repo, config, ref) { const settings = new Settings(nop, context, repo, config, ref) @@ -170,10 +170,10 @@ class Settings { // remove duplicate rows in this.results this.results = this.results.filter((thing, index, self) => { - return index === self.findIndex((t) => { - return t.type === thing.type && t.repo === thing.repo && t.plugin === thing.plugin - }) + return index === self.findIndex((t) => { + return t.type === thing.type && t.repo === thing.repo && t.plugin === thing.plugin }) + }) let error = false // Different logic @@ -300,7 +300,7 @@ ${this.results.reduce((x, y) => { } } - async updateRepos(repo) { + async updateRepos (repo) { this.subOrgConfigs = this.subOrgConfigs || await this.getSubOrgConfigs() // Keeping this as is instead of doing an object assign as that would cause `Cannot read properties of undefined (reading 'startsWith')` error // Copilot code review would recoommend using object assign but that would cause the error @@ -368,7 +368,6 @@ ${this.results.reduce((x, y) => { } } - async updateAll () { // this.subOrgConfigs = this.subOrgConfigs || await this.getSubOrgConfigs(this.github, this.repo, this.log) // this.repoConfigs = this.repoConfigs || await this.getRepoConfigs(this.github, this.repo, this.log) @@ -791,14 +790,14 @@ ${this.results.reduce((x, y) => { * @param params Params to fetch the file with * @return The parsed YAML file */ - async loadYaml(filePath) { + async loadYaml (filePath) { try { const repo = { owner: this.repo.owner, repo: env.ADMIN_REPO } const params = Object.assign(repo, { path: filePath, ref: this.ref }) - const namespacedFilepath = `${this.repo.owner}/${filePath}`; + const namespacedFilepath = `${this.repo.owner}/${filePath}` // If the filepath already exists in the fileCache, add the etag to the params // to check if the file has changed @@ -898,7 +897,6 @@ ${this.results.reduce((x, y) => { } } - async getSubOrgRepositories (subOrgProperties) { const organizationName = this.repo.owner try { diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 000000000..e69de29bb diff --git a/package-lock.json b/package-lock.json index 92cf50ebd..6fb37db30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,14 @@ "license": "ISC", "dependencies": { "@apidevtools/json-schema-ref-parser": "^12.0.2", + "@octokit/auth-app": "^8.0.2", "@probot/adapter-aws-lambda-serverless": "^4.0.3", "deepmerge": "^4.3.1", "eta": "^3.5.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", - "minimatch": "^10.0.1", + "minimatch": "^10.0.3", + "next": "^15.5.2", "node-cron": "^3.0.2", "octokit": "^5.0.2", "probot": "^13.4.4", @@ -40,7 +42,8 @@ "nodemon": "^3.1.9", "npm-run-all": "^4.1.5", "smee-client": "^3.1.1", - "standard": "^17.1.2" + "standard": "^17.1.2", + "supertest": "^7.1.4" }, "engines": { "node": ">= 16.0.0" @@ -706,6 +709,16 @@ "node": ">=18" } }, + "node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -887,12 +900,451 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz", + "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.0" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz", + "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz", + "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz", + "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz", + "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz", + "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz", + "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz", + "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz", + "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz", + "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz", + "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz", + "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz", + "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz", + "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz", + "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz", + "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz", + "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz", + "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.4.4" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz", + "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz", + "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz", + "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@ioredis/commands": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==", "license": "MIT" }, + "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.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1701,21 +2153,168 @@ "node": ">=18" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } + "node_modules/@next/env": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.2.tgz", + "integrity": "sha512-Qe06ew4zt12LeO6N7j8/nULSOe3fMXE4dM6xgpBQNvdzyK1sv5y4oAP3bq4LamrvGCZtmRYnW8URFCeX5nFgGg==", + "license": "MIT" }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", + "node_modules/@next/swc-darwin-arm64": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.2.tgz", + "integrity": "sha512-8bGt577BXGSd4iqFygmzIfTYizHb0LGWqH+qgIF/2EDxS5JsSdERJKA8WgwDyNBZgTIIA4D8qUtoQHmxIIquoQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.2.tgz", + "integrity": "sha512-2DjnmR6JHK4X+dgTXt5/sOCu/7yPtqpYt8s8hLkHFK3MGkka2snTv3yRMdHvuRtJVkPwCGsvBSwmoQCHatauFQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.2.tgz", + "integrity": "sha512-3j7SWDBS2Wov/L9q0mFJtEvQ5miIqfO4l7d2m9Mo06ddsgUK8gWfHGgbjdFlCp2Ek7MmMQZSxpGFqcC8zGh2AA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.2.tgz", + "integrity": "sha512-s6N8k8dF9YGc5T01UPQ08yxsK6fUow5gG1/axWc1HVVBYQBgOjca4oUZF7s4p+kwhkB1bDSGR8QznWrFZ/Rt5g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.2.tgz", + "integrity": "sha512-o1RV/KOODQh6dM6ZRJGZbc+MOAHww33Vbs5JC9Mp1gDk8cpEO+cYC/l7rweiEalkSm5/1WGa4zY7xrNwObN4+Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.2.tgz", + "integrity": "sha512-/VUnh7w8RElYZ0IV83nUcP/J4KJ6LLYliiBIri3p3aW2giF+PAVgZb6mk8jbQSB3WlTai8gEmCAr7kptFa1H6g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.2.tgz", + "integrity": "sha512-sMPyTvRcNKXseNQ/7qRfVRLa0VhR0esmQ29DD6pqvG71+JdVnESJaHPA8t7bc67KD5spP3+DOCNLhqlEI2ZgQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.2.tgz", + "integrity": "sha512-W5VvyZHnxG/2ukhZF/9Ikdra5fdNftxI6ybeVKYvBPDtyx7x4jPPSNduUkfH5fo3zG0JQ0bPxgy41af2JX5D4Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, @@ -1753,68 +2352,6 @@ "node": ">= 20" } }, - "node_modules/@octokit/app/node_modules/@octokit/auth-app": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-8.0.1.tgz", - "integrity": "sha512-P2J5pB3pjiGwtJX4WqJVYCtNkcZ+j5T2Wm14aJAEIC3WJOrv12jvBley3G1U/XI8q9o1A7QMG54LiFED2BiFlg==", - "dependencies": { - "@octokit/auth-oauth-app": "^9.0.1", - "@octokit/auth-oauth-user": "^6.0.0", - "@octokit/request": "^10.0.2", - "@octokit/request-error": "^7.0.0", - "@octokit/types": "^14.0.0", - "toad-cache": "^3.7.0", - "universal-github-app-jwt": "^2.2.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/app/node_modules/@octokit/auth-oauth-app": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-9.0.1.tgz", - "integrity": "sha512-TthWzYxuHKLAbmxdFZwFlmwVyvynpyPmjwc+2/cI3cvbT7mHtsAW9b1LvQaNnAuWL+pFnqtxdmrU8QpF633i1g==", - "dependencies": { - "@octokit/auth-oauth-device": "^8.0.1", - "@octokit/auth-oauth-user": "^6.0.0", - "@octokit/request": "^10.0.2", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/app/node_modules/@octokit/auth-oauth-device": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-8.0.1.tgz", - "integrity": "sha512-TOqId/+am5yk9zor0RGibmlqn4V0h8vzjxlw/wYr3qzkQxl8aBPur384D1EyHtqvfz0syeXji4OUvKkHvxk/Gw==", - "dependencies": { - "@octokit/oauth-methods": "^6.0.0", - "@octokit/request": "^10.0.2", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/app/node_modules/@octokit/auth-oauth-user": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-6.0.0.tgz", - "integrity": "sha512-GV9IW134PHsLhtUad21WIeP9mlJ+QNpFd6V9vuPWmaiN25HEJeEQUcS4y5oRuqCm9iWDLtfIs+9K8uczBXKr6A==", - "dependencies": { - "@octokit/auth-oauth-device": "^8.0.1", - "@octokit/oauth-methods": "^6.0.0", - "@octokit/request": "^10.0.2", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, "node_modules/@octokit/app/node_modules/@octokit/auth-token": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", @@ -1877,28 +2414,6 @@ "node": ">= 20" } }, - "node_modules/@octokit/app/node_modules/@octokit/oauth-authorization-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-8.0.0.tgz", - "integrity": "sha512-7QoLPRh/ssEA/HuHBHdVdSgF8xNLz/Bc5m9fZkArJE5bb6NmVkDm3anKxXPmN1zh6b5WKZPRr3697xKT/yM3qQ==", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/app/node_modules/@octokit/oauth-methods": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-6.0.0.tgz", - "integrity": "sha512-Q8nFIagNLIZgM2odAraelMcDssapc+lF+y3OlcIPxyAU+knefO8KmozGqfnma1xegRDP4z5M73ABsamn72bOcA==", - "dependencies": { - "@octokit/oauth-authorization-url": "^8.0.0", - "@octokit/request": "^10.0.2", - "@octokit/request-error": "^7.0.0", - "@octokit/types": "^14.0.0" - }, - "engines": { - "node": ">= 20" - } - }, "node_modules/@octokit/app/node_modules/@octokit/openapi-types": { "version": "25.0.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.0.0.tgz", @@ -1978,156 +2493,325 @@ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==" }, - "node_modules/@octokit/app/node_modules/universal-github-app-jwt": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-2.2.2.tgz", - "integrity": "sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw==" - }, "node_modules/@octokit/app/node_modules/universal-user-agent": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==" }, "node_modules/@octokit/auth-app": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-6.1.3.tgz", - "integrity": "sha512-dcaiteA6Y/beAlDLZOPNReN3FGHu+pARD6OHfh3T9f3EO09++ec+5wt3KtGGSSs2Mp5tI8fQwdMOEnrzBLfgUA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-8.0.2.tgz", + "integrity": "sha512-dLTmmA9gUlqiAJZgozfOsZFfpN/OldH3xweb7lqSnngax5Rs+PfO5dDlokaBfc41H1xOtsLYV5QqR0DkBAtPmw==", "license": "MIT", "dependencies": { - "@octokit/auth-oauth-app": "^7.1.0", - "@octokit/auth-oauth-user": "^4.1.0", - "@octokit/request": "^8.3.1", - "@octokit/request-error": "^5.1.0", - "@octokit/types": "^13.1.0", - "deprecation": "^2.3.1", - "lru-cache": "npm:@wolfy1339/lru-cache@^11.0.2-patch.1", - "universal-github-app-jwt": "^1.1.2", - "universal-user-agent": "^6.0.0" + "@octokit/auth-oauth-app": "^9.0.1", + "@octokit/auth-oauth-user": "^6.0.0", + "@octokit/request": "^10.0.2", + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0", + "toad-cache": "^3.7.0", + "universal-github-app-jwt": "^2.2.0", + "universal-user-agent": "^7.0.0" }, "engines": { - "node": ">= 18" + "node": ">= 20" + } + }, + "node_modules/@octokit/auth-app/node_modules/@octokit/endpoint": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.0.tgz", + "integrity": "sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" } }, "node_modules/@octokit/auth-app/node_modules/@octokit/openapi-types": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz", - "integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==", + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", "license": "MIT" }, - "node_modules/@octokit/auth-app/node_modules/@octokit/types": { - "version": "13.8.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz", - "integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==", + "node_modules/@octokit/auth-app/node_modules/@octokit/request": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.3.tgz", + "integrity": "sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==", "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^23.0.1" + "@octokit/endpoint": "^11.0.0", + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" } }, - "node_modules/@octokit/auth-app/node_modules/lru-cache": { - "name": "@wolfy1339/lru-cache", - "version": "11.0.2-patch.1", - "resolved": "https://registry.npmjs.org/@wolfy1339/lru-cache/-/lru-cache-11.0.2-patch.1.tgz", - "integrity": "sha512-BgYZfL2ADCXKOw2wJtkM3slhHotawWkgIRRxq4wEybnZQPjvAp71SPX35xepMykTw8gXlzWcWPTY31hlbnRsDA==", - "license": "ISC", + "node_modules/@octokit/auth-app/node_modules/@octokit/request-error": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.0.tgz", + "integrity": "sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0" + }, "engines": { - "node": "18 >=18.20 || 20 || >=22" + "node": ">= 20" } }, + "node_modules/@octokit/auth-app/node_modules/@octokit/types": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", + "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^25.1.0" + } + }, + "node_modules/@octokit/auth-app/node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + }, "node_modules/@octokit/auth-oauth-app": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-7.1.0.tgz", - "integrity": "sha512-w+SyJN/b0l/HEb4EOPRudo7uUOSW51jcK1jwLa+4r7PA8FPFpoxEnHBHMITqCsc/3Vo2qqFjgQfz/xUUvsSQnA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-9.0.1.tgz", + "integrity": "sha512-TthWzYxuHKLAbmxdFZwFlmwVyvynpyPmjwc+2/cI3cvbT7mHtsAW9b1LvQaNnAuWL+pFnqtxdmrU8QpF633i1g==", "license": "MIT", "dependencies": { - "@octokit/auth-oauth-device": "^6.1.0", - "@octokit/auth-oauth-user": "^4.1.0", - "@octokit/request": "^8.3.1", - "@octokit/types": "^13.0.0", - "@types/btoa-lite": "^1.0.0", - "btoa-lite": "^1.0.0", - "universal-user-agent": "^6.0.0" + "@octokit/auth-oauth-device": "^8.0.1", + "@octokit/auth-oauth-user": "^6.0.0", + "@octokit/request": "^10.0.2", + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.0" }, "engines": { - "node": ">= 18" + "node": ">= 20" + } + }, + "node_modules/@octokit/auth-oauth-app/node_modules/@octokit/endpoint": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.0.tgz", + "integrity": "sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" } }, "node_modules/@octokit/auth-oauth-app/node_modules/@octokit/openapi-types": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz", - "integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==", + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", "license": "MIT" }, + "node_modules/@octokit/auth-oauth-app/node_modules/@octokit/request": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.3.tgz", + "integrity": "sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.0", + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/auth-oauth-app/node_modules/@octokit/request-error": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.0.tgz", + "integrity": "sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/@octokit/auth-oauth-app/node_modules/@octokit/types": { - "version": "13.8.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz", - "integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", + "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^23.0.1" + "@octokit/openapi-types": "^25.1.0" } }, + "node_modules/@octokit/auth-oauth-app/node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + }, "node_modules/@octokit/auth-oauth-device": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-6.1.0.tgz", - "integrity": "sha512-FNQ7cb8kASufd6Ej4gnJ3f1QB5vJitkoV1O0/g6e6lUsQ7+VsSNRHRmFScN2tV4IgKA12frrr/cegUs0t+0/Lw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-8.0.1.tgz", + "integrity": "sha512-TOqId/+am5yk9zor0RGibmlqn4V0h8vzjxlw/wYr3qzkQxl8aBPur384D1EyHtqvfz0syeXji4OUvKkHvxk/Gw==", "license": "MIT", "dependencies": { - "@octokit/oauth-methods": "^4.1.0", - "@octokit/request": "^8.3.1", - "@octokit/types": "^13.0.0", - "universal-user-agent": "^6.0.0" + "@octokit/oauth-methods": "^6.0.0", + "@octokit/request": "^10.0.2", + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.0" }, "engines": { - "node": ">= 18" + "node": ">= 20" + } + }, + "node_modules/@octokit/auth-oauth-device/node_modules/@octokit/endpoint": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.0.tgz", + "integrity": "sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" } }, "node_modules/@octokit/auth-oauth-device/node_modules/@octokit/openapi-types": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz", - "integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==", + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", "license": "MIT" }, + "node_modules/@octokit/auth-oauth-device/node_modules/@octokit/request": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.3.tgz", + "integrity": "sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.0", + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/auth-oauth-device/node_modules/@octokit/request-error": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.0.tgz", + "integrity": "sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/@octokit/auth-oauth-device/node_modules/@octokit/types": { - "version": "13.8.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz", - "integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", + "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^23.0.1" + "@octokit/openapi-types": "^25.1.0" } }, + "node_modules/@octokit/auth-oauth-device/node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + }, "node_modules/@octokit/auth-oauth-user": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-4.1.0.tgz", - "integrity": "sha512-FrEp8mtFuS/BrJyjpur+4GARteUCrPeR/tZJzD8YourzoVhRics7u7we/aDcKv+yywRNwNi/P4fRi631rG/OyQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-6.0.0.tgz", + "integrity": "sha512-GV9IW134PHsLhtUad21WIeP9mlJ+QNpFd6V9vuPWmaiN25HEJeEQUcS4y5oRuqCm9iWDLtfIs+9K8uczBXKr6A==", "license": "MIT", "dependencies": { - "@octokit/auth-oauth-device": "^6.1.0", - "@octokit/oauth-methods": "^4.1.0", - "@octokit/request": "^8.3.1", - "@octokit/types": "^13.0.0", - "btoa-lite": "^1.0.0", - "universal-user-agent": "^6.0.0" + "@octokit/auth-oauth-device": "^8.0.1", + "@octokit/oauth-methods": "^6.0.0", + "@octokit/request": "^10.0.2", + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.0" }, "engines": { - "node": ">= 18" + "node": ">= 20" + } + }, + "node_modules/@octokit/auth-oauth-user/node_modules/@octokit/endpoint": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.0.tgz", + "integrity": "sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" } }, "node_modules/@octokit/auth-oauth-user/node_modules/@octokit/openapi-types": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz", - "integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==", + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", "license": "MIT" }, + "node_modules/@octokit/auth-oauth-user/node_modules/@octokit/request": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.3.tgz", + "integrity": "sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.0", + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/auth-oauth-user/node_modules/@octokit/request-error": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.0.tgz", + "integrity": "sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/@octokit/auth-oauth-user/node_modules/@octokit/types": { - "version": "13.8.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz", - "integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", + "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^23.0.1" + "@octokit/openapi-types": "^25.1.0" } }, + "node_modules/@octokit/auth-oauth-user/node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + }, "node_modules/@octokit/auth-token": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", @@ -2248,50 +2932,6 @@ "node": ">= 20" } }, - "node_modules/@octokit/oauth-app/node_modules/@octokit/auth-oauth-app": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-9.0.1.tgz", - "integrity": "sha512-TthWzYxuHKLAbmxdFZwFlmwVyvynpyPmjwc+2/cI3cvbT7mHtsAW9b1LvQaNnAuWL+pFnqtxdmrU8QpF633i1g==", - "dependencies": { - "@octokit/auth-oauth-device": "^8.0.1", - "@octokit/auth-oauth-user": "^6.0.0", - "@octokit/request": "^10.0.2", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/oauth-app/node_modules/@octokit/auth-oauth-device": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-8.0.1.tgz", - "integrity": "sha512-TOqId/+am5yk9zor0RGibmlqn4V0h8vzjxlw/wYr3qzkQxl8aBPur384D1EyHtqvfz0syeXji4OUvKkHvxk/Gw==", - "dependencies": { - "@octokit/oauth-methods": "^6.0.0", - "@octokit/request": "^10.0.2", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/oauth-app/node_modules/@octokit/auth-oauth-user": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-6.0.0.tgz", - "integrity": "sha512-GV9IW134PHsLhtUad21WIeP9mlJ+QNpFd6V9vuPWmaiN25HEJeEQUcS4y5oRuqCm9iWDLtfIs+9K8uczBXKr6A==", - "dependencies": { - "@octokit/auth-oauth-device": "^8.0.1", - "@octokit/oauth-methods": "^6.0.0", - "@octokit/request": "^10.0.2", - "@octokit/types": "^14.0.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 20" - } - }, "node_modules/@octokit/oauth-app/node_modules/@octokit/auth-token": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", @@ -2354,28 +2994,6 @@ "node": ">= 20" } }, - "node_modules/@octokit/oauth-app/node_modules/@octokit/oauth-authorization-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-8.0.0.tgz", - "integrity": "sha512-7QoLPRh/ssEA/HuHBHdVdSgF8xNLz/Bc5m9fZkArJE5bb6NmVkDm3anKxXPmN1zh6b5WKZPRr3697xKT/yM3qQ==", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@octokit/oauth-app/node_modules/@octokit/oauth-methods": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-6.0.0.tgz", - "integrity": "sha512-Q8nFIagNLIZgM2odAraelMcDssapc+lF+y3OlcIPxyAU+knefO8KmozGqfnma1xegRDP4z5M73ABsamn72bOcA==", - "dependencies": { - "@octokit/oauth-authorization-url": "^8.0.0", - "@octokit/request": "^10.0.2", - "@octokit/request-error": "^7.0.0", - "@octokit/types": "^14.0.0" - }, - "engines": { - "node": ">= 20" - } - }, "node_modules/@octokit/oauth-app/node_modules/@octokit/openapi-types": { "version": "25.0.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.0.0.tgz", @@ -2426,45 +3044,91 @@ "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==" }, "node_modules/@octokit/oauth-authorization-url": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-6.0.2.tgz", - "integrity": "sha512-CdoJukjXXxqLNK4y/VOiVzQVjibqoj/xHgInekviUJV73y/BSIcwvJ/4aNHPBPKcPWFnd4/lO9uqRV65jXhcLA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-8.0.0.tgz", + "integrity": "sha512-7QoLPRh/ssEA/HuHBHdVdSgF8xNLz/Bc5m9fZkArJE5bb6NmVkDm3anKxXPmN1zh6b5WKZPRr3697xKT/yM3qQ==", "license": "MIT", "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/@octokit/oauth-methods": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-4.1.0.tgz", - "integrity": "sha512-4tuKnCRecJ6CG6gr0XcEXdZtkTDbfbnD5oaHBmLERTjTMZNi2CbfEHZxPU41xXLDG4DfKf+sonu00zvKI9NSbw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-6.0.0.tgz", + "integrity": "sha512-Q8nFIagNLIZgM2odAraelMcDssapc+lF+y3OlcIPxyAU+knefO8KmozGqfnma1xegRDP4z5M73ABsamn72bOcA==", "license": "MIT", "dependencies": { - "@octokit/oauth-authorization-url": "^6.0.2", - "@octokit/request": "^8.3.1", - "@octokit/request-error": "^5.1.0", - "@octokit/types": "^13.0.0", - "btoa-lite": "^1.0.0" + "@octokit/oauth-authorization-url": "^8.0.0", + "@octokit/request": "^10.0.2", + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0" }, "engines": { - "node": ">= 18" + "node": ">= 20" + } + }, + "node_modules/@octokit/oauth-methods/node_modules/@octokit/endpoint": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.0.tgz", + "integrity": "sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" } }, "node_modules/@octokit/oauth-methods/node_modules/@octokit/openapi-types": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz", - "integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==", + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", "license": "MIT" }, + "node_modules/@octokit/oauth-methods/node_modules/@octokit/request": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.3.tgz", + "integrity": "sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.0", + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/oauth-methods/node_modules/@octokit/request-error": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.0.tgz", + "integrity": "sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/@octokit/oauth-methods/node_modules/@octokit/types": { - "version": "13.8.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz", - "integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", + "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^23.0.1" + "@octokit/openapi-types": "^25.1.0" } }, + "node_modules/@octokit/oauth-methods/node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + }, "node_modules/@octokit/openapi-types": { "version": "20.0.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", @@ -3309,6 +3973,16 @@ "@opentelemetry/api": "^1.1.0" } }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", + "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, "node_modules/@prisma/instrumentation": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-5.22.0.tgz", @@ -3506,6 +4180,15 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@travi/any": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@travi/any/-/any-3.1.2.tgz", @@ -3675,9 +4358,9 @@ "dev": true }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", - "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", "license": "MIT", "dependencies": { "@types/ms": "*", @@ -4156,6 +4839,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4377,6 +5067,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, "node_modules/before-after-hook": { @@ -4443,15 +5134,6 @@ "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" }, - "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_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -4623,7 +5305,6 @@ "version": "1.0.30001615", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001615.tgz", "integrity": "sha512-1IpazM5G3r38meiae0bHRnPhz+CBQ3ZLqbQMtrg+AsTPKAXgW38JNsXkyZ+v8waCsDmPq87lmfun5Q2AGysNEQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4752,6 +5433,12 @@ "node": ">=6" } }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -4791,6 +5478,20 @@ "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", "dev": true }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -4804,7 +5505,38 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "devOptional": true + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT", + "optional": true }, "node_modules/colorette": { "version": "2.0.20", @@ -4857,6 +5589,16 @@ "node": ">=18" } }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4902,6 +5644,13 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, "node_modules/cosmiconfig": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", @@ -5124,11 +5873,12 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -5256,6 +6006,16 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -5265,6 +6025,17 @@ "node": ">=8" } }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -6726,6 +7497,24 @@ "node": ">= 6" } }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -9678,12 +10467,12 @@ } }, "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "1.0.1", + "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } @@ -10088,12 +10877,12 @@ } }, "node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { "node": "20 || >=22" @@ -10129,9 +10918,28 @@ "license": "MIT" }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } }, "node_modules/natural-compare": { "version": "1.4.0", @@ -10147,6 +10955,58 @@ "node": ">= 0.6" } }, + "node_modules/next": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.2.tgz", + "integrity": "sha512-H8Otr7abj1glFhbGnvUt3gz++0AF1+QoCXEBmd/6aKbfdFwrn0LpA836Ed5+00va/7HQSDD+mOoVhn3tNy3e/Q==", + "license": "MIT", + "dependencies": { + "@next/env": "15.5.2", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.5.2", + "@next/swc-darwin-x64": "15.5.2", + "@next/swc-linux-arm64-gnu": "15.5.2", + "@next/swc-linux-arm64-musl": "15.5.2", + "@next/swc-linux-x64-gnu": "15.5.2", + "@next/swc-linux-x64-musl": "15.5.2", + "@next/swc-win32-arm64-msvc": "15.5.2", + "@next/swc-win32-x64-msvc": "15.5.2", + "sharp": "^0.34.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -10586,6 +11446,172 @@ "@octokit/core": ">=5" } }, + "node_modules/octokit-auth-probot/node_modules/@octokit/auth-app": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-6.1.4.tgz", + "integrity": "sha512-QkXkSOHZK4dA5oUqY5Dk3S+5pN2s1igPjEASNQV8/vgJgW034fQWR16u7VsNOK/EljA00eyjYF5mWNxWKWhHRQ==", + "license": "MIT", + "dependencies": { + "@octokit/auth-oauth-app": "^7.1.0", + "@octokit/auth-oauth-user": "^4.1.0", + "@octokit/request": "^8.3.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.1.0", + "deprecation": "^2.3.1", + "lru-cache": "npm:@wolfy1339/lru-cache@^11.0.2-patch.1", + "universal-github-app-jwt": "^1.1.2", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/auth-app/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/auth-oauth-app": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-7.1.0.tgz", + "integrity": "sha512-w+SyJN/b0l/HEb4EOPRudo7uUOSW51jcK1jwLa+4r7PA8FPFpoxEnHBHMITqCsc/3Vo2qqFjgQfz/xUUvsSQnA==", + "license": "MIT", + "dependencies": { + "@octokit/auth-oauth-device": "^6.1.0", + "@octokit/auth-oauth-user": "^4.1.0", + "@octokit/request": "^8.3.1", + "@octokit/types": "^13.0.0", + "@types/btoa-lite": "^1.0.0", + "btoa-lite": "^1.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/auth-oauth-app/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/auth-oauth-device": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-6.1.0.tgz", + "integrity": "sha512-FNQ7cb8kASufd6Ej4gnJ3f1QB5vJitkoV1O0/g6e6lUsQ7+VsSNRHRmFScN2tV4IgKA12frrr/cegUs0t+0/Lw==", + "license": "MIT", + "dependencies": { + "@octokit/oauth-methods": "^4.1.0", + "@octokit/request": "^8.3.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/auth-oauth-device/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/auth-oauth-user": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-4.1.0.tgz", + "integrity": "sha512-FrEp8mtFuS/BrJyjpur+4GARteUCrPeR/tZJzD8YourzoVhRics7u7we/aDcKv+yywRNwNi/P4fRi631rG/OyQ==", + "license": "MIT", + "dependencies": { + "@octokit/auth-oauth-device": "^6.1.0", + "@octokit/oauth-methods": "^4.1.0", + "@octokit/request": "^8.3.1", + "@octokit/types": "^13.0.0", + "btoa-lite": "^1.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/auth-oauth-user/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/oauth-authorization-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-6.0.2.tgz", + "integrity": "sha512-CdoJukjXXxqLNK4y/VOiVzQVjibqoj/xHgInekviUJV73y/BSIcwvJ/4aNHPBPKcPWFnd4/lO9uqRV65jXhcLA==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/oauth-methods": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-4.1.0.tgz", + "integrity": "sha512-4tuKnCRecJ6CG6gr0XcEXdZtkTDbfbnD5oaHBmLERTjTMZNi2CbfEHZxPU41xXLDG4DfKf+sonu00zvKI9NSbw==", + "license": "MIT", + "dependencies": { + "@octokit/oauth-authorization-url": "^6.0.2", + "@octokit/request": "^8.3.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.0.0", + "btoa-lite": "^1.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/oauth-methods/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/octokit-auth-probot/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "license": "MIT" + }, + "node_modules/octokit-auth-probot/node_modules/lru-cache": { + "name": "@wolfy1339/lru-cache", + "version": "11.0.2-patch.1", + "resolved": "https://registry.npmjs.org/@wolfy1339/lru-cache/-/lru-cache-11.0.2-patch.1.tgz", + "integrity": "sha512-BgYZfL2ADCXKOw2wJtkM3slhHotawWkgIRRxq4wEybnZQPjvAp71SPX35xepMykTw8gXlzWcWPTY31hlbnRsDA==", + "license": "ISC", + "engines": { + "node": "18 >=18.20 || 20 || >=22" + } + }, + "node_modules/octokit-auth-probot/node_modules/universal-github-app-jwt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-1.2.0.tgz", + "integrity": "sha512-dncpMpnsKBk0eetwfN8D8OUHGfiDhhJ+mtsbMl+7PfW7mYjiH8LIcqRmYMtzYLgSh47HjfdBtrBwIQ/gizKR3g==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "^9.0.0", + "jsonwebtoken": "^9.0.2" + } + }, "node_modules/octokit/node_modules/@octokit/auth-token": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", @@ -11021,7 +12047,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -11280,6 +12305,34 @@ "node": ">= 0.4" } }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -11579,6 +12632,29 @@ "node": ">= 0.8" } }, + "node_modules/react": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.1" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -12006,6 +13082,13 @@ "node": ">=v12.22.7" } }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT", + "peer": true + }, "node_modules/secure-json-parse": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", @@ -12078,11 +13161,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, "node_modules/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", @@ -12157,6 +13235,62 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/sharp": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz", + "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.4", + "semver": "^7.7.2" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.3", + "@img/sharp-darwin-x64": "0.34.3", + "@img/sharp-libvips-darwin-arm64": "1.2.0", + "@img/sharp-libvips-darwin-x64": "1.2.0", + "@img/sharp-libvips-linux-arm": "1.2.0", + "@img/sharp-libvips-linux-arm64": "1.2.0", + "@img/sharp-libvips-linux-ppc64": "1.2.0", + "@img/sharp-libvips-linux-s390x": "1.2.0", + "@img/sharp-libvips-linux-x64": "1.2.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0", + "@img/sharp-linux-arm": "0.34.3", + "@img/sharp-linux-arm64": "0.34.3", + "@img/sharp-linux-ppc64": "0.34.3", + "@img/sharp-linux-s390x": "0.34.3", + "@img/sharp-linux-x64": "0.34.3", + "@img/sharp-linuxmusl-arm64": "0.34.3", + "@img/sharp-linuxmusl-x64": "0.34.3", + "@img/sharp-wasm32": "0.34.3", + "@img/sharp-win32-arm64": "0.34.3", + "@img/sharp-win32-ia32": "0.34.3", + "@img/sharp-win32-x64": "0.34.3" + } + }, + "node_modules/sharp/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==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -12271,6 +13405,23 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT", + "optional": true + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -12357,6 +13508,15 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-support": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", @@ -12824,6 +13984,77 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/superagent": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", + "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.1", + "cookiejar": "^2.1.4", + "debug": "^4.3.7", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.4", + "formidable": "^3.5.4", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz", + "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^10.2.3" + }, + "engines": { + "node": ">=14.18.0" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -13043,10 +14274,10 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", @@ -13219,14 +14450,10 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/universal-github-app-jwt": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-1.2.0.tgz", - "integrity": "sha512-dncpMpnsKBk0eetwfN8D8OUHGfiDhhJ+mtsbMl+7PfW7mYjiH8LIcqRmYMtzYLgSh47HjfdBtrBwIQ/gizKR3g==", - "license": "MIT", - "dependencies": { - "@types/jsonwebtoken": "^9.0.0", - "jsonwebtoken": "^9.0.2" - } + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-2.2.2.tgz", + "integrity": "sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw==", + "license": "MIT" }, "node_modules/universal-user-agent": { "version": "6.0.1", diff --git a/package.json b/package.json index e765fb80e..8c6aee56d 100644 --- a/package.json +++ b/package.json @@ -26,12 +26,14 @@ "license": "ISC", "dependencies": { "@apidevtools/json-schema-ref-parser": "^12.0.2", + "@octokit/auth-app": "^8.0.2", "@probot/adapter-aws-lambda-serverless": "^4.0.3", "deepmerge": "^4.3.1", "eta": "^3.5.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", - "minimatch": "^10.0.1", + "minimatch": "^10.0.3", + "next": "^15.5.2", "node-cron": "^3.0.2", "octokit": "^5.0.2", "probot": "^13.4.4", @@ -56,7 +58,8 @@ "nodemon": "^3.1.9", "npm-run-all": "^4.1.5", "smee-client": "^3.1.1", - "standard": "^17.1.2" + "standard": "^17.1.2", + "supertest": "^7.1.4" }, "standard": { "env": [ diff --git a/safe-settings.log b/safe-settings.log new file mode 100644 index 000000000..962c13d3d --- /dev/null +++ b/safe-settings.log @@ -0,0 +1,54 @@ +2025-09-11T01:43:41.125Z [INFO] Received 'pull_request.closed' event: 45 +2025-09-11T01:43:41.125Z [INFO] Pull request closed on Safe-Settings Hub: (jefeish-training/safe-settings-config-master) +2025-09-11T01:43:42.072Z [INFO] Files changed in PR #45: .github/safe-settings/globals/suborg.yml +2025-09-11T01:43:42.072Z [DEBUG] Detected changes in the globals folder. Routing to syncHubGlobalsUpdate(...). +2025-09-11T01:43:42.073Z [INFO] Syncing safe settings for 'globals/'. +2025-09-11T01:43:42.359Z [DEBUG] Loaded manifest.yml rules from hub repo:{ + "rules": [ + { + "name": "global-defaults", + "targets": [ + "*" + ], + "files": [ + "*.yml" + ], + "mergeStrategy": "merge" + }, + { + "name": "security-policies", + "targets": [ + "acme-*", + "foo-bar" + ], + "files": [ + "settings.yml" + ], + "mergeStrategy": "overwrite" + } + ] +} +2025-09-11T01:43:42.361Z [DEBUG] Evaluating globals file: .github/safe-settings/globals/suborg.yml +2025-09-11T01:43:42.361Z [DEBUG] Preparing to sync file 'suborg.yml' to org 'jetest99' with mergeStrategy='merge' +2025-09-11T01:43:42.361Z [DEBUG] Rule 'global-defaults' matches file 'suborg.yml'. Targets: jetest99, jefeish-training, jefeish-test1, copilot-for-emus, jefeish-migration-test, decyjphr-training, decyjphr-emu +2025-09-11T01:43:42.988Z [DEBUG] Checking existence of .github/suborg.yml in jetest99/safe-settings-config +2025-09-11T01:43:43.292Z [INFO] Skipping sync of suborg.yml to jetest99 (already exists & mergeStrategy=merge) +2025-09-11T01:43:43.292Z [DEBUG] Found .github/suborg.yml in jetest99/safe-settings-config +2025-09-11T01:43:43.292Z [DEBUG] Preparing to sync file 'suborg.yml' to org 'jefeish-training' with mergeStrategy='merge' +2025-09-11T01:43:43.773Z [DEBUG] Checking existence of .github/suborg.yml in jefeish-training/safe-settings-config +2025-09-11T01:43:44.077Z [DEBUG] Found .github/suborg.yml in jefeish-training/safe-settings-config +2025-09-11T01:43:44.078Z [INFO] Skipping sync of suborg.yml to jefeish-training (already exists & mergeStrategy=merge) +2025-09-11T01:43:44.078Z [DEBUG] Preparing to sync file 'suborg.yml' to org 'jefeish-test1' with mergeStrategy='merge' +2025-09-11T01:43:44.793Z [DEBUG] Checking existence of .github/suborg.yml in jefeish-test1/safe-settings-config +2025-09-11T01:43:45.082Z [DEBUG] Found .github/suborg.yml in jefeish-test1/safe-settings-config +2025-09-11T01:43:45.082Z [INFO] Skipping sync of suborg.yml to jefeish-test1 (already exists & mergeStrategy=merge) +2025-09-11T01:43:45.082Z [DEBUG] Preparing to sync file 'suborg.yml' to org 'copilot-for-emus' with mergeStrategy='merge' +2025-09-11T01:43:45.593Z [INFO] Skipping org copilot-for-emus: config repo 'safe-settings-config' does not exist. +2025-09-11T01:43:45.593Z [DEBUG] Preparing to sync file 'suborg.yml' to org 'jefeish-migration-test' with mergeStrategy='merge' +2025-09-11T01:43:46.208Z [DEBUG] Checking existence of .github/suborg.yml in jefeish-migration-test/safe-settings-config +2025-09-11T01:43:46.461Z [INFO] Skipping sync of suborg.yml to jefeish-migration-test (already exists & mergeStrategy=merge) +2025-09-11T01:43:46.461Z [DEBUG] Found .github/suborg.yml in jefeish-migration-test/safe-settings-config +2025-09-11T01:43:46.461Z [DEBUG] Preparing to sync file 'suborg.yml' to org 'decyjphr-training' with mergeStrategy='merge' +2025-09-11T01:43:46.897Z [INFO] Skipping org decyjphr-training: config repo 'safe-settings-config' does not exist. +2025-09-11T01:43:46.897Z [DEBUG] Preparing to sync file 'suborg.yml' to org 'decyjphr-emu' with mergeStrategy='merge' +2025-09-11T01:43:47.342Z [INFO] Skipping org decyjphr-emu: config repo 'safe-settings-config' does not exist. diff --git a/test/unit/index.test.js b/test/unit/index.test.js index feae42d95..b053e845f 100644 --- a/test/unit/index.test.js +++ b/test/unit/index.test.js @@ -1,16 +1,18 @@ const { Probot } = require('probot') const plugin = require('../../index') +jest.mock('../../lib/hubSyncHandler', () => ({ hubSyncHandler: jest.fn() })) +const { hubSyncHandler } = require('../../lib/hubSyncHandler') describe.skip('plugin', () => { let app, event, sync, github beforeEach(() => { class Octokit { - static defaults () { + static defaults() { return Octokit } - constructor () { + constructor() { this.config = { get: jest.fn().mockReturnValue({}) } @@ -19,7 +21,7 @@ describe.skip('plugin', () => { } } - auth () { + auth() { return this } } @@ -39,6 +41,8 @@ describe.skip('plugin', () => { sync = jest.fn() plugin(app, {}, { sync, FILE_NAME: '.github/settings.yml' }) + jest.clearAllMocks() + }) describe('with settings modified on master', () => { diff --git a/test/unit/lib/hubSyncHandler.test.js b/test/unit/lib/hubSyncHandler.test.js new file mode 100644 index 000000000..618d1f324 --- /dev/null +++ b/test/unit/lib/hubSyncHandler.test.js @@ -0,0 +1,106 @@ + +// Import the functions to test from the implementation file +const { hubSyncHandler, retrieveSettingsFromOrgs } = require('../../../lib/hubSyncHandler') + +// --- Mock dependencies --- +// Mock the env module to provide controlled environment variables for tests +jest.mock('../../../lib/env', () => ({ + SAFE_SETTINGS_HUB_ORG: 'test-org', // Simulate the hub org name + SAFE_SETTINGS_HUB_REPO: 'test-repo', // Simulate the hub repo name + ADMIN_REPO: 'admin-repo', // Simulate the admin repo name + CONFIG_PATH: '.github', // Simulate the config path + SAFE_SETTINGS_HUB_PATH: 'safe-settings', // Simulate the hub path + SAFE_SETTINGS_HUB_DIRECT_PUSH: 'true' // Simulate direct push mode +})) +// Mock the installationCache module to control installation lookups +jest.mock('../../../lib/installationCache', () => ({ + getInstallations: jest.fn() +})) + +// --- Create mock objects for robot and context --- +// Mock robot object with logging and auth methods +const mockRobot = { + log: { + info: jest.fn(), // Track info logs + warn: jest.fn(), // Track warning logs + error: jest.fn() // Track error logs + }, + auth: jest.fn() // Mock authentication method +} + +// Mock context object to simulate GitHub event payloads and API +const mockContext = { + payload: { + repository: { + name: 'test-repo', // Simulate repo name + owner: { login: 'test-org' }, // Simulate repo owner + full_name: 'test-org/test-repo' // Simulate full repo name + }, + pull_request: { number: 1, head: { sha: 'abc123' } } // Simulate pull request info + }, + repo: () => ({ owner: 'test-org', repo: 'test-repo' }), // Simulate repo lookup + octokit: { + paginate: jest.fn(), // Mock pagination for API calls + rest: { + pulls: { + listFiles: jest.fn() // Mock listFiles API + } + } + } +} + +// --- Unit tests for hubSyncHandler --- +describe('hubSyncHandler', () => { + // Test that hubSyncHandler ignores events from non-master repo/org + it('should ignore non-master repo/org', async () => { + const context = { ...mockContext, payload: { repository: { name: 'other', owner: { login: 'other' } } } } + await hubSyncHandler(mockRobot, context) + expect(mockRobot.log.info).toHaveBeenCalledWith(expect.stringContaining('ignoring')) + }) + + // Test routing for organizations folder changes + it('should call syncHubOrgUpdate for organizations folder changes', async () => { + const orgFile = '.github/safe-settings/organizations/acme/settings.yml' + const files = [{ filename: orgFile }] + const context = { + ...mockContext, + octokit: { ...mockContext.octokit, paginate: jest.fn().mockResolvedValue(files) }, + payload: { ...mockContext.payload, repository: { name: 'test-repo', owner: { login: 'test-org' }, full_name: 'test-org/test-repo' }, pull_request: { number: 1, head: { sha: 'abc123' } } } + } + const mod = require('../../../lib/hubSyncHandler') + // Spy on syncHubOrgUpdate + const spy = jest.spyOn(mod, 'syncHubOrgUpdate').mockImplementation(jest.fn()) + await mod.hubSyncHandler(mockRobot, context) + expect(spy).toHaveBeenCalledWith(mockRobot, context, 'acme', expect.anything(), expect.anything()) + spy.mockRestore() + }) + + // Test routing for globals folder changes + it('should call syncHubGlobalsUpdate for globals folder changes', async () => { + const globalsFile = '.github/safe-settings/globals/foo.yml' + const files = [{ filename: globalsFile }] + const context = { + ...mockContext, + octokit: { ...mockContext.octokit, paginate: jest.fn().mockResolvedValue(files) }, + payload: { ...mockContext.payload, repository: { name: 'test-repo', owner: { login: 'test-org' }, full_name: 'test-org/test-repo' }, pull_request: { number: 1, head: { sha: 'abc123' } } } + } + const mod = require('../../../lib/hubSyncHandler') + // Spy on syncHubGlobalsUpdate + const spy = jest.spyOn(mod, 'syncHubGlobalsUpdate').mockImplementation(jest.fn()) + await mod.hubSyncHandler(mockRobot, context) + expect(spy).toHaveBeenCalledWith(mockRobot, context, files) + spy.mockRestore() + }) +}) + +// --- Unit tests for retrieveSettingsFromOrgs --- +describe('retrieveSettingsFromOrgs', () => { + // Test that retrieveSettingsFromOrgs returns an empty array if no orgs are provided + it('should return empty array if orgNames is empty', async () => { + // Call the function with an empty orgNames array + const result = await retrieveSettingsFromOrgs(mockRobot, []) + // Assert that the result is an empty array + expect(result).toEqual([]) + }) + // Additional tests can be added here to cover error handling, file import, etc. +}) diff --git a/test/unit/lib/plugins/archive.test.js b/test/unit/lib/plugins/archive.test.js index 9f5804f0d..a0a58a550 100644 --- a/test/unit/lib/plugins/archive.test.js +++ b/test/unit/lib/plugins/archive.test.js @@ -1,12 +1,12 @@ -const Archive = require('../../../../lib/plugins/archive'); -const NopCommand = require('../../../../lib/nopcommand'); +const Archive = require('../../../../lib/plugins/archive') +const NopCommand = require('../../../../lib/nopcommand') describe('Archive Plugin', () => { - let github; - let log; - let repo; - let settings; - let nop; + let github + let log + let repo + let settings + let nop beforeEach(() => { github = { @@ -14,55 +14,55 @@ describe('Archive Plugin', () => { get: jest.fn(), update: jest.fn() } - }; + } log = { - debug: jest.fn(), - }; - repo = { owner: 'test-owner', repo: 'test-repo' }; - settings = {}; - nop = false; - }); + debug: jest.fn() + } + repo = { owner: 'test-owner', repo: 'test-repo' } + settings = {} + nop = false + }) it('should return false if the repository is archived and settings.archived is true', async () => { - github.repos.get.mockResolvedValue({ data: { archived: true } }); - settings.archived = true; + github.repos.get.mockResolvedValue({ data: { archived: true } }) + settings.archived = true - const archive = new Archive(nop, github, repo, settings, log); - const result = await archive.sync(); + const archive = new Archive(nop, github, repo, settings, log) + const result = await archive.sync() - expect(result.shouldContinue).toBe(false); - }); + expect(result.shouldContinue).toBe(false) + }) it('should return true if the repository is archived and settings.archived is false', async () => { - github.repos.get.mockResolvedValue({ data: { archived: true } }); - settings.archived = false; + github.repos.get.mockResolvedValue({ data: { archived: true } }) + settings.archived = false - const archive = new Archive(nop, github, repo, settings, log); - const result = await archive.sync(); + const archive = new Archive(nop, github, repo, settings, log) + const result = await archive.sync() - expect(result.shouldContinue).toBe(true); - expect(log.debug).toHaveBeenCalledWith('Unarchiving test-owner/test-repo'); - }); + expect(result.shouldContinue).toBe(true) + expect(log.debug).toHaveBeenCalledWith('Unarchiving test-owner/test-repo') + }) it('should return false if the repository is not archived and settings.archived is true', async () => { - github.repos.get.mockResolvedValue({ data: { archived: false } }); - settings.archived = true; + github.repos.get.mockResolvedValue({ data: { archived: false } }) + settings.archived = true - const archive = new Archive(nop, github, repo, settings, log); - const result = await archive.sync(); + const archive = new Archive(nop, github, repo, settings, log) + const result = await archive.sync() - expect(result.shouldContinue).toBe(false); - expect(log.debug).toHaveBeenCalledWith('Archiving test-owner/test-repo'); - }); + expect(result.shouldContinue).toBe(false) + expect(log.debug).toHaveBeenCalledWith('Archiving test-owner/test-repo') + }) it('should return true if the repository is not archived and settings.archived is false', async () => { - github.repos.get.mockResolvedValue({ data: { archived: false } }); - settings.archived = false; + github.repos.get.mockResolvedValue({ data: { archived: false } }) + settings.archived = false - const archive = new Archive(nop, github, repo, settings, log); - const result = await archive.sync(); + const archive = new Archive(nop, github, repo, settings, log) + const result = await archive.sync() - expect(result.shouldContinue).toBe(true); - expect(log.debug).toHaveBeenCalledWith('Repo test-owner/test-repo is not archived, ignoring.'); - }); -}); \ No newline at end of file + expect(result.shouldContinue).toBe(true) + expect(log.debug).toHaveBeenCalledWith('Repo test-owner/test-repo is not archived, ignoring.') + }) +}) diff --git a/test/unit/lib/plugins/environments.test.js b/test/unit/lib/plugins/environments.test.js index 31fbb1cdf..d9c974f1c 100644 --- a/test/unit/lib/plugins/environments.test.js +++ b/test/unit/lib/plugins/environments.test.js @@ -1,6 +1,6 @@ const { when } = require('jest-when') const Environments = require('../../../../lib/plugins/environments') -const NopCommand = require('../../../../lib/nopcommand'); +const NopCommand = require('../../../../lib/nopcommand') describe('Environments Plugin test suite', () => { let github @@ -312,7 +312,7 @@ describe('Environments Plugin test suite', () => { protected_branches: false, custom_branch_policies: [ { - names: ['main','dev'], + names: ['main', 'dev'], type: 'branch' }, { @@ -389,7 +389,7 @@ describe('Environments Plugin test suite', () => { name: environmentName, deployment_branch_policy: { protected_branches: false, - custom_branch_policies: ["main", "dev"] + custom_branch_policies: ['main', 'dev'] } } ], log, errors) @@ -841,7 +841,7 @@ describe('Environments Plugin test suite', () => { protected_branches: false, custom_branch_policies: [ { - names: ['main','dev'], + names: ['main', 'dev'], type: 'branch' }, { @@ -855,7 +855,7 @@ describe('Environments Plugin test suite', () => { name: 'deployment-branch-policy-custom_environment_legacy', deployment_branch_policy: { protected_branches: false, - custom_branch_policies: ["main", "dev"] + custom_branch_policies: ['main', 'dev'] } }, { @@ -1098,7 +1098,7 @@ describe('Environments Plugin test suite', () => { protected_branches: false, custom_branch_policies: [ { - names: ['main','dev'], + names: ['main', 'dev'], type: 'branch' }, { @@ -1112,7 +1112,7 @@ describe('Environments Plugin test suite', () => { name: 'deployment-branch-policy-custom_environment_legacy', deployment_branch_policy: { protected_branches: false, - custom_branch_policies: ["main", "dev"] + custom_branch_policies: ['main', 'dev'] } }, { @@ -1166,7 +1166,7 @@ describe('Environments Plugin test suite', () => { protected_branches: false, custom_branch_policies: [ { - names: ['main','dev'], + names: ['main', 'dev'], type: 'branch' }, { @@ -1180,7 +1180,7 @@ describe('Environments Plugin test suite', () => { name: 'new-deployment-branch-policy-custom-legacy', deployment_branch_policy: { protected_branches: false, - custom_branch_policies: ["main", "dev"] + custom_branch_policies: ['main', 'dev'] } }, { @@ -1396,37 +1396,37 @@ describe('Environments Plugin test suite', () => { }) describe('nopifyRequest', () => { - let github; - let plugin; - const org = 'bkeepers'; - const repo = 'test'; - const environment_name = 'test-environment'; - const url = 'PUT /repos/:org/:repo/environments/:environment_name'; - const options = { org, repo, environment_name, wait_timer: 1 }; - const description = 'Update environment wait timer'; + let github + let plugin + const org = 'bkeepers' + const repo = 'test' + const environment_name = 'test-environment' + const url = 'PUT /repos/:org/:repo/environments/:environment_name' + const options = { org, repo, environment_name, wait_timer: 1 } + const description = 'Update environment wait timer' beforeEach(() => { github = { request: jest.fn(() => Promise.resolve(true)) - }; - plugin = new Environments(undefined, github, { owner: org, repo }, [], { debug: jest.fn(), error: console.error }, []); - }); + } + plugin = new Environments(undefined, github, { owner: org, repo }, [], { debug: jest.fn(), error: console.error }, []) + }) it('should make a request when nop is false', async () => { - plugin.nop = false; + plugin.nop = false - await plugin.nopifyRequest(url, options, description); + await plugin.nopifyRequest(url, options, description) - expect(github.request).toHaveBeenCalledWith(url, options); - }); + expect(github.request).toHaveBeenCalledWith(url, options) + }) it('should return NopCommand when nop is true', async () => { - plugin.nop = true; + plugin.nop = true - const result = await plugin.nopifyRequest(url, options, description); + const result = await plugin.nopifyRequest(url, options, description) expect(result).toEqual([ new NopCommand('Environments', { owner: org, repo }, url, description) - ]); - }); -}); + ]) + }) +}) diff --git a/test/unit/lib/plugins/rulesets.test.js b/test/unit/lib/plugins/rulesets.test.js index f15abd63f..359799059 100644 --- a/test/unit/lib/plugins/rulesets.test.js +++ b/test/unit/lib/plugins/rulesets.test.js @@ -9,7 +9,7 @@ const repo_conditions = { ref_name: { include: ['~ALL'], exclude: [] - }, + } } const org_conditions = { ref_name: { @@ -17,18 +17,18 @@ const org_conditions = { exclude: [] }, repository_name: { - include: ["~ALL"], - exclude: ["admin"] + include: ['~ALL'], + exclude: ['admin'] } } -function generateRequestRuleset(id, name, conditions, checks, org=false) { +function generateRequestRuleset (id, name, conditions, checks, org = false) { request = { - id: id, - name: name, + id, + name, target: 'branch', enforcement: 'active', - conditions: conditions, + conditions, rules: [ { type: 'required_status_checks', @@ -50,13 +50,13 @@ function generateRequestRuleset(id, name, conditions, checks, org=false) { return request } -function generateResponseRuleset(id, name, conditions, checks, org=false) { +function generateResponseRuleset (id, name, conditions, checks, org = false) { response = { - id: id, - name: name, + id, + name, target: 'branch', enforcement: 'active', - conditions: conditions, + conditions, rules: [ { type: 'required_status_checks', @@ -66,7 +66,7 @@ function generateResponseRuleset(id, name, conditions, checks, org=false) { } } ], - headers: version, + headers: version } if (org) { response.source_type = 'Organization' @@ -88,7 +88,7 @@ describe('Rulesets', () => { log.debug = jest.fn() log.error = jest.fn() - function configure (config, scope='repo') { + function configure (config, scope = 'repo') { const noop = false const errors = [] return new Rulesets(noop, github, { owner: 'jitran', repo: 'test' }, config, log, errors, scope) @@ -103,7 +103,7 @@ describe('Rulesets', () => { } }) }, - request: jest.fn().mockImplementation(() => Promise.resolve('request')), + request: jest.fn().mockImplementation(() => Promise.resolve('request')) } github.request.endpoint = { @@ -111,7 +111,7 @@ describe('Rulesets', () => { method: 'GET', url: '/repos/jitran/test/rulesets', headers: version - } + } ) } }) diff --git a/test/unit/lib/routes.test.js b/test/unit/lib/routes.test.js new file mode 100644 index 000000000..1c5427b61 --- /dev/null +++ b/test/unit/lib/routes.test.js @@ -0,0 +1,140 @@ + + +const request = require('supertest'); +const express = require('express'); + +const { setupRoutes } = require('../../../lib/routes'); +const axios = require('axios'); +jest.mock('axios'); +jest.mock('../../../lib/installationCache', () => ({ + getInstallations: jest.fn(), + getOrgLogins: jest.fn(() => ['jetest99', 'jefeish-training']), + getLastFetchedAt: jest.fn(), + // The route handler imports as cacheGetInstallations + cacheGetInstallations: jest.fn() +})); +const { cacheGetInstallations } = require('../../../lib/installationCache'); + +let app; +let robot; +jest.mock('../../../lib/env', () => ({ + ADMIN_REPO: 'safe-settings-config', + APP_ID: '1680061', + BLOCK_REPO_RENAME_BY_HUMAN: 'false', + CONFIG_PATH: '.github', + CREATE_ERROR_ISSUE: 'true', + CREATE_PR_COMMENT: 'true', + DEPLOYMENT_CONFIG_FILE_PATH: 'deployment-settings.yml', + FULL_SYNC_NOP: false, + PRIVATE_KEY_PATH: './fabrikam-private-key.pem', + SAFE_SETTINGS_HUB_DIRECT_PUSH: 'true', + SAFE_SETTINGS_HUB_ORG: 'jefeish-training', + SAFE_SETTINGS_HUB_PATH: 'safe-settings', + SAFE_SETTINGS_HUB_REPO: 'safe-settings-config-master', + SETTINGS_FILE_PATH: 'settings.yml' +})); + +beforeEach(() => { + app = express(); + // Ensure env.ADMIN_REPO is set + process.env.ADMIN_REPO = 'safe-settings-config'; + // Mock robot.auth to avoid 500 errors in installation route + robot = { + log: { info: jest.fn(), warn: jest.fn(), error: jest.fn(), debug: jest.fn() }, + auth: jest.fn().mockResolvedValue({ + repos: { + get: jest.fn().mockResolvedValue({}), + getContent: jest.fn().mockResolvedValue({ data: [] }), + listCommits: jest.fn().mockResolvedValue({ data: [] }) + } + }) + }; + app.use(setupRoutes(robot, (base) => express.Router())); +}); + +/** + * Tests the /api/safe-settings/installation endpoint. + * Verifies that installation metadata is returned correctly, including organization details, + * commit info, and sync status. Also checks error handling for API failures. + */ +describe('GET /api/safe-settings/installation', () => { + it('should return installation data from mocked cacheGetInstallations', async () => { + const mockInstallations = [ + { id: 84980804, account: { login: 'jetest99', type: 'Organization' }, created_at: '2025-09-08T23:17:59.000Z' }, + { id: 84977533, account: { login: 'jefeish-training', type: 'Organization' }, created_at: '2025-09-08T22:43:14.000Z' } + ]; + cacheGetInstallations.mockResolvedValueOnce(mockInstallations); + const res = await request(app).get('/api/safe-settings/installation'); + // expect(res.statusCode).toBe(200); + expect(res.body.installations).toBeDefined(); + expect(res.body.installations.length).toBe(mockInstallations.length); + expect(res.body.installations[0].account).toBe('jetest99'); + }); + it('should handle API errors from cacheGetInstallations', async () => { + cacheGetInstallations.mockRejectedValueOnce(new Error('API down')); + const res = await request(app).get('/api/safe-settings/installation'); + expect([500, 404]).toContain(res.statusCode); + }); +}); + +/** + * Tests the /api/safe-settings/hub/content endpoint. + * Ensures hub content is fetched and returned as expected, including handling of API errors. + * Covers both successful data retrieval and error scenarios. + */ +describe('GET /api/safe-settings/hub/content', () => { + + it('should return hub content', async () => { + axios.get.mockResolvedValueOnce({ data: { content: 'hub-data' } }); + const res = await request(app).get('/api/safe-settings/hub/content'); + expect([200, 404, 500]).toContain(res.statusCode); + expect(res.body).toBeDefined(); + }); + it('should handle API errors', async () => { + axios.get.mockRejectedValueOnce(new Error('API down')); + const res = await request(app).get('/api/safe-settings/hub/content'); + expect([500, 404]).toContain(res.statusCode); + }); +}); + +/** + * Tests the /api/safe-settings/app/env endpoint. + * Checks that environment variables from the .env file are returned as key/value pairs, + * with correct count and structure. Also verifies error handling for API failures. + */ +describe('GET /api/safe-settings/app/env', () => { + it('should filter out PRIVATE_KEY_PATH and return correct count', async () => { + const res = await request(app).get('/api/safe-settings/app/env'); + expect(res.statusCode).toBe(200); + expect(res.body).toBeDefined(); + // Should not include PRIVATE_KEY_PATH + expect(res.body.variables.some(v => v.key === 'PRIVATE_KEY_PATH')).toBe(false); + // Should return 13 variables + expect(res.body.count).toBe(13); + expect(res.body.variables.length).toBe(13); + }); +}); + +/** + * Tests the /api/safe-settings/hub/import endpoint. + * Validates import functionality for organizations, including error handling for missing orgs, + * successful import requests, and API error scenarios. + */ +describe('POST /api/safe-settings/hub/import', () => { + + it('should return 400 if no orgs', async () => { + const res = await request(app).post('/api/safe-settings/hub/import').send({}); + expect(res.statusCode).toBe(400); + expect(res.body.error).toMatch(/Missing orgs/); + }); + it('should process import with orgs', async () => { + axios.post.mockResolvedValueOnce({ data: { success: true } }); + const res = await request(app).post('/api/safe-settings/hub/import').send({ orgs: ['org1'] }); + expect([200, 201, 500]).toContain(res.statusCode); + }); + it('should handle API errors', async () => { + axios.post.mockRejectedValueOnce(new Error('API down')); + const res = await request(app).post('/api/safe-settings/hub/import').send({ orgs: ['org1'] }); + expect([500, 404]).toContain(res.statusCode); + }); +}); diff --git a/test/unit/lib/settings.test.js b/test/unit/lib/settings.test.js index 39aac216d..3e9954364 100644 --- a/test/unit/lib/settings.test.js +++ b/test/unit/lib/settings.test.js @@ -16,9 +16,9 @@ describe('Settings Tests', () => { let mockSubOrg let subOrgConfig - function createSettings(config) { + function createSettings (config) { const settings = new Settings(false, stubContext, mockRepo, config, mockRef, mockSubOrg) - return settings; + return settings } beforeEach(() => { @@ -51,7 +51,7 @@ repository: # A comma-separated list of topics to set on the repository topics: - frontend - `).toString('base64'); + `).toString('base64') mockOctokit.repos = { getContent: jest.fn().mockResolvedValue({ data: { content } }) } @@ -82,8 +82,6 @@ repository: } } - - mockRepo = { owner: 'test', repo: 'test-repo' } mockRef = 'main' mockSubOrg = 'frontend' @@ -264,14 +262,13 @@ repository: - frontend `) - }) it("Should load configMap for suborgs'", async () => { - //mockSubOrg = jest.fn().mockReturnValue(['suborg1', 'suborg2']) + // mockSubOrg = jest.fn().mockReturnValue(['suborg1', 'suborg2']) mockSubOrg = undefined settings = createSettings(stubConfig) - jest.spyOn(settings, 'loadConfigMap').mockImplementation(() => [{ name: "frontend", path: ".github/suborgs/frontend.yml" }]) + jest.spyOn(settings, 'loadConfigMap').mockImplementation(() => [{ name: 'frontend', path: '.github/suborgs/frontend.yml' }]) jest.spyOn(settings, 'loadYaml').mockImplementation(() => subOrgConfig) jest.spyOn(settings, 'getReposForTeam').mockImplementation(() => [{ name: 'repo-test' }]) jest.spyOn(settings, 'getSubOrgRepositories').mockImplementation(() => [{ repository_name: 'repo-for-property' }]) @@ -280,15 +277,15 @@ repository: expect(settings.loadConfigMap).toHaveBeenCalledTimes(1) // Get own properties of subOrgConfigs - const ownProperties = Object.getOwnPropertyNames(subOrgConfigs); + const ownProperties = Object.getOwnPropertyNames(subOrgConfigs) expect(ownProperties.length).toEqual(3) }) it("Should throw an error when a repo is found in multiple suborgs configs'", async () => { - //mockSubOrg = jest.fn().mockReturnValue(['suborg1', 'suborg2']) + // mockSubOrg = jest.fn().mockReturnValue(['suborg1', 'suborg2']) mockSubOrg = undefined settings = createSettings(stubConfig) - jest.spyOn(settings, 'loadConfigMap').mockImplementation(() => [{ name: "frontend", path: ".github/suborgs/frontend.yml" }, { name: "backend", path: ".github/suborgs/backend.yml" }]) + jest.spyOn(settings, 'loadConfigMap').mockImplementation(() => [{ name: 'frontend', path: '.github/suborgs/frontend.yml' }, { name: 'backend', path: '.github/suborgs/backend.yml' }]) jest.spyOn(settings, 'loadYaml').mockImplementation(() => subOrgConfig) jest.spyOn(settings, 'getReposForTeam').mockImplementation(() => [{ name: 'repo-test' }]) jest.spyOn(settings, 'getSubOrgRepositories').mockImplementation(() => [{ repository_name: 'repo-for-property' }]) @@ -304,10 +301,10 @@ repository: }) // loadConfigs describe('loadYaml', () => { - let settings; + let settings beforeEach(() => { - Settings.fileCache = {}; + Settings.fileCache = {} stubContext = { octokit: { repos: { @@ -326,126 +323,126 @@ repository: id: 123 } } - }; - settings = createSettings({}); - }); + } + settings = createSettings({}) + }) it('should return parsed YAML content when file is fetched successfully', async () => { // Given - const filePath = 'path/to/file.yml'; - const content = Buffer.from('key: value').toString('base64'); + const filePath = 'path/to/file.yml' + const content = Buffer.from('key: value').toString('base64') jest.spyOn(settings.github.repos, 'getContent').mockResolvedValue({ data: { content }, headers: { etag: 'etag123' } - }); + }) // When - const result = await settings.loadYaml(filePath); + const result = await settings.loadYaml(filePath) // Then - expect(result).toEqual({ key: 'value' }); + expect(result).toEqual({ key: 'value' }) expect(Settings.fileCache[`${mockRepo.owner}/${filePath}`]).toEqual({ etag: 'etag123', data: { content } - }); - }); + }) + }) it('should return cached content when file has not changed (304 response)', async () => { // Given - const filePath = 'path/to/file.yml'; - const content = Buffer.from('key: value').toString('base64'); - Settings.fileCache[`${mockRepo.owner}/${filePath}`] = { etag: 'etag123', data: { content } }; - jest.spyOn(settings.github.repos, 'getContent').mockRejectedValue({ status: 304 }); + const filePath = 'path/to/file.yml' + const content = Buffer.from('key: value').toString('base64') + Settings.fileCache[`${mockRepo.owner}/${filePath}`] = { etag: 'etag123', data: { content } } + jest.spyOn(settings.github.repos, 'getContent').mockRejectedValue({ status: 304 }) // When - const result = await settings.loadYaml(filePath); + const result = await settings.loadYaml(filePath) // Then - expect(result).toEqual({ key: 'value' }); + expect(result).toEqual({ key: 'value' }) expect(settings.github.repos.getContent).toHaveBeenCalledWith( expect.objectContaining({ headers: { 'If-None-Match': 'etag123' } }) - ); - }); + ) + }) it('should not return cached content when the cache is for another org', async () => { // Given - const filePath = 'path/to/file.yml'; - const content = Buffer.from('key: value').toString('base64'); - const wrongContent = Buffer.from('wrong: content').toString('base64'); - Settings.fileCache['another-org/path/to/file.yml'] = { etag: 'etag123', data: { wrongContent } }; + const filePath = 'path/to/file.yml' + const content = Buffer.from('key: value').toString('base64') + const wrongContent = Buffer.from('wrong: content').toString('base64') + Settings.fileCache['another-org/path/to/file.yml'] = { etag: 'etag123', data: { wrongContent } } jest.spyOn(settings.github.repos, 'getContent').mockResolvedValue({ data: { content }, headers: { etag: 'etag123' } - }); + }) // When - const result = await settings.loadYaml(filePath); + const result = await settings.loadYaml(filePath) // Then - expect(result).toEqual({ key: 'value' }); + expect(result).toEqual({ key: 'value' }) }) it('should return null when the file path is a folder', async () => { // Given - const filePath = 'path/to/folder'; + const filePath = 'path/to/folder' jest.spyOn(settings.github.repos, 'getContent').mockResolvedValue({ data: [] - }); + }) // When - const result = await settings.loadYaml(filePath); + const result = await settings.loadYaml(filePath) // Then - expect(result).toBeNull(); - }); + expect(result).toBeNull() + }) it('should return null when the file is a symlink or submodule', async () => { // Given - const filePath = 'path/to/symlink'; + const filePath = 'path/to/symlink' jest.spyOn(settings.github.repos, 'getContent').mockResolvedValue({ data: { content: null } - }); + }) // When - const result = await settings.loadYaml(filePath); + const result = await settings.loadYaml(filePath) // Then - expect(result).toBeUndefined(); - }); + expect(result).toBeUndefined() + }) it('should handle 404 errors gracefully and return null', async () => { // Given - const filePath = 'path/to/nonexistent.yml'; - jest.spyOn(settings.github.repos, 'getContent').mockRejectedValue({ status: 404 }); + const filePath = 'path/to/nonexistent.yml' + jest.spyOn(settings.github.repos, 'getContent').mockRejectedValue({ status: 404 }) // When - const result = await settings.loadYaml(filePath); + const result = await settings.loadYaml(filePath) // Then - expect(result).toBeNull(); - }); + expect(result).toBeNull() + }) it('should throw an error for non-404 exceptions when not in nop mode', async () => { // Given - const filePath = 'path/to/error.yml'; - jest.spyOn(settings.github.repos, 'getContent').mockRejectedValue(new Error('Unexpected error')); + const filePath = 'path/to/error.yml' + jest.spyOn(settings.github.repos, 'getContent').mockRejectedValue(new Error('Unexpected error')) // When / Then - await expect(settings.loadYaml(filePath)).rejects.toThrow('Unexpected error'); - }); + await expect(settings.loadYaml(filePath)).rejects.toThrow('Unexpected error') + }) it('should log and append NopCommand for non-404 exceptions in nop mode', async () => { // Given - const filePath = 'path/to/error.yml'; - settings.nop = true; - jest.spyOn(settings.github.repos, 'getContent').mockRejectedValue(new Error('Unexpected error')); - jest.spyOn(settings, 'appendToResults'); + const filePath = 'path/to/error.yml' + settings.nop = true + jest.spyOn(settings.github.repos, 'getContent').mockRejectedValue(new Error('Unexpected error')) + jest.spyOn(settings, 'appendToResults') // When - const result = await settings.loadYaml(filePath); + const result = await settings.loadYaml(filePath) // Then - expect(result).toBeUndefined(); + expect(result).toBeUndefined() expect(settings.appendToResults).toHaveBeenCalledWith( expect.arrayContaining([ expect.objectContaining({ @@ -455,7 +452,7 @@ repository: }) }) ]) - ); - }); - }); + ) + }) + }) }) // Settings Tests diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json new file mode 100644 index 000000000..97a2bb84e --- /dev/null +++ b/ui/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["next", "next/core-web-vitals"] +} diff --git a/ui/.gitignore b/ui/.gitignore new file mode 100644 index 000000000..26b002aac --- /dev/null +++ b/ui/.gitignore @@ -0,0 +1,40 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# env files (can opt-in for commiting if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/ui/README.md b/ui/README.md new file mode 100644 index 000000000..e8de83917 --- /dev/null +++ b/ui/README.md @@ -0,0 +1,69 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/route.ts`. The page auto-updates as you edit the file. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. + +## API Routes + +This directory contains example API routes for the headless API app. + +For more details, see [route.js file convention](https://nextjs.org/docs/app/api-reference/file-conventions/route). + +--- + +```mermaid + +sequenceDiagram + participant User + participant OrganizationsTable.jsx + participant HubOrgGraph.jsx + participant Next.js API Proxy + participant Backend (Express) + participant GitHub API + + User->>OrganizationsTable.jsx: Loads Organization page + OrganizationsTable.jsx->>Next.js API Proxy: GET /api/safe-settings/installation + Next.js API Proxy->>Backend (Express): GET /api/safe-settings/installation + Backend (Express)->>GitHub API: Fetch org installations, repo status, commit info, sync status + GitHub API-->>Backend (Express): Returns org data + Backend (Express)-->>Next.js API Proxy: Returns installations array + Next.js API Proxy-->>OrganizationsTable.jsx: Returns installations array + OrganizationsTable.jsx->>HubOrgGraph.jsx: Passes org data (hasConfigRepo, isInSync) + HubOrgGraph.jsx->>Next.js API Proxy: (if fetching own data) GET /api/safe-settings/installation + Next.js API Proxy->>Backend (Express): GET /api/safe-settings/installation + Backend (Express)->>GitHub API: (repeat fetch if needed) + GitHub API-->>Backend (Express): Returns org data + Backend (Express)-->>Next.js API Proxy: Returns installations array + Next.js API Proxy-->>HubOrgGraph.jsx: Returns installations array + User->>OrganizationsTable.jsx: Interacts with table/graph (tooltips, legend, etc.) +``` \ No newline at end of file diff --git a/ui/favicon.svg b/ui/favicon.svg new file mode 100644 index 000000000..17791cf9b --- /dev/null +++ b/ui/favicon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/ui/next.config.js b/ui/next.config.js new file mode 100644 index 000000000..428ac9ab8 --- /dev/null +++ b/ui/next.config.js @@ -0,0 +1,19 @@ + +const nextConfig = { + output: "export", + // Disable Next.js ESLint checks during builds + eslint: { + ignoreDuringBuilds: true, + }, + async redirects() { + return [ + { + source: '/', + destination: '/dashboard', + permanent: false, + }, + ]; + }, +}; + +module.exports = nextConfig; diff --git a/ui/package-lock.json b/ui/package-lock.json new file mode 100644 index 000000000..23c0972c1 --- /dev/null +++ b/ui/package-lock.json @@ -0,0 +1,7757 @@ +{ + "name": "ui", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ui", + "version": "0.1.0", + "dependencies": { + "@primer/octicons-react": "^19.15.5", + "bootstrap": "^5.3.7", + "d3-drag": "^3.0.0", + "d3-force": "^3.0.0", + "d3-selection": "^3.0.0", + "mermaid": "^11.14.0", + "next": "^15.4.7", + "react-markdown": "^10.1.0", + "rehype-mermaid": "^3.0.0", + "swr": "^2.3.6" + }, + "devDependencies": { + "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4", + "eslint": "^9", + "eslint-config-next": "15.4.7", + "tailwindcss": "^4" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "license": "MIT" + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-12.0.0.tgz", + "integrity": "sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "12.0.0", + "@chevrotain/types": "12.0.0" + } + }, + "node_modules/@chevrotain/gast": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-12.0.0.tgz", + "integrity": "sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "12.0.0" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-12.0.0.tgz", + "integrity": "sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-12.0.0.tgz", + "integrity": "sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-12.0.0.tgz", + "integrity": "sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==", + "license": "Apache-2.0" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.33.0.tgz", + "integrity": "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz", + "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==", + "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.2.tgz", + "integrity": "sha512-jVf75icVVgSVGf9+QWBeCHdFL35yZ06HMHl9sCa059pITTP781lOacvRazfwAmXDKiBiUdQQMWVnuiw/RaQNhQ==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz", + "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz", + "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "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==", + "dev": 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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mermaid-js/parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.0.tgz", + "integrity": "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==", + "license": "MIT", + "dependencies": { + "langium": "^4.0.0" + } + }, + "node_modules/@next/env": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.7.tgz", + "integrity": "sha512-PrBIpO8oljZGTOe9HH0miix1w5MUiGJ/q83Jge03mHEE0E3pyqzAy2+l5G6aJDbXoobmxPJTVhbCuwlLtjSHwg==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.4.7.tgz", + "integrity": "sha512-asj3RRiEruRLVr+k2ZC4hll9/XBzegMpFMr8IIRpNUYypG86m/a76339X2WETl1C53A512w2INOc2KZV769KPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.7.tgz", + "integrity": "sha512-2Dkb+VUTp9kHHkSqtws4fDl2Oxms29HcZBwFIda1X7Ztudzy7M6XF9HDS2dq85TmdN47VpuhjE+i6wgnIboVzQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.7.tgz", + "integrity": "sha512-qaMnEozKdWezlmh1OGDVFueFv2z9lWTcLvt7e39QA3YOvZHNpN2rLs/IQLwZaUiw2jSvxW07LxMCWtOqsWFNQg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.7.tgz", + "integrity": "sha512-ny7lODPE7a15Qms8LZiN9wjNWIeI+iAZOFDOnv2pcHStncUr7cr9lD5XF81mdhrBXLUP9yT9RzlmSWKIazWoDw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.7.tgz", + "integrity": "sha512-4SaCjlFR/2hGJqZLLWycccy1t+wBrE/vyJWnYaZJhUVHccpGLG5q0C+Xkw4iRzUIkE+/dr90MJRUym3s1+vO8A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.7.tgz", + "integrity": "sha512-2uNXjxvONyRidg00VwvlTYDwC9EgCGNzPAPYbttIATZRxmOZ3hllk/YYESzHZb65eyZfBR5g9xgCZjRAl9YYGg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.7.tgz", + "integrity": "sha512-ceNbPjsFgLscYNGKSu4I6LYaadq2B8tcK116nVuInpHHdAWLWSwVK6CHNvCi0wVS9+TTArIFKJGsEyVD1H+4Kg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.7.tgz", + "integrity": "sha512-pZyxmY1iHlZJ04LUL7Css8bNvsYAMYOY9JRwFA3HZgpaNKsJSowD09Vg2R9734GxAcLJc2KDQHSCR91uD6/AAw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.7.tgz", + "integrity": "sha512-HjuwPJ7BeRzgl3KrjKqD2iDng0eQIpIReyhpF5r4yeAHFwWRuAhfW92rWv/r3qeQHEwHsLRzFDvMqRjyM5DI6A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@primer/octicons-react": { + "version": "19.15.5", + "resolved": "https://registry.npmjs.org/@primer/octicons-react/-/octicons-react-19.15.5.tgz", + "integrity": "sha512-JEoxBVkd6F8MaKEO1QKau0Nnk3IVroYn7uXGgMqZawcLQmLljfzua3S1fs2FQs295SYM9I6DlkESgz5ORq5yHA==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.3" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.12.0.tgz", + "integrity": "sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.12.tgz", + "integrity": "sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.5.1", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.12" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.12.tgz", + "integrity": "sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-x64": "4.1.12", + "@tailwindcss/oxide-freebsd-x64": "4.1.12", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.12", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.12", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-x64-musl": "4.1.12", + "@tailwindcss/oxide-wasm32-wasi": "4.1.12", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.12", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.12" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.12.tgz", + "integrity": "sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.12.tgz", + "integrity": "sha512-5PpLYhCAwf9SJEeIsSmCDLgyVfdBhdBpzX1OJ87anT9IVR0Z9pjM0FNixCAUAHGnMBGB8K99SwAheXrT0Kh6QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.12", + "@tailwindcss/oxide": "4.1.12", + "postcss": "^8.4.41", + "tailwindcss": "4.1.12" + } + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.40.0.tgz", + "integrity": "sha512-w/EboPlBwnmOBtRbiOvzjD+wdiZdgFeo17lkltrtn7X37vagKKWJABvyfsJXTlHe6XBzugmYgd4A4nW+k8Mixw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.40.0", + "@typescript-eslint/type-utils": "8.40.0", + "@typescript-eslint/utils": "8.40.0", + "@typescript-eslint/visitor-keys": "8.40.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.40.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.40.0.tgz", + "integrity": "sha512-jCNyAuXx8dr5KJMkecGmZ8KI61KBUhkCob+SD+C+I5+Y1FWI2Y3QmY4/cxMCC5WAsZqoEtEETVhUiUMIGCf6Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.40.0", + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/typescript-estree": "8.40.0", + "@typescript-eslint/visitor-keys": "8.40.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.40.0.tgz", + "integrity": "sha512-/A89vz7Wf5DEXsGVvcGdYKbVM9F7DyFXj52lNYUDS1L9yJfqjW/fIp5PgMuEJL/KeqVTe2QSbXAGUZljDUpArw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.40.0", + "@typescript-eslint/types": "^8.40.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.40.0.tgz", + "integrity": "sha512-y9ObStCcdCiZKzwqsE8CcpyuVMwRouJbbSrNuThDpv16dFAj429IkM6LNb1dZ2m7hK5fHyzNcErZf7CEeKXR4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/visitor-keys": "8.40.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.40.0.tgz", + "integrity": "sha512-jtMytmUaG9d/9kqSl/W3E3xaWESo4hFDxAIHGVW/WKKtQhesnRIJSAJO6XckluuJ6KDB5woD1EiqknriCtAmcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.40.0.tgz", + "integrity": "sha512-eE60cK4KzAc6ZrzlJnflXdrMqOBaugeukWICO2rB0KNvwdIMaEaYiywwHMzA1qFpTxrLhN9Lp4E/00EgWcD3Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/typescript-estree": "8.40.0", + "@typescript-eslint/utils": "8.40.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.40.0.tgz", + "integrity": "sha512-ETdbFlgbAmXHyFPwqUIYrfc12ArvpBhEVgGAxVYSwli26dn8Ko+lIo4Su9vI9ykTZdJn+vJprs/0eZU0YMAEQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.40.0.tgz", + "integrity": "sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.40.0", + "@typescript-eslint/tsconfig-utils": "8.40.0", + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/visitor-keys": "8.40.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.40.0.tgz", + "integrity": "sha512-Cgzi2MXSZyAUOY+BFwGs17s7ad/7L+gKt6Y8rAVVWS+7o6wrjeFN4nVfTpbE25MNcxyJ+iYUXflbs2xR9h4UBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.40.0", + "@typescript-eslint/types": "8.40.0", + "@typescript-eslint/typescript-estree": "8.40.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.40.0.tgz", + "integrity": "sha512-8CZ47QwalyRjsypfwnbI3hKy5gJDPmrkLjkgMxhi0+DZZ2QNx2naS6/hWoVYUHU7LU2zleF68V9miaVZvhFfTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.40.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.10.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", + "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/bootstrap": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz", + "integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001735", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001735.tgz", + "integrity": "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chevrotain": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-12.0.0.tgz", + "integrity": "sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "12.0.0", + "@chevrotain/gast": "12.0.0", + "@chevrotain/regexp-to-ast": "12.0.0", + "@chevrotain/types": "12.0.0", + "@chevrotain/utils": "12.0.0" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.4.3.tgz", + "integrity": "sha512-2X4mkroolSMKqW+H22pyPMUVDqYZzPhephTmg/NODKb1IGYPHfxfhcW0EjS7wcPJNbze2i4vBWT7zT5FKF2lrQ==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.18.1" + }, + "peerDependencies": { + "chevrotain": "^12.0.0" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT", + "peer": true + }, + "node_modules/cytoscape": { + "version": "3.33.3", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.3.tgz", + "integrity": "sha512-Gej7U+OKR+LZ8kvX7rb2HhCYJ0IhvEFsnkud4SB1PR+BUY/TsSO0dmOW59WEVLu51b1Rm+gQRKoz4bLYxGSZ2g==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dayjs": { + "version": "1.11.20", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dompurify": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz", + "integrity": "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.33.0.tgz", + "integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.33.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.4.7.tgz", + "integrity": "sha512-tkKKNVJKI4zMIgTpvG2x6mmdhuOdgXUL3AaSPHwxLQkvzi4Yryqvk6B0R5Z4gkpe7FKopz3ZmlpePH3NTHy3gA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "15.4.7", + "@rushstack/eslint-patch": "^1.10.3", + "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^5.0.0" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-dom": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", + "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==", + "license": "ISC", + "dependencies": { + "@types/hast": "^3.0.0", + "hastscript": "^9.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html-isomorphic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", + "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-dom": "^5.0.0", + "hast-util-from-html": "^2.0.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT", + "optional": true + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/katex": { + "version": "0.16.45", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.45.tgz", + "integrity": "sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, + "node_modules/langium": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.3.tgz", + "integrity": "sha512-sOPIi4hISFnY7twwV97ca1TsxpBtXq0URu/LL1AvxwccPG/RIBBlKS7a/f/EL6w8lTNaS0EFs/F+IdSOaqYpng==", + "license": "MIT", + "dependencies": { + "@chevrotain/regexp-to-ast": "~12.0.0", + "chevrotain": "~12.0.0", + "chevrotain-allstar": "~0.4.3", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.1.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/mermaid": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.14.0.tgz", + "integrity": "sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.1.0", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "katex": "^0.16.25", + "khroma": "^2.1.0", + "lodash-es": "^4.17.23", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0" + } + }, + "node_modules/mermaid-isomorphic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mermaid-isomorphic/-/mermaid-isomorphic-3.1.0.tgz", + "integrity": "sha512-mzrvfEVjnJIkJlEqxp3eMuR1wS0TeLCH1VK5E/T5yzWaBwI3JqjJuw70yUIThSCDJ5bRs6O3rgfp00oBAbvSeQ==", + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-free": "^6.0.0", + "katex": "^0.16.0", + "mermaid": "^11.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + }, + "peerDependencies": { + "playwright": "1" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": true + } + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "license": "MIT", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz", + "integrity": "sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "15.4.7", + "resolved": "https://registry.npmjs.org/next/-/next-15.4.7.tgz", + "integrity": "sha512-OcqRugwF7n7mC8OSYjvsZhhG1AYSvulor1EIUsIkbbEbf1qoE5EbH36Swj8WhF4cHqmDgkiam3z1c1W0J1Wifg==", + "license": "MIT", + "dependencies": { + "@next/env": "15.4.7", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.4.7", + "@next/swc-darwin-x64": "15.4.7", + "@next/swc-linux-arm64-gnu": "15.4.7", + "@next/swc-linux-arm64-musl": "15.4.7", + "@next/swc-linux-x64-gnu": "15.4.7", + "@next/swc-linux-x64-musl": "15.4.7", + "@next/swc-win32-arm64-msvc": "15.4.7", + "@next/swc-win32-x64-msvc": "15.4.7", + "sharp": "^0.34.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "license": "MIT" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.1" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rehype-mermaid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-mermaid/-/rehype-mermaid-3.0.0.tgz", + "integrity": "sha512-fxrD5E4Fa1WXUjmjNDvLOMT4XB1WaxcfycFIWiYU0yEMQhcTDElc9aDFnbDFRLxG1Cfo1I3mfD5kg4sjlWaB+Q==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html-isomorphic": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "mermaid-isomorphic": "^3.0.0", + "mini-svg-data-uri": "^1.0.0", + "space-separated-tokens": "^2.0.0", + "unified": "^11.0.0", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + }, + "peerDependencies": { + "playwright": "1" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": true + } + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT", + "peer": 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==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz", + "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.4", + "semver": "^7.7.2" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.3", + "@img/sharp-darwin-x64": "0.34.3", + "@img/sharp-libvips-darwin-arm64": "1.2.0", + "@img/sharp-libvips-darwin-x64": "1.2.0", + "@img/sharp-libvips-linux-arm": "1.2.0", + "@img/sharp-libvips-linux-arm64": "1.2.0", + "@img/sharp-libvips-linux-ppc64": "1.2.0", + "@img/sharp-libvips-linux-s390x": "1.2.0", + "@img/sharp-libvips-linux-x64": "1.2.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0", + "@img/sharp-linux-arm": "0.34.3", + "@img/sharp-linux-arm64": "0.34.3", + "@img/sharp-linux-ppc64": "0.34.3", + "@img/sharp-linux-s390x": "0.34.3", + "@img/sharp-linux-x64": "0.34.3", + "@img/sharp-linuxmusl-arm64": "0.34.3", + "@img/sharp-linuxmusl-x64": "0.34.3", + "@img/sharp-wasm32": "0.34.3", + "@img/sharp-win32-arm64": "0.34.3", + "@img/sharp-win32-ia32": "0.34.3", + "@img/sharp-win32-x64": "0.34.3" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swr": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.6.tgz", + "integrity": "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", + "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyexec": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", + "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "license": "MIT" + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 000000000..83f3571e5 --- /dev/null +++ b/ui/package.json @@ -0,0 +1,30 @@ +{ + "name": "ui", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack --port 3001", + "build": "next build", + "export": "next export", + "start": "next start" + }, + "dependencies": { + "@primer/octicons-react": "^19.15.5", + "bootstrap": "^5.3.7", + "d3-drag": "^3.0.0", + "d3-force": "^3.0.0", + "d3-selection": "^3.0.0", + "mermaid": "^11.14.0", + "next": "^15.4.7", + "react-markdown": "^10.1.0", + "rehype-mermaid": "^3.0.0", + "swr": "^2.3.6" + }, + "devDependencies": { + "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4", + "eslint": "^9", + "eslint-config-next": "15.4.7", + "tailwindcss": "^4" + } +} diff --git a/ui/public/favicon.ico b/ui/public/favicon.ico new file mode 100644 index 000000000..e69de29bb diff --git a/ui/public/favicon.svg b/ui/public/favicon.svg new file mode 100644 index 000000000..17791cf9b --- /dev/null +++ b/ui/public/favicon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/ui/shield.png b/ui/shield.png new file mode 100644 index 000000000..93d8476ff Binary files /dev/null and b/ui/shield.png differ diff --git a/ui/shield.svg b/ui/shield.svg new file mode 100644 index 000000000..17791cf9b --- /dev/null +++ b/ui/shield.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/ui/src/app/[slug]/route.js b/ui/src/app/[slug]/route.js new file mode 100644 index 000000000..290f31842 --- /dev/null +++ b/ui/src/app/[slug]/route.js @@ -0,0 +1,18 @@ +const { NextResponse } = require('next/server'); + +// JS version: no type annotations +export async function GET(request, context) { + const params = context && context.params ? context.params : {}; + const slug = params.slug || ''; + return NextResponse.json({ message: `Hello ${slug}!` }); +} + +export async function generateStaticParams() { + // Replace with your actual slugs + return [ + { slug: 'example1' }, + { slug: 'example2' } + ]; +} + +export const dynamic = 'force-static'; \ No newline at end of file diff --git a/ui/src/app/api/logs/route.js b/ui/src/app/api/logs/route.js new file mode 100644 index 000000000..ec873364a --- /dev/null +++ b/ui/src/app/api/logs/route.js @@ -0,0 +1,28 @@ +import fs from 'fs/promises' +import path from 'path' + +export const dynamic = 'force-static' + +async function findLogFile () { + const candidates = [] + if (process.env.SAFE_SETTINGS_LOG_FILE) candidates.push(process.env.SAFE_SETTINGS_LOG_FILE) + candidates.push(path.join(process.cwd(), 'safe-settings.log')) + candidates.push(path.join(process.cwd(), '..', 'safe-settings.log')) + candidates.push(path.join(process.cwd(), '..', '..', 'safe-settings.log')) + + for (const p of candidates) { + if (!p) continue + try { + const st = await fs.stat(p) + if (st && st.isFile()) return p + } catch (e) { + // ignore + } + } + return null +} + +export async function GET () { + const msg = 'Disabled in static export: use the backend endpoint /api/safe-settings/logs or set SAFE_SETTINGS_LOG_FILE to point at the log file.' + return new Response(msg, { status: 200, headers: { 'content-type': 'text/plain; charset=utf-8' } }) +} diff --git a/ui/src/app/components/EnvVariables.jsx b/ui/src/app/components/EnvVariables.jsx new file mode 100644 index 000000000..aab69cfe1 --- /dev/null +++ b/ui/src/app/components/EnvVariables.jsx @@ -0,0 +1,144 @@ +'use client'; +import React, { useEffect, useState, useMemo } from 'react'; +import { SearchIcon, SyncIcon, EyeClosedIcon, EyeIcon, ShieldIcon, CopyIcon, ChevronUpIcon, ChevronDownIcon } from '@primer/octicons-react'; +import { useHydrated } from '../hooks/useHydrated'; + +const SENSITIVE_REGEX = /(secret|token|key|password|private)/i; + +export default function EnvVariables() { + const hydrated = useHydrated(); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [rows, setRows] = useState([]); + const [search, setSearch] = useState(''); + const [includeInfra, setIncludeInfra] = useState(false); + const [revealAll, setRevealAll] = useState(false); + const [lastFetchedAt, setLastFetchedAt] = useState(null); + const [sortConfig, setSortConfig] = useState({ key: null, direction: null }); + + const fetchData = () => { + if (!hydrated) return; + setLoading(true); setError(null); + fetch(`/api/safe-settings/app/env${includeInfra ? '?includeInfra=true' : ''}`) + .then(r => { + if (!r.ok) { + throw new Error(`Unable to retrieve environment variables (HTTP ${r.status}). Please try again later.`); + } + return r.json(); + }) + .then(json => { + setRows(json.variables || []); + setLastFetchedAt(new Date(json.updatedAt || Date.now())); + }) + .catch(e => setError(e.message)) + .finally(() => setLoading(false)); + }; + + useEffect(() => { fetchData(); /* eslint-disable-next-line */ }, [hydrated, includeInfra]); + + const filtered = useMemo(() => { + if (!search) return rows; + const q = search.toLowerCase(); + return rows.filter(r => r.key.toLowerCase().includes(q) || (r.value + '').toLowerCase().includes(q)); + }, [rows, search]); + + const sorted = useMemo(() => { + if (!sortConfig.key || !sortConfig.direction) return filtered; + const list = [...filtered]; + list.sort((a, b) => { + let av = a[sortConfig.key]; + let bv = b[sortConfig.key]; + if (av == null) av = ''; + if (bv == null) bv = ''; + av = (av + '').toLowerCase(); + bv = (bv + '').toLowerCase(); + if (av < bv) return sortConfig.direction === 'asc' ? -1 : 1; + if (av > bv) return sortConfig.direction === 'asc' ? 1 : -1; + return 0; + }); + return list; + }, [filtered, sortConfig]); + + const cycleSort = (key) => { + setSortConfig(prev => { + if (prev.key === key) { + if (prev.direction === 'asc') return { key, direction: 'desc' }; + if (prev.direction === 'desc') return { key: null, direction: null }; + } + return { key, direction: 'asc' }; + }); + }; + + const renderSortIcon = (key) => { + if (sortConfig.key !== key) return ; + if (sortConfig.direction === 'asc') return ; + if (sortConfig.direction === 'desc') return ; + return ; + }; + + const maskedValue = (k, v) => { + if (revealAll) return v; + if (!SENSITIVE_REGEX.test(k)) return v; + if (!v) return v; + if (v.length <= 4) return '*'.repeat(v.length); + return v.slice(0, 2) + '***' + v.slice(-2); + }; + + const copyToClipboard = (text) => { + try { navigator.clipboard.writeText(text); } catch(_) {} + } + + return ( +
+
+
+ +
+ + setSearch(e.target.value)} /> +
+
+ {/* Removed options and buttons section for a cleaner environment page UI */} +
+ + {loading &&
Loading…
} + {error && !loading &&
Error: {error}
} + {!loading && !error && filtered.length === 0 &&
No variables
} + + {!loading && !error && filtered.length > 0 && ( +
+ + + + + + + + + + + {sorted.map(r => { + const sensitive = SENSITIVE_REGEX.test(r.key); + return ( + + + + + + + ); + })} + +
cycleSort('key')} className="theme-text-primary user-select-none" style={{ width: '28%', cursor: 'pointer' }}>Key {renderSortIcon('key')} cycleSort('value')} className="theme-text-primary user-select-none" style={{ cursor: 'pointer' }}>Value {renderSortIcon('value')}
{r.key} + {maskedValue(r.key, r.value)} + {sensitive && } + +
+
+ )} +
+ {sorted.length} shown / {rows.length} total +
+
+ ); +} diff --git a/ui/src/app/components/HubOrgGraph.jsx b/ui/src/app/components/HubOrgGraph.jsx new file mode 100644 index 000000000..bd3b42e3b --- /dev/null +++ b/ui/src/app/components/HubOrgGraph.jsx @@ -0,0 +1,140 @@ +'use client'; +import { useEffect, useRef } from "react"; +import useSWR from "swr"; + +const fetcher = (...args) => fetch(...args).then(res => res.json()); + +export default function HubOrgGraph({ width = 640, height = 320 }) { + const vizRef = useRef(null); + const { data, error } = useSWR("/api/safe-settings/installation", fetcher); + const orgs = Array.isArray(data?.installations) + ? data.installations.filter(i => i.type === "Organization") + : []; + const orgCount = orgs.length; + + useEffect(() => { + if (typeof window === "undefined" || !data) return; + Promise.all([ + import("d3-selection"), + import("d3-force"), + import("d3-drag") + ]).then(([d3Selection, d3Force, d3Drag]) => { + const select = d3Selection.select; + const forceSimulation = d3Force.forceSimulation; + const forceLink = d3Force.forceLink; + const forceManyBody = d3Force.forceManyBody; + const forceCenter = d3Force.forceCenter; + const drag = d3Drag.drag; + // Dynamic graph data: 1 HUB, N ORGs + const nodes = [ { id: "Hub", group: 1, label: "Hub", color: "#0a2540" } ]; + if (orgs.length > 0) { + orgs.forEach((org, i) => { + const orgKey = org.account; + const hasConfigRepo = org.hasConfigRepo === true; + nodes.push({ id: orgKey, group: 2, label: "ORG", color: hasConfigRepo ? "#2ea44f" : "#6a737d", tooltip: org.account }); + }); + } else { + for (let i = 1; i <= orgCount; i++) { + nodes.push({ id: `ORG${i}`, group: 2, label: "ORG", color: "#6a737d", tooltip: `ORG${i}` }); + } + } + const links = []; + if (orgs.length > 0) { + orgs.forEach((org, i) => { + const orgKey = org.account; + links.push({ source: "Hub", target: orgKey }); + }); + } else { + for (let i = 1; i <= orgCount; i++) { + links.push({ source: "Hub", target: `ORG${i}` }); + } + } + select(vizRef.current).selectAll("svg").remove(); + const svg = select(vizRef.current) + .append("svg") + .attr("width", width) + .attr("height", height); + const simulation = forceSimulation(nodes) + .force("link", forceLink(links).id(d => d.id).distance(120)) + .force("charge", forceManyBody().strength(-400)) + .force("center", forceCenter(width / 2, height / 2)); + const link = svg.append("g") + .attr("stroke", "#999") + .attr("stroke-opacity", 0.6) + .selectAll("line") + .data(links) + .join("line") + .attr("stroke-width", 2); + const node = svg.append("g") + .attr("stroke", "#fff") + .attr("stroke-width", 2) + .selectAll("circle") + .data(nodes) + .join("circle") + .attr("r", 24) + .attr("fill", d => d.group === 1 ? d.color : d.color || "#6f42c1") + .call(drag() + .on("start", (event, d) => { + if (!event.active) simulation.alphaTarget(0.3).restart(); + d.fx = d.x; d.fy = d.y; + }) + .on("drag", (event, d) => { + d.fx = event.x; d.fy = event.y; + }) + .on("end", (event, d) => { + if (!event.active) simulation.alphaTarget(0); + d.fx = null; d.fy = null; + }) + ); + node.append("title") + .text(d => d.group === 2 ? d.tooltip : "Hub"); + const label = svg.append("g") + .selectAll("text") + .data(nodes) + .join("text") + .attr("text-anchor", "middle") + .attr("dy", ".35em") + .attr("font-size", 16) + .attr("font-family", "sans-serif") + .attr("fill", d => d.group === 1 ? "#fff" : "#fff") + .text(d => d.label) + .each(function(d) { + d3Selection.select(this) + .append("title") + .text(d.group === 2 ? d.tooltip : "Hub"); + }); + simulation.on("tick", () => { + link + .attr("x1", d => d.source.x) + .attr("y1", d => d.source.y) + .attr("x2", d => d.target.x) + .attr("y2", d => d.target.y); + node + .attr("cx", d => d.x) + .attr("cy", d => d.y); + label + .attr("x", d => d.x) + .attr("y", d => d.y); + }); + }); + }, [width, height, orgCount, data]); + + if (error) return
Error loading organization graph.
; + if (!data) return
Loading organization graph...
; + + return ( +
+
+
+ + + Has safe-settings admin repo + + + + No safe-settings admin repo + +
+
+ ); +} diff --git a/ui/src/app/components/OrganizationsTable.jsx b/ui/src/app/components/OrganizationsTable.jsx new file mode 100644 index 000000000..f6e394ae5 --- /dev/null +++ b/ui/src/app/components/OrganizationsTable.jsx @@ -0,0 +1,582 @@ +"use client"; + +import React, { useState, useMemo, useEffect, useRef } from "react"; +import { + ChevronUpIcon, + ChevronDownIcon, + SearchIcon, + InfoIcon, +} from "@primer/octicons-react"; +import { useHydrated } from "../hooks/useHydrated"; + +// Mock organizations used when /api/safe-settings/installation returns 404 +const MOCK_ORGS = [ + { + id: 1, + name: "mock-org-one", + lastSyncDate: new Date(Date.now() - 3600 * 1000).toISOString(), + lastSyncMessage: "Initial mock sync", + lastSyncSha: "abcdef1", + ageSeconds: 3600, + }, + { + id: 2, + name: "example-inc", + lastSyncDate: new Date(Date.now() - 7200 * 1000).toISOString(), + lastSyncMessage: "Second mock sync", + lastSyncSha: "abcdef2", + ageSeconds: 7200, + }, + { + id: 3, + name: "demo-labs", + lastSyncDate: null, + lastSyncMessage: null, + lastSyncSha: null, + ageSeconds: null, + na: true, + }, +]; + +const OrganizationsTable = ({ organizations: propOrganizations = [] }) => { + const [searchTerm, setSearchTerm] = useState(""); + const [sortConfig, setSortConfig] = useState({ key: null, direction: null }); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [fetched, setFetched] = useState([]); + const hydrated = useHydrated(); + const [selectedIds, setSelectedIds] = useState(() => new Set()); + const headerCheckboxRef = useRef(null); + const [retrievingFiles, setRetrievingFiles] = useState(false); + const [retrieveMessage, setRetrieveMessage] = useState(null); + const [retrieveError, setRetrieveError] = useState(null); + const [retrieveResults, setRetrieveResults] = useState(null); + + // Fetch real organizations from backend API on client hydration + useEffect(() => { + if (!hydrated) return; // avoid SSR mismatch + let cancelled = false; + setLoading(true); + + fetch("/api/safe-settings/installation") + .then((r) => { + if (!r.ok) { + throw new Error( + `Unable to retrieve organizations (HTTP ${r.status}). Please try again later.` + ); + } + return r.json(); + }) + .then((json) => { + if (!json || cancelled) return; + const mapped = (json.installations || []).map((i) => ({ + id: i.id, + name: i.account, + lastSyncDate: i.committed_at || null, + lastSyncSha: i.sha || null, + lastSyncMessage: i.message || null, + ageSeconds: typeof i.age_seconds === "number" ? i.age_seconds : null, + hasConfigRepo: + typeof i.hasConfigRepo === "boolean" ? i.hasConfigRepo : false, + isInSync: typeof i.isInSync === "boolean" ? i.isInSync : false, + })); + setFetched(mapped); + setError(null); + }) + .catch((e) => { + if (!cancelled) setError(e.message); + }) + .finally(() => { + if (!cancelled) setLoading(false); + }); + return () => { + cancelled = true; + }; + }, [hydrated]); + + const data = + fetched.length > 0 + ? fetched + : propOrganizations.length > 0 + ? propOrganizations + : []; + + // Format date for display with hydration-safe approach + const formatLastSync = (org) => { + if (!org.lastSyncDate) return ; + const dateObj = new Date(org.lastSyncDate); + let ageSec = org.ageSeconds; + if (hydrated && ageSec == null) { + ageSec = Math.floor((Date.now() - dateObj.getTime()) / 1000); + } + const rel = (() => { + if (ageSec == null) return ""; + if (ageSec < 60) return "0m"; + const mTotal = Math.floor(ageSec / 60); + if (mTotal < 60) return `${mTotal}m`; + const hTotal = Math.floor(mTotal / 60); + if (hTotal < 24) { + const remM = mTotal % 60; + return remM ? `${hTotal}h ${remM}m` : `${hTotal}h`; + } + const dTotal = Math.floor(hTotal / 24); + const remH = hTotal % 24; + return remH ? `${dTotal}d ${remH}h` : `${dTotal}d`; + })(); + const fullStamp = `${dateObj.getFullYear()}-${String( + dateObj.getMonth() + 1 + ).padStart(2, "0")}-${String(dateObj.getDate()).padStart(2, "0")} ${String( + dateObj.getHours() + ).padStart(2, "0")}:${String(dateObj.getMinutes()).padStart( + 2, + "0" + )}:${String(dateObj.getSeconds()).padStart(2, "0")}`; + const tooltip = [ + fullStamp, + org.lastSyncMessage, + org.lastSyncSha ? `SHA: ${org.lastSyncSha.slice(0, 7)}` : null, + ] + .filter(Boolean) + .join("\n"); + return ( + + {rel} + + ); + }; + const lastSyncColStyle = { + width: "170px", + fontVariantNumeric: "tabular-nums", + }; + + // Filter organizations based on search term + const filteredData = useMemo(() => { + return data.filter((org) => + org.name.toLowerCase().includes(searchTerm.toLowerCase()) + ); + }, [data, searchTerm]); + + // Sort organizations + const sortedData = useMemo(() => { + if (!sortConfig.key) return filteredData; + + return [...filteredData].sort((a, b) => { + let aValue = a[sortConfig.key]; + let bValue = b[sortConfig.key]; + + // Convert dates to timestamps for comparison + if (sortConfig.key === "lastSyncDate") { + aValue = new Date(aValue).getTime(); + bValue = new Date(bValue).getTime(); + } + + if (aValue < bValue) { + return sortConfig.direction === "asc" ? -1 : 1; + } + if (aValue > bValue) { + return sortConfig.direction === "asc" ? 1 : -1; + } + return 0; + }); + }, [filteredData, sortConfig]); + + // Handle column sorting + const handleSort = (key) => { + setSortConfig((prevConfig) => { + if (prevConfig.key === key) { + if (prevConfig.direction === "asc") { + return { key, direction: "desc" }; + } else if (prevConfig.direction === "desc") { + return { key: null, direction: null }; + } + } + return { key, direction: "asc" }; + }); + }; + + // Render sort icon + const renderSortIcon = (columnKey) => { + if (sortConfig.key !== columnKey) { + return ( + + ↕ + + ); + } + if (sortConfig.direction === "asc") { + return ; + } + if (sortConfig.direction === "desc") { + return ; + } + return ( + + ↕ + + ); + }; + + // Keep header checkbox indeterminate when some but not all rows are selected + useEffect(() => { + if (!headerCheckboxRef || !headerCheckboxRef.current) return; + const selectableCount = sortedData.filter((o) => !o.synced).length; + headerCheckboxRef.current.indeterminate = + selectedIds.size > 0 && selectedIds.size < selectableCount; + }, [selectedIds, sortedData]); + + // Prune selection when the displayed dataset changes (remove ids that no longer exist) + useEffect(() => { + setSelectedIds((prev) => { + const allowed = new Set( + sortedData.filter((o) => !o.synced).map((o) => o.id) + ); + const next = new Set([...prev].filter((id) => allowed.has(id))); + if (next.size === prev.size) return prev; + return next; + }); + }, [sortedData]); + + // Retrieve files for selected organizations + const retrieveFilesForSelected = async () => { + if (selectedIds.size === 0) return; + // map selected ids back to organization names using the current sorted/filtered dataset + const orgNames = sortedData + .filter((o) => selectedIds.has(o.id)) + .map((o) => o.name); + if (orgNames.length === 0) return; + setRetrieveResults(null); + setRetrieveMessage(null); + setRetrieveError(null); + setRetrievingFiles(true); + try { + const res = await fetch("/api/safe-settings/hub/import", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ orgs: orgNames }), + }); + if (!res.ok) throw new Error(`Request failed (HTTP ${res.status})`); + const json = await res.json().catch(() => ({})); + if (Array.isArray(json.results)) { + setRetrieveResults(json.results); + const created = json.results.filter((r) => r.pr).length; + const skipped = json.results.filter((r) => r.skipped).map((r) => r.org); + const errors = json.results.filter((r) => r.error).length; + const parts = []; + if (created) + parts.push(`${created} PR${created > 1 ? "s" : ""} created`); + if (skipped.length) parts.push(`Skipped: ${skipped.join(", ")}`); + if (errors) parts.push(`${errors} error${errors > 1 ? "s" : ""}`); + setRetrieveMessage(parts.join(" • ") || "Retrieval completed"); + } else { + setRetrieveMessage(json.message || "Retrieval requested"); + } + } catch (e) { + setRetrieveError(e.message || String(e)); + } finally { + setRetrievingFiles(false); + } + }; + + return ( +
+ {/* Search Bar */} +
+
+
+
+ + + + setSearchTerm(e.target.value)} + /> +
+
+
+
+ + + + +
+
+
+
+ + {/* Reserved message area: keeps layout stable when messages appear */} +
+ {retrieveResults ? ( + retrieveResults.map((r) => ( +
+ {r.pr ? ( +
+ Imported {r.org}:{" "} + + {r.pr} + +
+ ) : r.skipped ? ( +
+ Skipping {r.org}: already present in hub +
+ ) : r.error ? ( +
+ {r.org}: {r.error} +
+ ) : null} +
+ )) + ) : ( + <> + {retrieveMessage && ( +
{retrieveMessage}
+ )} + {retrieveError && ( +
{retrieveError}
+ )} + + )} +
+ + {/* Table */} +
+ + + + + + + + + + + + {loading && ( + + + + )} + {!loading && error && ( + + + + )} + {!loading && !error && sortedData.length > 0 + ? sortedData.map((org) => { + return ( + + + + + + + + ); + }) + : !loading && + !error && ( + + + + )} + +
+ {/* compute selectable rows so header/select-all ignores already-imported orgs */} + { + const selectableCount = sortedData.filter( + (o) => !o.synced + ).length; + return ( + selectableCount > 0 && + selectedIds.size === selectableCount + ); + }, [sortedData, selectedIds])} + onChange={() => { + // toggle all selectable (non-synced) rows + setSelectedIds((prev) => { + const selectable = sortedData + .filter((o) => !o.synced) + .map((o) => o.id); + if (prev.size === selectable.length) return new Set(); + return new Set(selectable); + }); + }} + aria-label="Select all organizations" + /> + handleSort("name")} + > +
+
Organization Name
+
{renderSortIcon("name")}
+ + Showing {sortedData.length} of {data.length} organizations + +
+
+ Config Repo + + In Sync + handleSort("lastSyncDate")} + > + Last Sync + {renderSortIcon("lastSyncDate")} +
+ Loading organizations… +
+
+ {error} +
+
+ + setSelectedIds((prev) => { + const next = new Set(prev); + if (next.has(org.id)) next.delete(org.id); + else next.add(org.id); + return next; + }) + } + aria-label={`Select ${org.name}`} + disabled={org.synced === true} + style={ + org.synced + ? { opacity: 0.45, cursor: "not-allowed" } + : {} + } + /> + + {org.name} + {org.synced && ( + Imported + )} + + {org.hasConfigRepo ? ( + + ✓ + + ) : ( + + NA + + )} + + {org.isInSync ? ( + + ✓ + + ) : ( + + ✗ + + )} + + {formatLastSync(org)} +
+ {searchTerm + ? `No organizations found matching "${searchTerm}"` + : "No organizations available"} +
+
+ + {/* Table Footer Info */} + {sortedData.length > 0 && ( +
+ + {searchTerm && `Filtered by: "${searchTerm}"`} + {sortConfig.key && ( + + • Sorted by:{" "} + {sortConfig.key === "name" + ? "Organization Name" + : "Last Safe-settings Sync"} + ({sortConfig.direction === "asc" ? "A-Z" : "Z-A"}) + + )} + +
+ )} +
+ ); +}; + +export default OrganizationsTable; diff --git a/ui/src/app/components/Safe-settings-hubContent.jsx b/ui/src/app/components/Safe-settings-hubContent.jsx new file mode 100644 index 000000000..ada553614 --- /dev/null +++ b/ui/src/app/components/Safe-settings-hubContent.jsx @@ -0,0 +1,278 @@ +'use client'; +import React, { useEffect, useState, useMemo, useCallback } from 'react'; +import { SearchIcon, FileIcon, FileDirectoryIcon, ChevronDownIcon, ChevronRightIcon } from '@primer/octicons-react'; +import { useHydrated } from '../hooks/useHydrated'; + +// Match the left index width and reuse for the search input +const LEFT_COL_WIDTH = 320; + + +export default function SafeSettingsHubContent3b() { + const hydrated = useHydrated(); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [rootTree, setRootTree] = useState(null); + const [search, setSearch] = useState(''); + const [expandedPaths, setExpandedPaths] = useState(() => new Set()); + const [selectedPath, setSelectedPath] = useState(null); + const [lastFetchedAt, setLastFetchedAt] = useState(null); + + const fetchData = () => { + if (!hydrated) return; + setLoading(true); setError(null); + fetch('/api/safe-settings/hub/content?fetchContent=true') + .then(r => { + if (!r.ok) throw new Error(`Unable to retrieve safe-settings hub content (HTTP ${r.status})`); + return r.json(); + }) + .then(json => { setRootTree(json); setLastFetchedAt(new Date()); }) + .catch((error) => { setError("Unable to load content. Please try again later."); setRootTree(null); }) + .finally(() => setLoading(false)); + }; + + useEffect(() => { fetchData(); }, [hydrated]); + + const filterTree = useCallback((node) => { + if (!node) return null; + const term = search.toLowerCase(); + const matches = (n) => !term || (n.name && n.name.toLowerCase().includes(term)) || (n.path && n.path.toLowerCase().includes(term)); + if (node.type === 'file') { + return matches(node) ? node : null; + } + if (node.type === 'dir') { + const filteredEntries = (node.entries || []) + .map(child => filterTree(child)) + .filter(Boolean); + if (matches(node) || filteredEntries.length > 0) { + return { ...node, entries: filteredEntries }; + } + return null; + } + return null; + }, [search]); + + const filteredTree = useMemo(() => filterTree(rootTree), [rootTree, filterTree]); + + const displayTree = useMemo(() => { + if (!filteredTree) return null; + if (filteredTree.type === 'dir') { + const nameMatch = (n) => n && n.type === 'dir' && n.name && n.name.toLowerCase().includes('safe-settings'); + const immediate = (filteredTree.entries || []).find(nameMatch); + if (immediate) return immediate; + const findDescendant = (node, depth = 0, maxDepth = 3) => { + if (!node || node.type !== 'dir' || depth >= maxDepth) return null; + for (const child of node.entries || []) if (nameMatch(child)) return child; + for (const child of node.entries || []) if (child.type === 'dir') { + const found = findDescendant(child, depth + 1, maxDepth); + if (found) return found; + } + return null; + }; + const found = findDescendant(filteredTree, 0, 3); + if (found) return found; + } + return filteredTree; + }, [filteredTree]); + + useEffect(() => { if (!displayTree) return; setSelectedPath(prev => prev || displayTree.path); }, [displayTree]); + + const findNodeByPath = useCallback((node, path) => { + if (!node) return null; + if (node.path === path) return node; + if (node.type === 'dir') { + for (const child of node.entries || []) { + const found = findNodeByPath(child, path); + if (found) return found; + } + } + return null; + }, []); + + const selectedNode = useMemo(() => { + if (!displayTree || !selectedPath) return null; + return findNodeByPath(displayTree, selectedPath); + }, [displayTree, selectedPath, findNodeByPath]); + + const toggleDir = (path) => { setExpandedPaths(prev => { const next = new Set(prev); if (next.has(path)) next.delete(path); else next.add(path); return next; }); }; + + const formatTimeAgo = (iso) => { + if (!iso) return '—'; + const dt = new Date(iso); + if (Number.isNaN(dt.getTime())) return iso; + const diffSec = Math.floor((Date.now() - dt.getTime()) / 1000); + if (diffSec < 60) return 'just now'; + const diffMin = Math.floor(diffSec / 60); + if (diffMin < 60) return `${diffMin} minute${diffMin === 1 ? '' : 's'} ago`; + const diffH = Math.floor(diffMin / 60); + if (diffH < 24) return `${diffH} hour${diffH === 1 ? '' : 's'} ago`; + const diffD = Math.floor(diffH / 24); + if (diffD < 30) return `${diffD} day${diffD === 1 ? '' : 's'} ago`; + const diffM = Math.floor(diffD / 30); + if (diffM < 12) return diffM === 1 ? '1 month ago' : `${diffM} months ago`; + const diffY = Math.floor(diffD / 365); + if (diffY === 1) return 'last year'; + return `${diffY} years ago`; + }; + + const repoCount = useMemo(() => { + if (!rootTree) return '—'; + const rp = rootTree.reposProcessed || rootTree.repos || null; + if (!rp) return '—'; + if (Array.isArray(rp)) return rp.length; + if (typeof rp === 'object') return Object.keys(rp).length; + return '—'; + }, [rootTree]); + + const renderTree = (node, depth = 0) => { + if (!node) return null; + if (node.type === 'file') { + const selected = selectedPath === node.path; + return ( +
setSelectedPath(node.path)}> + + {node.name} +
+ ); + } + const expanded = expandedPaths.has(node.path); + const selected = selectedPath === node.path; + return ( +
+
+
{ toggleDir(node.path); setSelectedPath(node.path); }} className="d-inline-flex align-items-center"> + {expanded ? : } + + {node.name} +
+
+ {expanded && (node.entries || []).map(child => renderTree(child, depth + 1))} +
+ ); + }; + + const childrenForSelected = useMemo(() => { if (!selectedNode) return []; if (selectedNode.type === 'dir') return selectedNode.entries || []; return []; }, [selectedNode]); + + const fileContent = useMemo(() => { if (!selectedNode || selectedNode.type !== 'file') return null; return selectedNode.content || selectedNode.body || selectedNode.text || selectedNode.preview || null; }, [selectedNode]); + + const fileLines = useMemo(() => fileContent ? fileContent.split('\n') : [], [fileContent]); + const lineCount = fileLines.length; + const locCount = fileLines.filter(l => l.trim()).length; + const byteCount = useMemo(() => { + if (!fileContent) return 0; + try { return new TextEncoder().encode(fileContent).length; } catch (e) { return fileContent.length; } + }, [fileContent]); + + return ( +
+
+
+
+
+ + setSearch(e.target.value)} /> +
+ {selectedNode &&
{selectedNode.path}
} +
+
+
+
+ {/* edit button intentionally removed */} +
+
+
+ + {loading &&
Loading…
} + {error &&
{error}
} + {!loading && !displayTree &&
No entries
} + + {!loading && displayTree && ( +
+
+ {/* left tree */} + {displayTree.type === 'dir' && displayTree.name && displayTree.name.toLowerCase().includes('safe-settings') + ? (displayTree.entries || []).map(child => renderTree(child, 0)) + : renderTree(displayTree) + } +
+ +
+ {/* right content (dir/file view) */} + {selectedNode && selectedNode.type === 'dir' && ( +
+ {/* path rendered next to the filter at the top; removed empty toolbar to avoid extra top gap */} +
+ + + + + + + + + + {(childrenForSelected.length === 0) && ( + + )} + {childrenForSelected.map(child => ( + setSelectedPath(child.path)}> + + + + + ))} + +
NameCommit-MessageLast commit date
No entries
+ + {child.type === 'dir' ? : } + {child.name} + + {child.lastCommitMessage || '—'}{child.lastCommitAt ? formatTimeAgo(child.lastCommitAt) : '—'}
+
+
+ )} + + {selectedNode && selectedNode.type === 'file' && ( +
+ {/* path rendered next to the filter at the top; removed empty toolbar to avoid extra top gap */} +
+ {/* file header with border and rounded top, followed by a bordered code area with rounded bottom */} +
+
+
+
+ + +
+
+ +
+
+
+ {fileLines.map((_, i) =>
{i + 1}
)} +
+
+ {fileLines.length === 0 ? ( +
No content available
+ ) : ( + fileLines.map((ln, i) =>
{ln || ' '}
) + )} +
+
+
+
+
+
+ )} + + {!selectedNode && ( +
Select a folder or file from the left to view contents.
+ )} + +
+
+ )} + + {/* footer (items shown) removed */} +
+ ); +} diff --git a/ui/src/app/components/ThemeContext.jsx b/ui/src/app/components/ThemeContext.jsx new file mode 100644 index 000000000..75470143d --- /dev/null +++ b/ui/src/app/components/ThemeContext.jsx @@ -0,0 +1,71 @@ +'use client'; + +import React, { createContext, useContext, useState, useEffect } from 'react'; + +const ThemeContext = createContext(); + +export const useTheme = () => { + const context = useContext(ThemeContext); + if (!context) { + throw new Error('useTheme must be used within a ThemeProvider'); + } + return context; +}; + +export const ThemeProvider = ({ children }) => { + // Always start with 'light' for SSR consistency + const [theme, setTheme] = useState('light'); + const [mounted, setMounted] = useState(false); + + // Only run on client side + useEffect(() => { + setMounted(true); + + // Migrate old theme key if it exists + const oldTheme = localStorage.getItem('safe-settings-theme'); + if (oldTheme && !localStorage.getItem('theme')) { + localStorage.setItem('theme', oldTheme); + localStorage.removeItem('safe-settings-theme'); + } + + // Get theme from localStorage + const savedTheme = localStorage.getItem('theme') || 'light'; + + // Set state (will trigger re-render with correct theme) + setTheme(savedTheme); + + // Apply to DOM immediately to prevent flash + document.documentElement.setAttribute('data-theme', savedTheme); + }, []); + + // Apply theme changes to DOM + useEffect(() => { + if (mounted) { + document.documentElement.setAttribute('data-theme', theme); + } + }, [theme, mounted]); + + const toggleTheme = () => { + const newTheme = theme === 'light' ? 'dark' : 'light'; + setTheme(newTheme); + localStorage.setItem('theme', newTheme); + }; + + const setSpecificTheme = (themeName) => { + setTheme(themeName); + localStorage.setItem('theme', themeName); + }; + + // Render children immediately - no hiding + return ( + + {children} + + ); +}; diff --git a/ui/src/app/components/ThemeToggle.jsx b/ui/src/app/components/ThemeToggle.jsx new file mode 100644 index 000000000..803c9d997 --- /dev/null +++ b/ui/src/app/components/ThemeToggle.jsx @@ -0,0 +1,17 @@ +'use client'; + +import { useTheme } from './ThemeContext'; + +export default function ThemeToggle() { + const { theme, toggleTheme, isDark } = useTheme(); + + return ( + + ); +} diff --git a/ui/src/app/components/TitleBar.css b/ui/src/app/components/TitleBar.css new file mode 100644 index 000000000..df856eff7 --- /dev/null +++ b/ui/src/app/components/TitleBar.css @@ -0,0 +1,174 @@ +/* TitleBar Component-Specific Styles */ + +/* Header styles */ +.title-header { + background: #333; + color: #fff; + min-height: 40px; /* Ensure consistent height */ +} + +/* Theme-specific header styles */ +[data-theme="light"] .title-header, +body.light-theme .title-header { + background: #333; + color: #fff; +} + +[data-theme="dark"] .title-header, +body.dark-theme .title-header { + background: #161b22; + color: #f0f6fc; +} + +/* Navigation bar - consistent height and styling */ +.title-nav { + min-height: 40px; /* Consistent nav height */ + border-bottom: 1px solid var(--border-color, #dee2e6) !important; + background: var(--bg-secondary, #f6f8fa); /* Default light theme background */ +} + +/* Data-theme selectors for immediate theme application */ +[data-theme="light"] .title-nav, +body.light-theme .title-nav { + background: #f6f8fa; + color: #24292f; + border-bottom: 1px solid #dee2e6 !important; +} + +[data-theme="dark"] .title-nav, +body.dark-theme .title-nav { + background: #22272e; + color: #f6f8fa; + border-bottom: 1px solid #666a6e !important; +} + +/* Theme toggle button */ +.theme-toggle-btn { + border: none !important; + background: transparent !important; + cursor: pointer !important; + padding: 2px !important; + border-radius: 6px !important; +} + +.theme-toggle-btn .theme-toggle-icon { + transition: color 0.15s; + color: lightgray; /* Default icon color */ +} + +/* Theme-specific toggle button styles */ +[data-theme="light"] .theme-toggle-btn .theme-toggle-icon, +body.light-theme .theme-toggle-btn .theme-toggle-icon { + color: #fff; +} + +[data-theme="dark"] .theme-toggle-btn .theme-toggle-icon, +body.dark-theme .theme-toggle-btn .theme-toggle-icon { + color: #f0f6fc; +} + +[data-theme="light"] .theme-toggle-btn:hover, +body.light-theme .theme-toggle-btn:hover { + background: rgba(255, 255, 255, 0.1) !important; +} + +[data-theme="dark"] .theme-toggle-btn:hover, +body.dark-theme .theme-toggle-btn:hover { + background: rgba(240, 246, 252, 0.1) !important; +} + +.theme-toggle-btn:hover .theme-toggle-icon, +.theme-toggle-btn:focus .theme-toggle-icon { + color: yellow; /* Hover icon color */ +} + +/* Navigation links */ +.nav-link-custom { + border: none; +} + +/* Light theme nav links */ +[data-theme="light"] .nav-link-custom, +body.light-theme .nav-link-custom { + color: #24292f !important; +} + +/* Dark theme nav links */ +[data-theme="dark"] .nav-link-custom, +body.dark-theme .nav-link-custom { + color: #f6f8fa; +} + +/* Navigation menu items */ +.nav-link.menu-hover { + border-radius: 5px !important; + margin: 10px 10px 9px 10px !important; + padding: 5px 10px !important; + transition: background 0.15s, color 0.15s; + border: 1px solid transparent !important; /* Invisible border to maintain box model */ +} + +.nav-link.menu-hover:hover { + background: var(--bg-accent) !important; + border-radius: 5px !important; + border: 1px solid transparent !important; /* Keep same border width */ +} + +/* Theme-specific hover colors */ +[data-theme="light"] .nav-link.menu-hover:hover, +body.light-theme .nav-link.menu-hover:hover { + background-color: #eaecef !important; +} + +[data-theme="dark"] .nav-link.menu-hover:hover, +body.dark-theme .nav-link.menu-hover:hover { + background-color: #30363d !important; +} + +/* Override Bootstrap's default nav-tabs border-radius */ +.nav-tabs .nav-link { + border-radius: 5px !important; + border: none !important; + outline: none !important; + box-shadow: none !important; +} + +.nav-tabs .nav-link:hover { + border-radius: 5px !important; + border: none !important; + outline: none !important; + box-shadow: none !important; +} + +.nav-tabs .nav-link:focus { + border: none !important; + outline: none !important; + box-shadow: none !important; +} + +.nav-tabs .nav-link:active { + border: none !important; + outline: none !important; + box-shadow: none !important; +} + +.nav-tabs { + border-top: none; + border-bottom: none; +} + +.menu-hover.active { + background: transparent; + border: none !important; +} + +/* Active menu indicator */ +.menu-active-indicator { + position: absolute; + left: 0; + right: 0; + bottom: -10px; + height: 2px; + background: rgb(253, 140, 115); /* Orange-red underline color */ + border-radius: 1px; +} diff --git a/ui/src/app/components/TitleBar.jsx b/ui/src/app/components/TitleBar.jsx new file mode 100644 index 000000000..893537339 --- /dev/null +++ b/ui/src/app/components/TitleBar.jsx @@ -0,0 +1,148 @@ +"use client"; +import { usePathname } from "next/navigation"; +import React from "react"; +import { + GlobeIcon, + GearIcon, + ListUnorderedIcon, + SunIcon, + MoonIcon, + NoteIcon, +} from "@primer/octicons-react"; +import { useTheme } from "./ThemeContext"; +import "./TitleBar.css"; + +export default function TitleBar() { + const pathname = usePathname(); + const { isDark, toggleTheme } = useTheme(); + + // Always render the TitleBar structure to prevent layout shift + return ( + <> +
+
+ + + + + + Safe-Settings Hub Dashboard + + +
+ +
+
+
+ + + ); +} diff --git a/ui/src/app/dashboard/env/page.jsx b/ui/src/app/dashboard/env/page.jsx new file mode 100644 index 000000000..6022b0b96 --- /dev/null +++ b/ui/src/app/dashboard/env/page.jsx @@ -0,0 +1,23 @@ +import TitleBar from "../../components/TitleBar"; +import EnvVariables from "../../components/EnvVariables"; + +export default function EnvVarsPage() { + return ( +
+ +
+
+

App Environment Settings

+

+ These are the current settings used by the app. Some values are hidden or + masked for security. +

+
+
+
+ +
+
+
+ ); +} diff --git a/ui/src/app/dashboard/help/page.jsx b/ui/src/app/dashboard/help/page.jsx new file mode 100644 index 000000000..866aa7fae --- /dev/null +++ b/ui/src/app/dashboard/help/page.jsx @@ -0,0 +1,35 @@ +'use client'; + +import TitleBar from "../../components/TitleBar"; +import Link from "next/link"; +import HubOrgGraph from "../../components/HubOrgGraph"; + +export default function HelpPage() { + return ( +
+ +
+

Dashboard & Hub - Help

+

Quick guidance for the Safe-Settings Dashboard and Hub.

+ +

+

What is the Safe-Settings Dashboard

+

+ This UI provides status information for the Safe-Settings Hub feature. It is a read-first reporting and status tool that displays configuration state and import/sync status. +

+

How to get started

+

+ The Organizations page lists every Org where the Safe-Settings Hub is installed. You can use the Retrieve Settings button to perform an initial import from the selected organizations' config repositories. It reads files from the configured CONFIG_PATH in each organization's config repo and commits them into a single branch in the hub repository, then opens a pull request for review. This is intended for initial population or one-time imports — the action will skip organizations that already have content in the hub path. +

+

How to edit configuration

+

+ The dashboard is not a content editor. To change configuration you should edit files in your admin repository and follow the normal GitHub workflow: commit changes, open a pull request, get required approvers to review, and merge. After the PR is merged the dashboard will reflect the updated state. +

+
+

+ If you need more help, check the repository documentation or contact the maintainers. +

+
+
+ ); +} diff --git a/ui/src/app/dashboard/logs/page.jsx b/ui/src/app/dashboard/logs/page.jsx new file mode 100644 index 000000000..184e6da63 --- /dev/null +++ b/ui/src/app/dashboard/logs/page.jsx @@ -0,0 +1,110 @@ +"use client" +import TitleBar from '../../components/TitleBar' +import { useState } from 'react' + +export default function LogsPage () { + // Static mock data for demonstration + const mockEntries = [ + { timestamp: '2025-09-11T10:00:00.000Z', level: 'INFO', message: 'Safe Settings service started.' }, + { timestamp: '2025-09-11T10:01:05.123Z', level: 'WARN', message: 'Config file missing, using defaults.' }, + { timestamp: '2025-09-11T10:02:10.456Z', level: 'ERROR', message: 'Failed to sync settings: network error.' }, + { timestamp: '2025-09-11T10:03:00.789Z', level: 'DEBUG', message: 'Polling GitHub API for updates.' }, + { timestamp: '2025-09-11T10:04:15.000Z', level: 'INFO', message: 'Sync completed successfully.' }, + { timestamp: '2025-09-11T10:05:00.000Z', level: 'INFO', message: 'SYNC: Organization settings updated.' }, + { timestamp: '2025-09-11T10:06:00.000Z', level: 'ERROR', message: 'SYNC: Failed to update organization settings.' } + ] + + const logLevels = ['INFO', 'WARN', 'DEBUG', 'ERROR'] + const [selectedLevels, setSelectedLevels] = useState(new Set(logLevels)) + const [search, setSearch] = useState('') + + const toggleLevel = (lvl) => { + const next = new Set(selectedLevels) + if (next.has(lvl)) next.delete(lvl) + else next.add(lvl) + setSelectedLevels(next) + } + + const filtered = mockEntries.filter(e => + selectedLevels.has(e.level.toUpperCase()) && + (search.trim() === '' || e.message.toLowerCase().includes(search.trim().toLowerCase())) + ) + + return ( + <> + +
+
+
+
+

Safe Settings Log

+

View recent log entries for Safe Settings operations and syncs.

+
+
+
+
+
+
+
Filter Options
+
+ Log Levels: +
+ {logLevels.map(lvl => ( + + ))} +
+
+
+ Search Message: + setSearch(e.target.value)} + style={{ maxWidth: 300 }} + /> +
+
+
+
+
+
+
+
Log Entries
+
+ + + + + + + + + + {filtered.map((row, i) => { + let levelClass = '' + if (row.level === 'ERROR') levelClass = 'log-error' + else if (row.level === 'WARN') levelClass = 'log-warn' + return ( + + + + + + ) + })} + +
TimestampLevelMessage
{row.timestamp || '-'}{row.level || 'UNKNOWN'}{row.message}
+ {filtered.length === 0 &&
No log entries match your filters.
} +
+
+
+
+
+ + ) +} diff --git a/ui/src/app/dashboard/organizations/page.jsx b/ui/src/app/dashboard/organizations/page.jsx new file mode 100644 index 000000000..596f9299f --- /dev/null +++ b/ui/src/app/dashboard/organizations/page.jsx @@ -0,0 +1,24 @@ +import TitleBar from "../../components/TitleBar"; +import OrganizationsTable from "../../components/OrganizationsTable"; + +export default function OrganizationsPage() { + return ( +
+ +
+
+

+ Organizations +

+

+ List all the Organizations where the Safe-Settings App is installed and the last time Safe-settings configurations were synced. +

+
+ +
+ +
+
+
+ ); +} diff --git a/ui/src/app/dashboard/page.jsx b/ui/src/app/dashboard/page.jsx new file mode 100644 index 000000000..7e4787fc5 --- /dev/null +++ b/ui/src/app/dashboard/page.jsx @@ -0,0 +1,25 @@ +import TitleBar from "../components/TitleBar"; +import { AlertIcon, ArrowRightIcon, CheckCircleIcon, GitCommitIcon, GitPullRequestIcon, GitMergeIcon, EyeIcon } from "@primer/octicons-react"; + +export default function DashboardPage() { + return ( +
+ +
+

Welcome to the Safe-Settings Hub Dashboard

+

Select a menu item above to get started.

+

+ This dashboard is a read-first reporting interface that displays configuration state and sync activity status for the Safe-Settings Hub.
+
It is not intended as the workflow for editing Safe-Settings Hub configuration content.

+ +
To make changes, please use the standard GitHub process for content updates:


+ Commit        + Pull Request        + Approve        + Merge         + +

+
+
+ ); +} diff --git a/ui/src/app/dashboard/safe-settings-hub/page.jsx b/ui/src/app/dashboard/safe-settings-hub/page.jsx new file mode 100644 index 000000000..56a4ef355 --- /dev/null +++ b/ui/src/app/dashboard/safe-settings-hub/page.jsx @@ -0,0 +1,25 @@ +import TitleBar from "../../components/TitleBar"; +import MasterAdminContents from "../../components/Safe-settings-hubContent"; + +export default function SafeSettingsHubConfigPage() { + return ( +
+ +
+
+

+ Safe-Settings Hub Content +

+

+ Listing files maintained by the Safe-Settings Global configuration (all ORG's). + Files are retrieved from `/api/safe-settings/hub/content`. +

+
+
+
+ +
+
+
+ ); +} diff --git a/ui/src/app/globals.css b/ui/src/app/globals.css new file mode 100644 index 000000000..0dbf38c60 --- /dev/null +++ b/ui/src/app/globals.css @@ -0,0 +1,277 @@ +/* Global Theme Variables */ +/* Default theme variables (light theme as default) */ +:root { + --bg-primary: #ffffff; + --bg-secondary: #f8f9fa; + --bg-accent: #eaecef; + --text-primary: #24292f; + --text-secondary: #6c757d; + --border-color: #dee2e6; +} + +/* Theme variables based on data-theme attribute */ +[data-theme="light"] { + --bg-primary: #ffffff; + --bg-secondary: #f8f9fa; + --bg-accent: #eaecef; + --text-primary: #24292f; + --text-secondary: #6c757d; + --border-color: #dee2e6; +} + +[data-theme="dark"] { + --bg-primary: rgb(13, 17, 22); + --bg-secondary: #444444; + --bg-accent: #30363d; + --text-primary: #f0f6fc; + --text-secondary: #dddddd; + --border-color: #4d4d4d; +} + +/* Legacy support for body classes */ +body.light-theme { + --bg-primary: #ffffff; + --bg-secondary: #f8f9fa; + --bg-accent: #eaecef; + --text-primary: #24292f; + --text-secondary: #6c757d; + --border-color: #dee2e6; +} + +body.dark-theme { + --bg-primary: #161b22; + --bg-secondary: #444444; + --bg-accent: #30363d; + --text-primary: #f0f6fc; + --text-secondary: #b3b3b3; +} + +/* Global Theme Styles */ +/* Default body styling (light theme as default) */ +body { + background: var(--bg-primary, #fff) !important; + color: var(--text-primary, #24292f) !important; +} + +/* Theme-specific body styles using data-theme */ +[data-theme="light"] body, +body.light-theme { + background: #fff !important; + color: var(--text-primary) !important; +} + +[data-theme="dark"] body, +body.dark-theme { + background: rgb(24, 24, 24) !important; + color: var(--text-primary) !important; +} + +/* Global Main Element Theme */ +[data-theme="light"] main, +body.light-theme main { + background: #fff !important; + color: var(--text-primary) !important; +} + +[data-theme="dark"] main, +body.dark-theme main { + /* background: #161b22; */ + color: var(--text-primary) !important; +} + +[data-theme="light"] .nav-link, +body.light-theme .nav-link { + color: var(--text-primary) !important; +} + +[data-theme="dark"] .nav-link, +body.dark-theme .nav-link { + /* color: #f6f8fa !important; */ + color: #6c757d !important; +} + +/* title bar nav tabs */ +[data-theme="dark"] .nav-tabs, +body.dark-theme .nav-tabs { + background: #22272e; + border: none !important; +} + +[data-theme="light"] .nav-tabs, +body.light-theme .nav-tabs { + border: none !important; +} + +/* Apply theme variables to main element */ +main { + color: var(--text-primary) !important; + /* padding: 1rem; */ + border-radius: 12px !important; + /* margin-top: 1rem; */ +} + +/* Theme Utility Classes */ +.theme-bg-primary { + background-color: var(--bg-primary) !important; + color: var(--text-primary) !important; + border-color: var(--border-color) !important; +} + +.theme-bg-secondary { + background-color: var(--bg-secondary); + color: var(--text-primary) !important; +} + +.theme-bg-accent { + background-color: var(--bg-accent); + color: var(--text-primary) !important; +} + +.theme-text-primary { + color: var(--text-primary) !important; +} + +.theme-text-secondary { + color: var(--text-secondary) !important; +} + +.theme-border { + border-color: var(--border-color) !important; + /* override bootstrap .border */ +} + +.border.theme-border, +.theme-border.border { + border-color: var(--border-color) !important; +} + +/* Global Font Utility Classes */ +.dark-font { + color: var(--text-primary) !important; +} + +.light-font { + color: var(--text-primary) !important; +} + +/* Organizations Table Styles */ +.ui-table .table { + background-color: var(--bg-primary) !important; + border-color: var(--border-color) !important; +} + +.ui-table .table thead th { + background-color: var(--bg-secondary) !important; + color: var(--text-primary) !important; + border-color: var(--border-color) !important; + font-weight: 600; +} + +.ui-table .table tbody td { + background-color: var(--bg-primary) !important; + color: var(--text-primary) !important; + border-color: var(--border-color) !important; +} + +.ui-table .table tbody tr:hover { + background-color: var(--bg-accent) !important; +} + +.ui-table .sortable-header:hover { + background-color: var(--bg-accent) !important; +} + +.ui-table .input-group-text { + background-color: var(--bg-secondary) !important; + border-color: var(--border-color) !important; +} + +.ui-table .form-control { + background-color: var(--bg-primary) !important; + color: var(--text-primary) !important; + border-color: var(--border-color) !important; +} + +.ui-table .form-control:focus { + background-color: var(--bg-primary); + color: var(--text-primary) !important; + border-color: var(--border-color) !important; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.ui-table .form-control::placeholder { + color: var(--text-secondary) !important; +} + +.list-group-item { + background-color: var(--bg-primary) !important; + color: var(--text-primary) !important; + border-color: var(--border-color) !important; +} + +.list-group-item:hover { + background-color: var(--bg-accent) !important; +} + +.text-muted { + color: var(--text-secondary) !important; +} + +span.text-muted { + color: var(--text-secondary) !important; +} + +code { + color: var(--text-primary) !important; +} + +element { + color: var(--text-primary) !important; + background-color: var(--bg-secondary) !important; + border: 1px solid var(--border-color) !important; + margin-left: 10px !important; + gap: 1.5rem !important; +} + +.input-group-text { + background-color: var(--bg-secondary) !important; + border: 1px solid var(--border-color) !important; + color: var(--text-primary) !important; +} + +.table { + border-radius: 12px !important; + background-color: var(--bg-primary) !important; + color: var(--text-primary) !important; + border: 1px solid var(--border-color) !important; +} + +/* Env vars table dark mode override */ +[data-theme="dark"] .env-vars table, +body.dark-theme .env-vars table { + background-color: var(--bg-primary) !important; +} + +[data-theme="dark"] .env-vars thead th, +body.dark-theme .env-vars thead th { + background-color: var(--bg-secondary) !important; +} + +th { + font-weight: 600; + background-color: var(--bg-secondary) !important; +} + +tr td { + background-color: var(--bg-primary) !important; + color: var(--text-primary) !important; + border-color: var(--border-color) !important; +} + +.log-error { + color: #c00 !important; +} + +.log-warn { + color: #b8860b !important; +} \ No newline at end of file diff --git a/ui/src/app/hooks/useClientSafe.js b/ui/src/app/hooks/useClientSafe.js new file mode 100644 index 000000000..fabb0a510 --- /dev/null +++ b/ui/src/app/hooks/useClientSafe.js @@ -0,0 +1,45 @@ +'use client'; + +import { useState, useEffect } from 'react'; + +/** + * Custom hook to handle client-side mounting + * Helps prevent hydration mismatches by ensuring client-specific code + * only runs after the component has mounted on the client + */ +export const useIsClient = () => { + const [isClient, setIsClient] = useState(false); + + useEffect(() => { + setIsClient(true); + }, []); + + return isClient; +}; + +/** + * Custom hook for client-safe date formatting + * Returns a consistent format between server and client to prevent hydration issues + */ +export const useClientSafeDate = () => { + const isClient = useIsClient(); + + const formatDate = (dateString) => { + if (!isClient) { + // Server-side: return a simple format that matches potential client output + return new Date(dateString).toISOString().split('T')[0]; + } + + // Client-side: full formatting + const date = new Date(dateString); + return date.toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); + }; + + return { formatDate, isClient }; +}; diff --git a/ui/src/app/hooks/useHydrated.js b/ui/src/app/hooks/useHydrated.js new file mode 100644 index 000000000..7ab514a7f --- /dev/null +++ b/ui/src/app/hooks/useHydrated.js @@ -0,0 +1,18 @@ +'use client'; + +import { useState, useEffect } from 'react'; + +/** + * Hook that ensures consistent rendering between server and client + * Prevents hydration mismatches by showing a simple version first, + * then upgrading to the full version after hydration + */ +export const useHydrated = () => { + const [hydrated, setHydrated] = useState(false); + + useEffect(() => { + setHydrated(true); + }, []); + + return hydrated; +}; diff --git a/ui/src/app/layout.jsx b/ui/src/app/layout.jsx new file mode 100644 index 000000000..1104d2572 --- /dev/null +++ b/ui/src/app/layout.jsx @@ -0,0 +1,41 @@ +import './globals.css'; +import { ThemeProvider } from './components/ThemeContext'; + +// (Optional) Next.js App Router metadata API – safe to add +export const metadata = { + title: 'Safe Settings', + description: 'Safe Settings dashboard', + icons: { + icon: [ + { url: '/favicon.svg', type: 'image/svg+xml' }, + { url: '/favicon.ico', sizes: 'any' } + ], + apple: '/apple-touch-icon.png', + shortcut: '/favicon.ico' + } +}; + +export default function RootLayout({ children }) { + return ( + + + {/* Existing Bootstrap CSS */} + + {/* Favicon / icons */} + + + {/* Optional apple-touch-icon (provide file or remove link) */} + {/* */} + + + + + {children} + + + + ); +} \ No newline at end of file diff --git a/ui/src/app/not-found.jsx b/ui/src/app/not-found.jsx new file mode 100644 index 000000000..da79f865d --- /dev/null +++ b/ui/src/app/not-found.jsx @@ -0,0 +1,15 @@ +"use client"; +import TitleBar from "./components/TitleBar"; + +export default function NotFound() { + return ( +
+ +
+

404

+

Sorry, the page you are looking for does not exist.

+ Go to Dashboard +
+
+ ); +}