31 Commits

Author SHA1 Message Date
9c0892078a Update dependency @effect/language-service to ^0.48.0
All checks were successful
Lint / lint (push) Successful in 12s
Test build / test-build (pull_request) Successful in 18s
2025-10-23 12:01:28 +00:00
Julien Valverdé
874da0b963 Refactor component
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-23 12:11:35 +02:00
Julien Valverdé
bb0579408d Fix
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-23 10:49:00 +02:00
Julien Valverdé
b39c5946f9 Fix
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-23 10:42:27 +02:00
Julien Valverdé
aaf494e27a Refactor component creation
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-23 10:36:33 +02:00
Julien Valverdé
dbc5694b6d Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-10-23 09:48:37 +02:00
Julien Valverdé
86582de0c5 Fix
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-23 02:30:32 +02:00
Julien Valverdé
72495bb9b5 Refactor useScope
All checks were successful
Lint / lint (push) Successful in 41s
2025-10-23 02:23:48 +02:00
Julien Valverdé
312c103e71 Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-10-22 13:29:35 +02:00
Julien Valverdé
a252cfec27 Fix
All checks were successful
Lint / lint (push) Successful in 19s
2025-10-22 13:07:59 +02:00
Julien Valverdé
4a5f4c329d Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-10-22 12:59:33 +02:00
Julien Valverdé
6f96608f64 Refactor
All checks were successful
Lint / lint (push) Successful in 15s
2025-10-22 11:58:48 +02:00
0bc29b2cb9 Update dependency @effect/language-service to ^0.46.0 (#16)
Some checks failed
Lint / lint (push) Failing after 10s
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
| [@effect/language-service](https://github.com/Effect-TS/language-service) | [`^0.45.0` -> `^0.46.0`](https://renovatebot.com/diffs/npm/@effect%2flanguage-service/0.45.1/0.46.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@effect%2flanguage-service/0.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@effect%2flanguage-service/0.45.1/0.46.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>Effect-TS/language-service (@&#8203;effect/language-service)</summary>

### [`v0.46.0`](https://github.com/Effect-TS/language-service/blob/HEAD/CHANGELOG.md#0460)

[Compare Source](https://github.com/Effect-TS/language-service/compare/v0.45.1...v0.46.0)

##### Minor Changes

- [#&#8203;424](https://github.com/Effect-TS/language-service/pull/424) [`4bbfdb0`](4bbfdb0a48) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Add support to mark a service as "leakable" via JSDoc tag. Services marked with `@effect-leakable-service` will be excluded from the leaking requirements diagnostic, allowing requirements that are expected to be provided per method invocation (e.g. HttpServerRequest).

  Example:

  ```ts
  /**
   * @&#8203;effect-leakable-service
   */
  export class FileSystem extends Context.Tag("FileSystem")<
    FileSystem,
    {
      writeFile: (content: string) => Effect.Effect<void>;
    }
  >() {}
  ```

- [#&#8203;428](https://github.com/Effect-TS/language-service/pull/428) [`ebaa8e8`](ebaa8e85d1) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Add diagnostic to warn when `@effect-diagnostics-next-line` comments have no effect. This helps identify unused suppression comments that don't actually suppress any diagnostics, improving code cleanliness.

  The new `missingDiagnosticNextLine` option controls the severity of this diagnostic (default: "warning"). Set to "off" to disable.

  Example:

  ```ts
  // This comment will trigger a warning because it doesn't suppress any diagnostic
  // @&#8203;effect-diagnostics-next-line effect/floatingEffect:off
  const x = 1;

  // This comment is correctly suppressing a diagnostic
  // @&#8203;effect-diagnostics-next-line effect/floatingEffect:off
  Effect.succeed(1);
  ```

##### Patch Changes

- [#&#8203;426](https://github.com/Effect-TS/language-service/pull/426) [`22717bd`](22717bda12) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Improve Layer Magic refactor with enhanced dependency sorting and cycle detection

  The Layer Magic refactor now includes:

  - Better handling of complex layer composition scenarios
  - Support for detecting missing layer implementations with helpful error messages

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNTYuMSIsInVwZGF0ZWRJblZlciI6IjQxLjE1Ni4xIiwidGFyZ2V0QnJhbmNoIjoibmV4dCIsImxhYmVscyI6W119-->

Reviewed-on: #16
Co-authored-by: Renovate Bot <renovate-bot@valverde.cloud>
Co-committed-by: Renovate Bot <renovate-bot@valverde.cloud>
2025-10-22 09:00:28 +02:00
Julien Valverdé
8642619a6a Form work
Some checks failed
Lint / lint (push) Failing after 9s
2025-10-21 14:49:53 +02:00
Julien Valverdé
e8b8df9449 Form work
Some checks failed
Lint / lint (push) Failing after 11s
2025-10-21 14:01:19 +02:00
Julien Valverdé
3695128923 Refactor Hooks
All checks were successful
Lint / lint (push) Successful in 41s
2025-10-21 06:16:54 +02:00
Julien Valverdé
1f14e8be6b Add useOnChange
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-20 21:24:27 +02:00
Julien Valverdé
adc8835304 Add useOnMount
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-20 07:09:49 +02:00
Julien Valverdé
8b06c56ec0 Merge branch 'master' into next
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-20 06:37:12 +02:00
Julien Valverdé
003d2f19a2 Version bump
All checks were successful
Lint / lint (push) Successful in 12s
Test build / test-build (pull_request) Successful in 18s
2025-10-20 06:33:06 +02:00
Julien Valverdé
15f6d695f8 Fix
All checks were successful
Lint / lint (push) Successful in 11s
2025-10-20 05:57:00 +02:00
Julien Valverdé
64583601dc Fix
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-20 05:55:58 +02:00
Julien Valverdé
cf4ba5805f Refactor Form
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-20 05:36:45 +02:00
Julien Valverdé
90db94e905 Refactor Subscribable
All checks were successful
Lint / lint (push) Successful in 40s
2025-10-20 04:35:11 +02:00
Julien Valverdé
336ea67ea2 Add Subscribable.flatMapSubscriptionRef
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-19 07:46:36 +02:00
Julien Valverdé
1af839f036 Fix example
All checks were successful
Lint / lint (push) Successful in 12s
2025-10-19 07:16:39 +02:00
Julien Valverdé
6bdf2a4d87 submit -> submitFn
All checks were successful
Lint / lint (push) Successful in 41s
2025-10-19 02:51:43 +02:00
8d55a67e75 Update dependency @effect/language-service to ^0.45.0 (#14)
All checks were successful
Lint / lint (push) Successful in 12s
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
| [@effect/language-service](https://github.com/Effect-TS/language-service) | [`^0.44.0` -> `^0.45.0`](https://renovatebot.com/diffs/npm/@effect%2flanguage-service/0.44.1/0.45.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@effect%2flanguage-service/0.45.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@effect%2flanguage-service/0.44.1/0.45.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>Effect-TS/language-service (@&#8203;effect/language-service)</summary>

### [`v0.45.1`](https://github.com/Effect-TS/language-service/blob/HEAD/CHANGELOG.md#0451)

[Compare Source](https://github.com/Effect-TS/language-service/compare/v0.45.0...v0.45.1)

##### Patch Changes

- [#&#8203;423](https://github.com/Effect-TS/language-service/pull/423) [`70d8734`](70d8734558) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Add code fix to rewrite Schema class constructor overrides as static 'new' methods

  When detecting constructor overrides in Schema classes, the diagnostic now provides a new code fix option that automatically rewrites the constructor as a static 'new' method. This preserves the custom initialization logic while maintaining Schema's decoding behavior.

  Example:

  ```typescript
  // Before (with constructor override)
  class MyClass extends Schema.Class<MyClass>("MyClass")({ a: Schema.Number }) {
    b: number;
    constructor() {
      super({ a: 42 });
      this.b = 56;
    }
  }

  // After (using static 'new' method)
  class MyClass extends Schema.Class<MyClass>("MyClass")({ a: Schema.Number }) {
    b: number;
    public static new() {
      const _this = new this({ a: 42 });
      _this.b = 56;
      return _this;
    }
  }
  ```

- [#&#8203;421](https://github.com/Effect-TS/language-service/pull/421) [`8c455ed`](8c455ed7a4) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Update dependencies to their latest versions including Effect 3.18.4, TypeScript 5.9.3, and various ESLint and build tooling packages

### [`v0.45.0`](https://github.com/Effect-TS/language-service/blob/HEAD/CHANGELOG.md#0450)

[Compare Source](https://github.com/Effect-TS/language-service/compare/v0.44.1...v0.45.0)

##### Minor Changes

- [#&#8203;419](https://github.com/Effect-TS/language-service/pull/419) [`7cd7216`](7cd7216abc) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Add support for custom APIs in deterministicKeys diagnostic using the `@effect-identifier` JSDoc tag.

  You can now enforce deterministic keys in custom APIs that follow an `extends MyApi("identifier")` pattern by:

  - Adding `extendedKeyDetection: true` to plugin options to enable detection
  - Marking the identifier parameter with `/** @&#8203;effect-identifier */` JSDoc tag

  Example:

  ```ts
  export function Repository(/** @&#8203;effect-identifier */ identifier: string) {
    return Context.Tag("Repository/" + identifier);
  }

  export class UserRepo extends Repository("user-repo")<
    UserRepo,
    {
      /** ... */
    }
  >() {}
  ```

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNTAuMCIsInVwZGF0ZWRJblZlciI6IjQxLjE1MC4wIiwidGFyZ2V0QnJhbmNoIjoibmV4dCIsImxhYmVscyI6W119-->

Reviewed-on: #14
Co-authored-by: Renovate Bot <renovate-bot@valverde.cloud>
Co-committed-by: Renovate Bot <renovate-bot@valverde.cloud>
2025-10-16 21:34:20 +02:00
Julien Valverdé
a1ec5c4781 Handle ParseError on form submit
All checks were successful
Lint / lint (push) Successful in 41s
2025-10-16 02:00:10 +02:00
756b652861 Update actions/setup-node action to v6 (#13)
All checks were successful
Lint / lint (push) Successful in 13s
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [actions/setup-node](https://github.com/actions/setup-node) | action | major | `v5` -> `v6` |

---

### Release Notes

<details>
<summary>actions/setup-node (actions/setup-node)</summary>

### [`v6`](https://github.com/actions/setup-node/compare/v5...v6)

[Compare Source](https://github.com/actions/setup-node/compare/v5...v6)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNDguMyIsInVwZGF0ZWRJblZlciI6IjQxLjE0OC4zIiwidGFyZ2V0QnJhbmNoIjoibmV4dCIsImxhYmVscyI6W119-->

Reviewed-on: #13
Co-authored-by: Renovate Bot <renovate-bot@valverde.cloud>
Co-committed-by: Renovate Bot <renovate-bot@valverde.cloud>
2025-10-14 16:50:05 +02:00
59f9358b9a Update dependency @effect/language-service to ^0.44.0 (#12)
All checks were successful
Lint / lint (push) Successful in 12s
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
| [@effect/language-service](https://github.com/Effect-TS/language-service) | [`^0.42.0` -> `^0.44.0`](https://renovatebot.com/diffs/npm/@effect%2flanguage-service/0.42.0/0.44.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@effect%2flanguage-service/0.44.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@effect%2flanguage-service/0.42.0/0.44.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>Effect-TS/language-service (@&#8203;effect/language-service)</summary>

### [`v0.44.0`](https://github.com/Effect-TS/language-service/blob/HEAD/CHANGELOG.md#0440)

[Compare Source](https://github.com/Effect-TS/language-service/compare/v0.43.2...v0.44.0)

##### Minor Changes

- [#&#8203;415](https://github.com/Effect-TS/language-service/pull/415) [`42c66a1`](42c66a1265) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Add `diagnosticsName` option to include rule names in diagnostic messages. When enabled (default: true), diagnostic messages will display the rule name at the end, e.g., "Effect must be yielded or assigned to a variable. effect(floatingEffect)"

### [`v0.43.2`](https://github.com/Effect-TS/language-service/blob/HEAD/CHANGELOG.md#0432)

[Compare Source](https://github.com/Effect-TS/language-service/compare/v0.43.1...v0.43.2)

##### Patch Changes

- [#&#8203;410](https://github.com/Effect-TS/language-service/pull/410) [`0b40c04`](0b40c04625) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Defer typescript loading in CLI

### [`v0.43.1`](https://github.com/Effect-TS/language-service/blob/HEAD/CHANGELOG.md#0431)

[Compare Source](https://github.com/Effect-TS/language-service/compare/v0.43.0...v0.43.1)

##### Patch Changes

- [#&#8203;408](https://github.com/Effect-TS/language-service/pull/408) [`9ccd800`](9ccd8007b3) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Fix handling of leading/trailing slashes

### [`v0.43.0`](https://github.com/Effect-TS/language-service/blob/HEAD/CHANGELOG.md#0430)

[Compare Source](https://github.com/Effect-TS/language-service/compare/v0.42.0...v0.43.0)

##### Minor Changes

- [#&#8203;407](https://github.com/Effect-TS/language-service/pull/407) [`6590590`](6590590c0d) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Add deterministicKeys diagnostic to enforce consistent key patterns for Services and Errors

  This new diagnostic helps maintain consistent and unique keys for Effect Services and Tagged Errors by validating them against configurable patterns. The diagnostic is disabled by default and can be enabled via the `deterministicKeys` diagnosticSeverity setting.

  Two patterns are supported:

  - `default`: Constructs keys from package name + file path + class identifier (e.g., `@effect/package/FileName/ClassIdentifier`)
  - `package-identifier`: Uses package name + identifier for flat project structures

  Example configuration:

  ```jsonc
  {
    "diagnosticSeverity": {
      "deterministicKeys": "error"
    },
    "keyPatterns": [
      {
        "target": "service",
        "pattern": "default",
        "skipLeadingPath": ["src/"]
      }
    ]
  }
  ```

  The diagnostic also provides auto-fix code actions to update keys to match the configured patterns.

##### Patch Changes

- [#&#8203;405](https://github.com/Effect-TS/language-service/pull/405) [`f43b3ab`](f43b3ab32c) Thanks [@&#8203;mattiamanzati](https://github.com/mattiamanzati)! - Fix wrapWithEffectGen refactor not working on class heritage clauses

  The wrapWithEffectGen refactor now correctly skips expressions in heritage clauses (e.g., `extends` clauses in class declarations) to avoid wrapping them inappropriately.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xMzguNCIsInVwZGF0ZWRJblZlciI6IjQxLjE0Ni4wIiwidGFyZ2V0QnJhbmNoIjoibmV4dCIsImxhYmVscyI6W119-->

Reviewed-on: #12
Co-authored-by: Renovate Bot <renovate-bot@valverde.cloud>
Co-committed-by: Renovate Bot <renovate-bot@valverde.cloud>
2025-10-13 01:00:50 +02:00
50 changed files with 1282 additions and 2110 deletions

View File

@@ -9,7 +9,7 @@ jobs:
- name: Setup Bun - name: Setup Bun
uses: oven-sh/setup-bun@v2 uses: oven-sh/setup-bun@v2
- name: Clone repo - name: Clone repo
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install dependencies - name: Install dependencies
run: bun install --frozen-lockfile run: bun install --frozen-lockfile
- name: Lint TypeScript - name: Lint TypeScript

View File

@@ -12,7 +12,7 @@ jobs:
- name: Setup Bun - name: Setup Bun
uses: oven-sh/setup-bun@v2 uses: oven-sh/setup-bun@v2
- name: Clone repo - name: Clone repo
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install dependencies - name: Install dependencies
run: bun install --frozen-lockfile run: bun install --frozen-lockfile
- name: Lint TypeScript - name: Lint TypeScript

View File

@@ -12,9 +12,9 @@ jobs:
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v6 uses: actions/setup-node@v6
with: with:
node-version: "24" node-version: "22"
- name: Clone repo - name: Clone repo
uses: actions/checkout@v6 uses: actions/checkout@v5
- name: Install dependencies - name: Install dependencies
run: bun install --frozen-lockfile run: bun install --frozen-lockfile
- name: Lint TypeScript - name: Lint TypeScript

365
bun.lock
View File

@@ -1,178 +1,197 @@
{ {
"lockfileVersion": 1, "lockfileVersion": 1,
"configVersion": 1,
"workspaces": { "workspaces": {
"": { "": {
"name": "@effect-fc/monorepo", "name": "@effect-fc/monorepo",
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^2.3.8", "@biomejs/biome": "^2.2.5",
"@effect/language-service": "^0.65.0", "@effect/language-service": "^0.48.0",
"@types/bun": "^1.3.3", "@types/bun": "^1.2.23",
"npm-check-updates": "^19.1.2", "npm-check-updates": "^19.0.0",
"npm-sort": "^0.0.4", "npm-sort": "^0.0.4",
"turbo": "^2.6.1", "turbo": "^2.5.8",
"typescript": "^5.9.3", "typescript": "^5.9.3",
}, },
}, },
"packages/effect-fc": { "packages/effect-fc": {
"name": "effect-fc", "name": "effect-fc",
"version": "0.2.2", "version": "0.1.5",
"devDependencies": { "dependencies": {
"@effect/platform-browser": "^0.74.0", "@typed/async-data": "^0.13.1",
}, },
"peerDependencies": { "peerDependencies": {
"@types/react": "^19.2.0", "@types/react": "^19.0.0",
"effect": "^3.19.0", "effect": "^3.15.0",
"react": "^19.2.0", "react": "^19.0.0",
}, },
}, },
"packages/example": { "packages/example": {
"name": "@effect-fc/example", "name": "@effect-fc/example",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@effect/platform": "^0.94.0", "@effect/platform": "^0.92.1",
"@effect/platform-browser": "^0.74.0", "@effect/platform-browser": "^0.72.0",
"@radix-ui/themes": "^3.2.1", "@radix-ui/themes": "^3.2.1",
"@typed/async-data": "^0.13.1",
"@typed/id": "^0.17.2", "@typed/id": "^0.17.2",
"effect": "^3.19.8", "@typed/lazy-ref": "^0.3.3",
"effect": "^3.18.1",
"effect-fc": "workspace:*", "effect-fc": "workspace:*",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
}, },
"devDependencies": { "devDependencies": {
"@tanstack/react-router": "^1.139.12", "@tanstack/react-router": "^1.132.31",
"@tanstack/react-router-devtools": "^1.139.12", "@tanstack/react-router-devtools": "^1.132.31",
"@tanstack/router-plugin": "^1.139.12", "@tanstack/router-plugin": "^1.132.31",
"@types/react": "^19.2.7", "@types/react": "^19.2.0",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^5.1.1", "@vitejs/plugin-react": "^5.0.4",
"globals": "^17.0.0", "globals": "^16.4.0",
"react": "^19.2.0", "react": "^19.2.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.0",
"type-fest": "^5.2.0", "type-fest": "^5.0.1",
"vite": "^7.2.6", "vite": "^7.1.8",
}, },
}, },
}, },
"packages": { "packages": {
"@babel/code-frame": ["@babel/code-frame@7.28.6", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q=="], "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
"@babel/compat-data": ["@babel/compat-data@7.28.6", "", {}, "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg=="], "@babel/compat-data": ["@babel/compat-data@7.28.4", "", {}, "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw=="],
"@babel/core": ["@babel/core@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/template": "^7.28.6", "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw=="], "@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="],
"@babel/generator": ["@babel/generator@7.28.6", "", { "dependencies": { "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw=="], "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
"@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.3", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg=="],
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA=="],
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
"@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
"@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
"@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
"@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="],
"@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="], "@babel/parser": ["@babel/parser@7.28.4", "", { "dependencies": { "@babel/types": "^7.28.4" }, "bin": "./bin/babel-parser.js" }, "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg=="],
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="], "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="],
"@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A=="], "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ=="],
"@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
"@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg=="],
"@babel/traverse": ["@babel/traverse@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.6", "@babel/template": "^7.28.6", "@babel/types": "^7.28.6", "debug": "^4.3.1" } }, "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg=="], "@babel/preset-typescript": ["@babel/preset-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ=="],
"@babel/types": ["@babel/types@7.28.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg=="], "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
"@biomejs/biome": ["@biomejs/biome@2.3.11", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.11", "@biomejs/cli-darwin-x64": "2.3.11", "@biomejs/cli-linux-arm64": "2.3.11", "@biomejs/cli-linux-arm64-musl": "2.3.11", "@biomejs/cli-linux-x64": "2.3.11", "@biomejs/cli-linux-x64-musl": "2.3.11", "@biomejs/cli-win32-arm64": "2.3.11", "@biomejs/cli-win32-x64": "2.3.11" }, "bin": { "biome": "bin/biome" } }, "sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ=="], "@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA=="], "@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-fh7nnvbweDPm2xEmFjfmq7zSUiox88plgdHF9OIW4i99WnXrAC3o2P3ag9judoUMv8FCSUnlwJCM1B64nO5Fbg=="], "@biomejs/biome": ["@biomejs/biome@2.2.5", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.2.5", "@biomejs/cli-darwin-x64": "2.2.5", "@biomejs/cli-linux-arm64": "2.2.5", "@biomejs/cli-linux-arm64-musl": "2.2.5", "@biomejs/cli-linux-x64": "2.2.5", "@biomejs/cli-linux-x64-musl": "2.2.5", "@biomejs/cli-win32-arm64": "2.2.5", "@biomejs/cli-win32-x64": "2.2.5" }, "bin": { "biome": "bin/biome" } }, "sha512-zcIi+163Rc3HtyHbEO7CjeHq8DjQRs40HsGbW6vx2WI0tg8mYQOPouhvHSyEnCBAorfYNnKdR64/IxO7xQ5faw=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g=="], "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.2.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MYT+nZ38wEIWVcL5xLyOhYQQ7nlWD0b/4mgATW2c8dvq7R4OQjt/XGXFkXrmtWmQofaIM14L7V8qIz/M+bx5QQ=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-XPSQ+XIPZMLaZ6zveQdwNjbX+QdROEd1zPgMwD47zvHV+tCGB88VH+aynyGxAHdzL+Tm/+DtKST5SECs4iwCLg=="], "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.2.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-FLIEl73fv0R7dI10EnEiZLw+IMz3mWLnF95ASDI0kbx6DDLJjWxE5JxxBfmG+udz1hIDd3fr5wsuP7nwuTRdAg=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg=="], "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.2.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-5DjiiDfHqGgR2MS9D+AZ8kOfrzTGqLKywn8hoXpXXlJXIECGQ32t+gt/uiS2XyGBM2XQhR6ztUvbjZWeccFMoQ=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw=="], "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.2.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Ov2wgAFwqDvQiESnu7b9ufD1faRa+40uwrohgBopeY84El2TnBDoMNXx6iuQdreoFGjwW8vH6k68G21EpNERw=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw=="], "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.2.5", "", { "os": "linux", "cpu": "x64" }, "sha512-fq9meKm1AEXeAWan3uCg6XSP5ObA6F/Ovm89TwaMiy1DNIwdgxPkNwxlXJX8iM6oRbFysYeGnT0OG8diCWb9ew=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg=="], "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.2.5", "", { "os": "linux", "cpu": "x64" }, "sha512-AVqLCDb/6K7aPNIcxHaTQj01sl1m989CJIQFQEaiQkGr2EQwyOpaATJ473h+nXDUuAcREhccfRpe/tu+0wu0eQ=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.2.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-xaOIad4wBambwJa6mdp1FigYSIF9i7PCqRbvBqtIi9y29QtPVQ13sDGtUnsRoe6SjL10auMzQ6YAe+B3RpZXVg=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.2.5", "", { "os": "win32", "cpu": "x64" }, "sha512-F/jhuXCssPFAuciMhHKk00xnCAxJRS/pUzVfXYmOMUp//XW7mO6QeCjsjvnm8L4AO/dG2VOB0O+fJPiJ2uXtIw=="],
"@effect-fc/example": ["@effect-fc/example@workspace:packages/example"], "@effect-fc/example": ["@effect-fc/example@workspace:packages/example"],
"@effect/language-service": ["@effect/language-service@0.65.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-eHcpLNCZa1XEDRrXLZqTdky6jAQojL6zQEW53Ba6vJL35j77tJTnV9BFkk34G3rxKoplNo39U0Mum3RfuH9rsg=="], "@effect/language-service": ["@effect/language-service@0.48.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-u7DTPoGFFeDGSdomjY5C2nCGNWSisxpYSqHp3dlSG8kCZh5cay+166bveHRYvuJSJS5yomdkPTJwjwrqMmT7Og=="],
"@effect/platform": ["@effect/platform@0.94.1", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.14" } }, "sha512-SlL8OMTogHmMNnFLnPAHHo3ua1yrB1LNQOVQMiZsqYu9g3216xjr0gn5WoDgCxUyOdZcseegMjWJ7dhm/2vnfg=="], "@effect/platform": ["@effect/platform@0.92.1", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.18.1" } }, "sha512-XXWCBVwyhaKZISN7aM1fv/3fWDGyxr84ObywnUrL8aHvJLoIeskWFAP/fqw3c5MFCrJ3ZV97RWLbv6JiBQugdg=="],
"@effect/platform-browser": ["@effect/platform-browser@0.74.0", "", { "dependencies": { "multipasta": "^0.2.7" }, "peerDependencies": { "@effect/platform": "^0.94.0", "effect": "^3.19.13" } }, "sha512-PAgkg5L5cASQpScA0SZTSy543MVA4A9kmpVCjo2fCINLRpTeuCFAOQHgPmw8dKHnYS0yGs2TYn7AlrhhqQ5o3g=="], "@effect/platform-browser": ["@effect/platform-browser@0.72.0", "", { "dependencies": { "multipasta": "^0.2.7" }, "peerDependencies": { "@effect/platform": "^0.92.0", "effect": "^3.18.0" } }, "sha512-xLlhR2S5yGo7//i8rTOiu1wCyrmrotXk+lK7Y257odxmQ2+HhV4wA2E+xFa0bFbHnqFCE3Yza9r0BkA3y1tgag=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.10", "", { "os": "aix", "cpu": "ppc64" }, "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.25.10", "", { "os": "android", "cpu": "arm" }, "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.10", "", { "os": "android", "cpu": "arm64" }, "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], "@esbuild/android-x64": ["@esbuild/android-x64@0.25.10", "", { "os": "android", "cpu": "x64" }, "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.10", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.10", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.10", "", { "os": "linux", "cpu": "arm" }, "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.10", "", { "os": "linux", "cpu": "ia32" }, "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.10", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.10", "", { "os": "linux", "cpu": "s390x" }, "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.10", "", { "os": "linux", "cpu": "x64" }, "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.10", "", { "os": "none", "cpu": "x64" }, "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.10", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.10", "", { "os": "openbsd", "cpu": "x64" }, "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.10", "", { "os": "sunos", "cpu": "x64" }, "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.10", "", { "os": "win32", "cpu": "ia32" }, "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.10", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="],
"@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="],
@@ -204,6 +223,12 @@
"@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="], "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@radix-ui/colors": ["@radix-ui/colors@3.0.0", "", {}, "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg=="], "@radix-ui/colors": ["@radix-ui/colors@3.0.0", "", {}, "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg=="],
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
@@ -328,84 +353,82 @@
"@radix-ui/themes": ["@radix-ui/themes@3.2.1", "", { "dependencies": { "@radix-ui/colors": "^3.0.0", "classnames": "^2.3.2", "radix-ui": "^1.1.3", "react-remove-scroll-bar": "^2.3.8" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-WJL2YKAGItkunwm3O4cLTFKCGJTfAfF6Hmq7f5bCo1ggqC9qJQ/wfg/25AAN72aoEM1yqXZQ+pslsw48AFR0Xg=="], "@radix-ui/themes": ["@radix-ui/themes@3.2.1", "", { "dependencies": { "@radix-ui/colors": "^3.0.0", "classnames": "^2.3.2", "radix-ui": "^1.1.3", "react-remove-scroll-bar": "^2.3.8" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-WJL2YKAGItkunwm3O4cLTFKCGJTfAfF6Hmq7f5bCo1ggqC9qJQ/wfg/25AAN72aoEM1yqXZQ+pslsw48AFR0Xg=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.38", "", {}, "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.55.1", "", { "os": "android", "cpu": "arm" }, "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg=="], "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.3", "", { "os": "android", "cpu": "arm" }, "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.55.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.3", "", { "os": "android", "cpu": "arm64" }, "sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.55.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg=="], "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.52.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.55.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ=="], "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.52.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.55.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg=="], "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.52.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.55.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw=="], "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.52.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ=="], "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.52.3", "", { "os": "linux", "cpu": "arm" }, "sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg=="], "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.52.3", "", { "os": "linux", "cpu": "arm" }, "sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ=="], "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.52.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA=="], "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.52.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g=="], "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.52.3", "", { "os": "linux", "cpu": "none" }, "sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg=="],
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw=="], "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.52.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw=="], "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.52.3", "", { "os": "linux", "cpu": "none" }, "sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg=="],
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw=="], "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.52.3", "", { "os": "linux", "cpu": "none" }, "sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw=="], "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.52.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg=="], "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.52.3", "", { "os": "linux", "cpu": "x64" }, "sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.55.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg=="], "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.52.3", "", { "os": "linux", "cpu": "x64" }, "sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg=="], "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.52.3", "", { "os": "none", "cpu": "arm64" }, "sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w=="], "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.52.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA=="],
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.55.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg=="], "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.52.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.55.1", "", { "os": "none", "cpu": "arm64" }, "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw=="], "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.52.3", "", { "os": "win32", "cpu": "x64" }, "sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.55.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g=="], "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.52.3", "", { "os": "win32", "cpu": "x64" }, "sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.55.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA=="], "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg=="], "@tanstack/history": ["@tanstack/history@1.132.31", "", {}, "sha512-UCHM2uS0t/uSszqPEo+SBSSoQVeQ+LlOWAVBl5SA7+AedeAbKafIPjFn8huZCXNLAYb0WKV2+wETr7lDK9uz7g=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw=="], "@tanstack/react-router": ["@tanstack/react-router@1.132.31", "", { "dependencies": { "@tanstack/history": "1.132.31", "@tanstack/react-store": "^0.7.0", "@tanstack/router-core": "1.132.31", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-bgYgffI9TQhi8Zc/I5DMQEO4WOcDNtSll66Eb3/+k3iuI59ovVB/CiVCGjqdT8+2YBBj2x0saRDjsF00vj5+Yg=="],
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.132.31", "", { "dependencies": { "@tanstack/router-devtools-core": "1.132.31", "vite": "^7.1.7" }, "peerDependencies": { "@tanstack/react-router": "^1.132.31", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-EiO+t6s1K8igqqtxCO0GLG6KoJgaIsv9JAZMcJV+z/BspElGQwGDBzTtWYcHd9NOP2Yw7OCkAhM8ihwMbzWJNQ=="],
"@tanstack/history": ["@tanstack/history@1.145.7", "", {}, "sha512-gMo/ReTUp0a3IOcZoI3hH6PLDC2R/5ELQ7P2yu9F6aEkA0wSQh+Q4qzMrtcKvF2ut0oE+16xWCGDo/TdYd6cEQ=="], "@tanstack/react-store": ["@tanstack/react-store@0.7.7", "", { "dependencies": { "@tanstack/store": "0.7.7", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-qqT0ufegFRDGSof9D/VqaZgjNgp4tRPHZIJq2+QIHkMUtHjaJ0lYrrXjeIUJvjnTbgPfSD1XgOMEt0lmANn6Zg=="],
"@tanstack/react-router": ["@tanstack/react-router@1.150.0", "", { "dependencies": { "@tanstack/history": "1.145.7", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.150.0", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-k/oycTCpBT2XoEk9dNd/nNYhF0X9fLSB10lT40+NVX1TjOtBq5whksk8MT6oRnSoQ8KWeb7La3G9kFaAeSULkA=="], "@tanstack/router-core": ["@tanstack/router-core@1.132.31", "", { "dependencies": { "@tanstack/history": "1.132.31", "@tanstack/store": "^0.7.0", "cookie-es": "^2.0.0", "seroval": "^1.3.2", "seroval-plugins": "^1.3.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-74W+J5N1NuPcuWDwsBAjCgK4ahtIRaB51KdegYrD1AeSNqiV4u8KzOzHKAAZD01UipQApUbpJbzFrHq0XQ9BHw=="],
"@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.150.0", "", { "dependencies": { "@tanstack/router-devtools-core": "1.150.0" }, "peerDependencies": { "@tanstack/react-router": "^1.150.0", "@tanstack/router-core": "^1.150.0", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-TlvTE+XK5XVCfYjazoMWkjyyPKe4kMw2nCA7EuWoYUJKOqRW5oKvBY7auViGWxp51FKDEjV3bbok3wPKBYwZww=="], "@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.132.31", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.5", "vite": "^7.1.7" }, "peerDependencies": { "@tanstack/router-core": "^1.132.31", "csstype": "^3.0.10", "tiny-invariant": "^1.3.3" }, "optionalPeers": ["csstype"] }, "sha512-GwymJRm21hkluQMjOkXn+mBNPMyWlpzQut8mqEObh1cnF3zUsYT5YkCFV8ePA0jb/YVdjK/AfCAgSlhyIa09IA=="],
"@tanstack/react-store": ["@tanstack/react-store@0.8.0", "", { "dependencies": { "@tanstack/store": "0.8.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow=="], "@tanstack/router-generator": ["@tanstack/router-generator@1.132.31", "", { "dependencies": { "@tanstack/router-core": "1.132.31", "@tanstack/router-utils": "1.132.31", "@tanstack/virtual-file-routes": "1.132.31", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-6Ys47sBR3jxet3CaqnF/ykV44R8HLQoT5ZbDqi6f2At6TXYe/+VELRSApC+cq1yjVJwp6Ot5Hm6mYWewh69bdQ=="],
"@tanstack/router-core": ["@tanstack/router-core@1.150.0", "", { "dependencies": { "@tanstack/history": "1.145.7", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.1", "seroval-plugins": "^1.4.0", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-cAm44t/tUbfyzaDH+rE/WO4u3AgaZdpJp00xjQ4gNkC2O95ntVHq5fx+4fhtrkKpgdXoKldgk8OK66djiWpuGQ=="], "@tanstack/router-plugin": ["@tanstack/router-plugin@1.132.31", "", { "dependencies": { "@babel/core": "^7.27.7", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.7", "@babel/types": "^7.27.7", "@tanstack/router-core": "1.132.31", "@tanstack/router-generator": "1.132.31", "@tanstack/router-utils": "1.132.31", "@tanstack/virtual-file-routes": "1.132.31", "babel-dead-code-elimination": "^1.0.10", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.132.31", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.8", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-5/n6VxA6tFLFyewjl1+Av0Qsxmr/WpnAR2UlccS7ZaYli3bvNPJSZd3dy9EphEAXeSbqvFT29nQ/ox8EmGTonQ=="],
"@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.150.0", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "@tanstack/router-core": "^1.150.0", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-61V+4fq2fOPru/48cuojKvWhQx2h/nuj4nVHwzu9E7O8h391h4Hks6axxRbY98/rIz96mn5TCoc0aYuoga53bg=="], "@tanstack/router-utils": ["@tanstack/router-utils@1.132.31", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/parser": "^7.27.5", "@babel/preset-typescript": "^7.27.1", "ansis": "^4.1.0", "diff": "^8.0.2", "fast-glob": "^3.3.3", "pathe": "^2.0.3" } }, "sha512-uf8mQ3wV58K8TL5XXBoWhkYxmCV7LLWbbf6AvcxdhnCnBNmXBGlY+T8RdsRnXyI2Iyp2HfHaVZ+8H3CEQedXfw=="],
"@tanstack/router-generator": ["@tanstack/router-generator@1.150.0", "", { "dependencies": { "@tanstack/router-core": "1.150.0", "@tanstack/router-utils": "1.143.11", "@tanstack/virtual-file-routes": "1.145.4", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-WsA1bN5/I+cxE6V1DkU5ABIPBQxZLlxszElYgnIhs884tzukv76rYMFOy6Xqd51YIFdYtjDrxZbp4/vfkrVCug=="], "@tanstack/store": ["@tanstack/store@0.7.7", "", {}, "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ=="],
"@tanstack/router-plugin": ["@tanstack/router-plugin@1.150.0", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.150.0", "@tanstack/router-generator": "1.150.0", "@tanstack/router-utils": "1.143.11", "@tanstack/virtual-file-routes": "1.145.4", "babel-dead-code-elimination": "^1.0.11", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.150.0", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.10", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-k2NLysBXO4Wpt4Oo0xeBhNtFsMwHOU8ud48/cWNWbV89QAjlk0XU5CGNj2JEaFMT0zlF3H/aM5/h0+vYnDjFFA=="], "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.132.31", "", {}, "sha512-rxS8Cm2nIXroLqkm9pE/8X2lFNuvcTIIiFi5VH4PwzvKscAuaW3YRMN1WmaGDI2mVEn+GLaoY6Kc3jOczL5i4w=="],
"@tanstack/router-utils": ["@tanstack/router-utils@1.143.11", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "ansis": "^4.1.0", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-N24G4LpfyK8dOlnP8BvNdkuxg1xQljkyl6PcrdiPSA301pOjatRT1y8wuCCJZKVVD8gkd0MpCZ0VEjRMGILOtA=="], "@typed/async-data": ["@typed/async-data@0.13.1", "", { "dependencies": { "@typed/lazy-ref": "^0.3.2", "effect": "^3.11.9" } }, "sha512-rKv3HQtoHeGJwZpEaTL0FAEKfqHcMr/x3GtgkE01p2tJiKjq1eVaPZYpweZEEF/zUutox7DQ14oH85x+ZpPA/Q=="],
"@tanstack/store": ["@tanstack/store@0.8.0", "", {}, "sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ=="],
"@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.145.4", "", {}, "sha512-CI75JrfqSluhdGwLssgVeQBaCphgfkMQpi8MCY3UJX1hoGzXa8kHYJcUuIFMOLs1q7zqHy++EVVtMK03osR5wQ=="],
"@typed/id": ["@typed/id@0.17.2", "", { "peerDependencies": { "effect": "^3.14.7" } }, "sha512-z/Z14/moeu9x45IpkGaRwuvb+CQ3s3UCc/agcpZibTz1yPb3RgSDXx4rOHIuyb6hG6oNzqe9yY4GbbMq3Hb5Ug=="], "@typed/id": ["@typed/id@0.17.2", "", { "peerDependencies": { "effect": "^3.14.7" } }, "sha512-z/Z14/moeu9x45IpkGaRwuvb+CQ3s3UCc/agcpZibTz1yPb3RgSDXx4rOHIuyb6hG6oNzqe9yY4GbbMq3Hb5Ug=="],
"@typed/lazy-ref": ["@typed/lazy-ref@0.3.3", "", { "dependencies": { "effect": "^3.11.9" } }, "sha512-qJoy01/RFYwWBaWhQBzL3Ow20Q+CPybJ/KJnGNKzyDpRUFcEvd3YSQMqZjRdBZmG2wnEpjedAnlCx9ApvKJIlA=="],
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
"@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
@@ -414,17 +437,17 @@
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], "@types/bun": ["@types/bun@1.2.23", "", { "dependencies": { "bun-types": "1.2.23" } }, "sha512-le8ueOY5b6VKYf19xT3McVbXqLqmxzPXHsQT/q9JHgikJ2X22wyTW3g3ohz2ZMnp7dod6aduIiq8A14Xyimm0A=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="], "@types/node": ["@types/node@24.6.2", "", { "dependencies": { "undici-types": "~7.13.0" } }, "sha512-d2L25Y4j+W3ZlNAeMKcy7yDsK425ibcAOO2t7aPTz6gNMH0z2GThtwENCDc0d/Pw9wgyRqE5Px1wkV7naz8ang=="],
"@types/react": ["@types/react@19.2.8", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg=="], "@types/react": ["@types/react@19.2.0", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-1LOH8xovvsKsCBq1wnT4ntDUdCJKmnEakhsuoUSy6ExlHCkGP2hqnatagYTgFk6oeL0VU31u7SNjunPN+GchtA=="],
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], "@types/react-dom": ["@types/react-dom@19.2.0", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-brtBs0MnE9SMx7px208g39lRmC5uHZs96caOJfTjFcYSLHNamvaSMfJNagChVNkup2SdtOxKX1FDBkRSJe1ZAg=="],
"@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.2", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.53", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ=="], "@vitejs/plugin-react": ["@vitejs/plugin-react@5.0.4", "", { "dependencies": { "@babel/core": "^7.28.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.38", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA=="],
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
@@ -436,19 +459,19 @@
"ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="],
"babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="], "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.10", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.14", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.8.10", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-uLfgBi+7IBNay8ECBO2mVMGZAc1VgZWEChxm4lv+TobGdG82LnXMjuNGo/BSSZZL4UmkWhxEHP2f5ziLNwGWMA=="],
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], "browserslist": ["browserslist@4.26.3", "", { "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", "electron-to-chromium": "^1.5.227", "node-releases": "^2.0.21", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w=="],
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], "bun-types": ["bun-types@1.2.23", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-R9f0hKAZXgFU3mlrA0YpE/fiDvwV0FT9rORApt2aQVWSuJDzZOyB5QLc0N/4HF57CS8IXJ6+L5E4W1bW6NS2Aw=="],
"caniuse-lite": ["caniuse-lite@1.0.30001764", "", {}, "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g=="], "caniuse-lite": ["caniuse-lite@1.0.30001746", "", {}, "sha512-eA7Ys/DGw+pnkWWSE/id29f2IcPHVoE8wxtvE5JdvD2V28VTDPy1yEeo11Guz0sJ4ZeGRcm3uaTcAqK1LXaphA=="],
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
@@ -460,23 +483,23 @@
"cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "detect-libc": ["detect-libc@2.1.1", "", {}, "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw=="],
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
"diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="], "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="],
"effect": ["effect@3.19.14", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-3vwdq0zlvQOxXzXNKRIPKTqZNMyGCdaFUBfMPqpsyzZDre67kgC1EEHDV4EoQTovJ4w5fmJW756f86kkuz7WFA=="], "effect": ["effect@3.18.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-5aJ7yRlvvkBplMSnhPyol7WYvPenvau12asO3HJhG/126SySWV9D8bscGTbV52XxtC5bwO/VUd5ffjE6uep/1A=="],
"effect-fc": ["effect-fc@workspace:packages/effect-fc"], "effect-fc": ["effect-fc@workspace:packages/effect-fc"],
"electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="], "electron-to-chromium": ["electron-to-chromium@1.5.228", "", {}, "sha512-nxkiyuqAn4MJ1QbobwqJILiDtu/jk14hEAWaMiJmNPh1Z+jqoFlBFZjdXwLWGeVSeu9hGLg6+2G9yJaW8rBIFA=="],
"esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], "esbuild": ["esbuild@0.25.10", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.10", "@esbuild/android-arm": "0.25.10", "@esbuild/android-arm64": "0.25.10", "@esbuild/android-x64": "0.25.10", "@esbuild/darwin-arm64": "0.25.10", "@esbuild/darwin-x64": "0.25.10", "@esbuild/freebsd-arm64": "0.25.10", "@esbuild/freebsd-x64": "0.25.10", "@esbuild/linux-arm": "0.25.10", "@esbuild/linux-arm64": "0.25.10", "@esbuild/linux-ia32": "0.25.10", "@esbuild/linux-loong64": "0.25.10", "@esbuild/linux-mips64el": "0.25.10", "@esbuild/linux-ppc64": "0.25.10", "@esbuild/linux-riscv64": "0.25.10", "@esbuild/linux-s390x": "0.25.10", "@esbuild/linux-x64": "0.25.10", "@esbuild/netbsd-arm64": "0.25.10", "@esbuild/netbsd-x64": "0.25.10", "@esbuild/openbsd-arm64": "0.25.10", "@esbuild/openbsd-x64": "0.25.10", "@esbuild/openharmony-arm64": "0.25.10", "@esbuild/sunos-x64": "0.25.10", "@esbuild/win32-arm64": "0.25.10", "@esbuild/win32-ia32": "0.25.10", "@esbuild/win32-x64": "0.25.10" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
@@ -484,6 +507,10 @@
"fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],
"fast-glob": ["fast-glob@3.3.3", "", { "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" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
@@ -496,13 +523,13 @@
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
"get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], "get-tsconfig": ["get-tsconfig@4.10.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ=="],
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"globals": ["globals@17.0.0", "", {}, "sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw=="], "globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="],
"goober": ["goober@2.1.18", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw=="], "goober": ["goober@2.1.16", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g=="],
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
@@ -512,7 +539,7 @@
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"isbot": ["isbot@5.1.32", "", {}, "sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ=="], "isbot": ["isbot@5.1.31", "", {}, "sha512-DPgQshehErHAqSCKDb3rNW03pa2wS/v5evvUqtxt6TTnHRqAG8FdzcSSJs9656pK6Y+NT7K9R4acEYXLHYfpUQ=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
@@ -522,9 +549,13 @@
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"msgpackr": ["msgpackr@1.11.8", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA=="], "msgpackr": ["msgpackr@1.11.5", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA=="],
"msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="], "msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="],
@@ -534,11 +565,11 @@
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], "node-releases": ["node-releases@2.0.21", "", {}, "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw=="],
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
"npm-check-updates": ["npm-check-updates@19.3.1", "", { "bin": { "npm-check-updates": "build/cli.js", "ncu": "build/cli.js" } }, "sha512-v92fHH8fmf9VVmQwwL5JWpX8GDEe8BDyrz4w3GF6D6JBUZKpQNcTfBBgxVkCcAPzVUjCHSZEXYmZAAKfLTsDBA=="], "npm-check-updates": ["npm-check-updates@19.0.0", "", { "bin": { "npm-check-updates": "build/cli.js", "ncu": "build/cli.js" } }, "sha512-qcfjZEv6xB+WvW24S8wU1MKISPPiTREraBg62XDo/7zmOLXH3Zj7ti2v/LRfks0qITU8SDZLTWwgIitflvursw=="],
"npm-sort": ["npm-sort@0.0.4", "", { "bin": { "npm-sort": "./index.js" } }, "sha512-S5Id/3Jvr7Cf/QnWjRteprngERCBhhEFOM+wMhUrAYP060/HUBC1aL5GoXS3xITlgacJCWaSmP4HQaAt91nNYQ=="], "npm-sort": ["npm-sort@0.0.4", "", { "bin": { "npm-sort": "./index.js" } }, "sha512-S5Id/3Jvr7Cf/QnWjRteprngERCBhhEFOM+wMhUrAYP060/HUBC1aL5GoXS3xITlgacJCWaSmP4HQaAt91nNYQ=="],
@@ -550,21 +581,23 @@
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"prettier": ["prettier@3.8.0", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA=="], "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
"pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="], "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="], "radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="],
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="], "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="], "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
"react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="], "react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="],
"react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
"react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], "react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="],
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
@@ -576,15 +609,21 @@
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
"rollup": ["rollup@4.55.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.55.1", "@rollup/rollup-android-arm64": "4.55.1", "@rollup/rollup-darwin-arm64": "4.55.1", "@rollup/rollup-darwin-x64": "4.55.1", "@rollup/rollup-freebsd-arm64": "4.55.1", "@rollup/rollup-freebsd-x64": "4.55.1", "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", "@rollup/rollup-linux-arm-musleabihf": "4.55.1", "@rollup/rollup-linux-arm64-gnu": "4.55.1", "@rollup/rollup-linux-arm64-musl": "4.55.1", "@rollup/rollup-linux-loong64-gnu": "4.55.1", "@rollup/rollup-linux-loong64-musl": "4.55.1", "@rollup/rollup-linux-ppc64-gnu": "4.55.1", "@rollup/rollup-linux-ppc64-musl": "4.55.1", "@rollup/rollup-linux-riscv64-gnu": "4.55.1", "@rollup/rollup-linux-riscv64-musl": "4.55.1", "@rollup/rollup-linux-s390x-gnu": "4.55.1", "@rollup/rollup-linux-x64-gnu": "4.55.1", "@rollup/rollup-linux-x64-musl": "4.55.1", "@rollup/rollup-openbsd-x64": "4.55.1", "@rollup/rollup-openharmony-arm64": "4.55.1", "@rollup/rollup-win32-arm64-msvc": "4.55.1", "@rollup/rollup-win32-ia32-msvc": "4.55.1", "@rollup/rollup-win32-x64-gnu": "4.55.1", "@rollup/rollup-win32-x64-msvc": "4.55.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A=="], "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"rollup": ["rollup@4.52.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.3", "@rollup/rollup-android-arm64": "4.52.3", "@rollup/rollup-darwin-arm64": "4.52.3", "@rollup/rollup-darwin-x64": "4.52.3", "@rollup/rollup-freebsd-arm64": "4.52.3", "@rollup/rollup-freebsd-x64": "4.52.3", "@rollup/rollup-linux-arm-gnueabihf": "4.52.3", "@rollup/rollup-linux-arm-musleabihf": "4.52.3", "@rollup/rollup-linux-arm64-gnu": "4.52.3", "@rollup/rollup-linux-arm64-musl": "4.52.3", "@rollup/rollup-linux-loong64-gnu": "4.52.3", "@rollup/rollup-linux-ppc64-gnu": "4.52.3", "@rollup/rollup-linux-riscv64-gnu": "4.52.3", "@rollup/rollup-linux-riscv64-musl": "4.52.3", "@rollup/rollup-linux-s390x-gnu": "4.52.3", "@rollup/rollup-linux-x64-gnu": "4.52.3", "@rollup/rollup-linux-x64-musl": "4.52.3", "@rollup/rollup-openharmony-arm64": "4.52.3", "@rollup/rollup-win32-arm64-msvc": "4.52.3", "@rollup/rollup-win32-ia32-msvc": "4.52.3", "@rollup/rollup-win32-x64-gnu": "4.52.3", "@rollup/rollup-win32-x64-msvc": "4.52.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"seroval": ["seroval@1.4.2", "", {}, "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ=="], "seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="],
"seroval-plugins": ["seroval-plugins@1.4.2", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-X7p4MEDTi+60o2sXZ4bnDBhgsUYDSkQEvzYZuJyFqWg9jcoPsHts5nrg5O956py2wyt28lUrBxk0M0/wU8URpA=="], "seroval-plugins": ["seroval-plugins@1.3.3", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w=="],
"solid-js": ["solid-js@1.9.9", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-A0ZBPJQldAeGCTW0YRYJmt7RCeh5rbFfPZ2aOttgYnctHE7HgKeHCBB/PVc2P7eOfmNXqMFFFoYYdm3S4dcbkA=="],
"source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
@@ -602,31 +641,31 @@
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], "tsx": ["tsx@4.20.6", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg=="],
"turbo": ["turbo@2.7.4", "", { "optionalDependencies": { "turbo-darwin-64": "2.7.4", "turbo-darwin-arm64": "2.7.4", "turbo-linux-64": "2.7.4", "turbo-linux-arm64": "2.7.4", "turbo-windows-64": "2.7.4", "turbo-windows-arm64": "2.7.4" }, "bin": { "turbo": "bin/turbo" } }, "sha512-bkO4AddmDishzJB2ze7aYYPaejMoJVfS0XnaR6RCdXFOY8JGJfQE+l9fKiV7uDPa5Ut44gmOWJL3894CIMeH9g=="], "turbo": ["turbo@2.5.8", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.8", "turbo-darwin-arm64": "2.5.8", "turbo-linux-64": "2.5.8", "turbo-linux-arm64": "2.5.8", "turbo-windows-64": "2.5.8", "turbo-windows-arm64": "2.5.8" }, "bin": { "turbo": "bin/turbo" } }, "sha512-5c9Fdsr9qfpT3hA0EyYSFRZj1dVVsb6KIWubA9JBYZ/9ZEAijgUEae0BBR/Xl/wekt4w65/lYLTFaP3JmwSO8w=="],
"turbo-darwin-64": ["turbo-darwin-64@2.7.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xDR30ltfkSsRfGzABBckvl1nz1cZ3ssTujvdj+TPwOweeDRvZ0e06t5DS0rmRBvyKpgGs42K/EK6Mn2qLlFY9A=="], "turbo-darwin-64": ["turbo-darwin-64@2.5.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Dh5bCACiHO8rUXZLpKw+m3FiHtAp2CkanSyJre+SInEvEr5kIxjGvCK/8MFX8SFRjQuhjtvpIvYYZJB4AGCxNQ=="],
"turbo-darwin-arm64": ["turbo-darwin-arm64@2.7.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-P7sjqXtOL/+nYWPvcDGWhi8wf8M8mZHHB8XEzw2VX7VJrS8IGHyJHGD1AYfDvhAEcr7pnk3gGifz3/xyhI655w=="], "turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-f1H/tQC9px7+hmXn6Kx/w8Jd/FneIUnvLlcI/7RGHunxfOkKJKvsoiNzySkoHQ8uq1pJnhJ0xNGTlYM48ZaJOQ=="],
"turbo-linux-64": ["turbo-linux-64@2.7.4", "", { "os": "linux", "cpu": "x64" }, "sha512-GofFOxRO/IhG8BcPyMSSB3Y2+oKQotsaYbHxL9yD6JPb20/o35eo+zUSyazOtilAwDHnak5dorAJFoFU8MIg2A=="], "turbo-linux-64": ["turbo-linux-64@2.5.8", "", { "os": "linux", "cpu": "x64" }, "sha512-hMyvc7w7yadBlZBGl/bnR6O+dJTx3XkTeyTTH4zEjERO6ChEs0SrN8jTFj1lueNXKIHh1SnALmy6VctKMGnWfw=="],
"turbo-linux-arm64": ["turbo-linux-arm64@2.7.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+RQKgNjksVPxYAyAgmDV7w/1qj++qca+nSNTAOKGOfJiDtSvRKoci89oftJ6anGs00uamLKVEQ712TI/tfNAIw=="], "turbo-linux-arm64": ["turbo-linux-arm64@2.5.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-LQELGa7bAqV2f+3rTMRPnj5G/OHAe2U+0N9BwsZvfMvHSUbsQ3bBMWdSQaYNicok7wOZcHjz2TkESn1hYK6xIQ=="],
"turbo-windows-64": ["turbo-windows-64@2.7.4", "", { "os": "win32", "cpu": "x64" }, "sha512-rfak1+g+ON3czs1mDYsCS4X74ZmK6gOgRQTXjDICtzvR4o61paqtgAYtNPofcVsMWeF4wvCajSeoAkkeAnQ1kg=="], "turbo-windows-64": ["turbo-windows-64@2.5.8", "", { "os": "win32", "cpu": "x64" }, "sha512-3YdcaW34TrN1AWwqgYL9gUqmZsMT4T7g8Y5Azz+uwwEJW+4sgcJkIi9pYFyU4ZBSjBvkfuPZkGgfStir5BBDJQ=="],
"turbo-windows-arm64": ["turbo-windows-arm64@2.7.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-1ZgBNjNRbDu/fPeqXuX9i26x3CJ/Y1gcwUpQ+Vp7kN9Un6RZ9kzs164f/knrjcu5E+szCRexVjRSJay1k5jApA=="], "turbo-windows-arm64": ["turbo-windows-arm64@2.5.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-eFC5XzLmgXJfnAK3UMTmVECCwuBcORrWdewoiXBnUm934DY6QN8YowC/srhNnROMpaKaqNeRpoB5FxCww3eteQ=="],
"type-fest": ["type-fest@5.4.1", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-xygQcmneDyzsEuKZrFbRMne5HDqMs++aFzefrJTgEIKjQ3rekM+RPfFCVq2Gp1VIDqddoYeppCj4Pcb+RZW0GQ=="], "type-fest": ["type-fest@5.0.1", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-9MpwAI52m8H6ssA542UxSLnSiSD2dsC3/L85g6hVubLSXd82wdI80eZwTWhdOfN67NlA+D+oipAs1MlcTcu3KA=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "undici-types": ["undici-types@7.13.0", "", {}, "sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ=="],
"unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="], "unplugin": ["unplugin@2.3.10", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw=="],
"update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
"use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
@@ -634,7 +673,7 @@
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
"vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], "vite": ["vite@7.1.8", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-oBXvfSHEOL8jF+R9Am7h59Up07kVVGH1NrFGFoEG6bPDZP3tGpQhvkBpy5x7U6+E6wZCu9OihsWgJqDbQIm8LQ=="],
"webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],
@@ -644,6 +683,8 @@
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],

View File

@@ -1,6 +1,6 @@
{ {
"name": "@effect-fc/monorepo", "name": "@effect-fc/monorepo",
"packageManager": "bun@1.3.3", "packageManager": "bun@1.2.23",
"private": true, "private": true,
"workspaces": [ "workspaces": [
"./packages/*" "./packages/*"
@@ -15,12 +15,12 @@
"clean:modules": "turbo clean:modules && rm -rf node_modules" "clean:modules": "turbo clean:modules && rm -rf node_modules"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^2.3.8", "@biomejs/biome": "^2.2.5",
"@effect/language-service": "^0.65.0", "@effect/language-service": "^0.48.0",
"@types/bun": "^1.3.3", "@types/bun": "^1.2.23",
"npm-check-updates": "^19.1.2", "npm-check-updates": "^19.0.0",
"npm-sort": "^0.0.4", "npm-sort": "^0.0.4",
"turbo": "^2.6.1", "turbo": "^2.5.8",
"typescript": "^5.9.3" "typescript": "^5.9.3"
} }
} }

View File

@@ -1,7 +1,7 @@
{ {
"name": "effect-fc", "name": "effect-fc",
"description": "Write React function components with Effect", "description": "Write React function components with Effect",
"version": "0.2.2", "version": "0.1.5",
"type": "module", "type": "module",
"files": [ "files": [
"./README.md", "./README.md",
@@ -37,12 +37,12 @@
"clean:dist": "rm -rf dist", "clean:dist": "rm -rf dist",
"clean:modules": "rm -rf node_modules" "clean:modules": "rm -rf node_modules"
}, },
"devDependencies": {
"@effect/platform-browser": "^0.74.0"
},
"peerDependencies": { "peerDependencies": {
"@types/react": "^19.2.0", "@types/react": "^19.0.0",
"effect": "^3.19.0", "effect": "^3.15.0",
"react": "^19.2.0" "react": "^19.0.0"
},
"dependencies": {
"@typed/async-data": "^0.13.1"
} }
} }

View File

@@ -4,7 +4,7 @@ import * as React from "react"
import * as Component from "./Component.js" import * as Component from "./Component.js"
export const TypeId: unique symbol = Symbol.for("@effect-fc/Async/Async") export const TypeId: unique symbol = Symbol.for("effect-fc/Async/Async")
export type TypeId = typeof TypeId export type TypeId = typeof TypeId
export interface Async extends Async.Options { export interface Async extends Async.Options {
@@ -20,7 +20,7 @@ export namespace Async {
} }
const AsyncProto = Object.freeze({ const SuspenseProto = Object.freeze({
[TypeId]: TypeId, [TypeId]: TypeId,
makeFunctionComponent<P extends {}, A extends React.ReactNode, E, R>( makeFunctionComponent<P extends {}, A extends React.ReactNode, E, R>(
@@ -63,7 +63,7 @@ export const async = <T extends Component.Component<any, any, any, any>>(
) => Object.setPrototypeOf( ) => Object.setPrototypeOf(
Object.assign(function() {}, self), Object.assign(function() {}, self),
Object.freeze(Object.setPrototypeOf( Object.freeze(Object.setPrototypeOf(
Object.assign({}, AsyncProto), Object.assign({}, SuspenseProto),
Object.getPrototypeOf(self), Object.getPrototypeOf(self),
)), )),
) )

View File

@@ -1,20 +1,13 @@
/** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */ /** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ /** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
import { Context, type Duration, Effect, Effectable, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, Layer, ManagedRuntime, Option, Predicate, Ref, Runtime, Scope, Tracer, type Utils } from "effect" import { Context, Effect, Effectable, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, Layer, ManagedRuntime, Option, Predicate, Ref, Runtime, Scope, Tracer, type Types, type Utils } from "effect"
import * as React from "react" import * as React from "react"
import { Memoized } from "./index.js" import { Memoized } from "./index.js"
export const TypeId: unique symbol = Symbol.for("@effect-fc/Component/Component") export const TypeId: unique symbol = Symbol.for("effect-fc/Component/Component")
export type TypeId = typeof TypeId export type TypeId = typeof TypeId
/**
* Interface representing an Effect-based React Component.
*
* This is both:
* - an Effect that produces a React function component
* - a constructor-like object with component metadata and options
*/
export interface Component<P extends {}, A extends React.ReactNode, E, R> export interface Component<P extends {}, A extends React.ReactNode, E, R>
extends extends
Effect.Effect<(props: P) => A, never, Exclude<R, Scope.Scope>>, Effect.Effect<(props: P) => A, never, Exclude<R, Scope.Scope>>,
@@ -27,6 +20,7 @@ extends
readonly "~Error": E readonly "~Error": E
readonly "~Context": R readonly "~Context": R
/** @internal */
readonly body: (props: P) => Effect.Effect<A, E, R> readonly body: (props: P) => Effect.Effect<A, E, R>
/** @internal */ /** @internal */
@@ -35,7 +29,7 @@ extends
): (props: P) => A ): (props: P) => A
} }
export declare namespace Component { export namespace Component {
export type Props<T extends Component<any, any, any, any>> = [T] extends [Component<infer P, infer _A, infer _E, infer _R>] ? P : never export type Props<T extends Component<any, any, any, any>> = [T] extends [Component<infer P, infer _A, infer _E, infer _R>] ? P : never
export type Success<T extends Component<any, any, any, any>> = [T] extends [Component<infer _P, infer A, infer _E, infer _R>] ? A : never export type Success<T extends Component<any, any, any, any>> = [T] extends [Component<infer _P, infer A, infer _E, infer _R>] ? A : never
export type Error<T extends Component<any, any, any, any>> = [T] extends [Component<infer _P, infer _A, infer E, infer _R>] ? E : never export type Error<T extends Component<any, any, any, any>> = [T] extends [Component<infer _P, infer _A, infer E, infer _R>] ? E : never
@@ -43,26 +37,18 @@ export declare namespace Component {
export type AsComponent<T extends Component<any, any, any, any>> = Component<Props<T>, Success<T>, Error<T>, Context<T>> export type AsComponent<T extends Component<any, any, any, any>> = Component<Props<T>, Success<T>, Error<T>, Context<T>>
/**
* Options that can be set on the component
*/
export interface Options { export interface Options {
/** Custom displayName for React DevTools and debugging */
readonly displayName?: string readonly displayName?: string
/** readonly finalizerExecutionMode: "sync" | "fork"
* Strategy used when executing finalizers on unmount/scope close
* @default ExecutionStrategy.sequential
*/
readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy
/**
* Debounce time before executing finalizers after component unmount
* Helps avoid unnecessary work during fast remount/remount cycles
* @default "100 millis"
*/
readonly finalizerExecutionDebounce: Duration.DurationInput
} }
} }
export interface ScopeOptions {
readonly finalizerExecutionMode?: "sync" | "fork"
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
}
const ComponentProto = Object.freeze({ const ComponentProto = Object.freeze({
...Effectable.CommitPrototype, ...Effectable.CommitPrototype,
@@ -102,17 +88,17 @@ const ComponentProto = Object.freeze({
}, },
} as const) } as const)
const defaultOptions: Component.Options = { const defaultOptions = {
finalizerExecutionMode: "fork",
finalizerExecutionStrategy: ExecutionStrategy.sequential, finalizerExecutionStrategy: ExecutionStrategy.sequential,
finalizerExecutionDebounce: "100 millis", } as const
}
const nonReactiveTags = [Tracer.ParentSpan] as const const nonReactiveTags = [Tracer.ParentSpan] as const
export const isComponent = (u: unknown): u is Component<{}, React.ReactNode, unknown, unknown> => Predicate.hasProperty(u, TypeId) export const isComponent = (u: unknown): u is Component<{}, React.ReactNode, unknown, unknown> => Predicate.hasProperty(u, TypeId)
export declare namespace make { export namespace make {
export type Gen = { export type Gen = {
<Eff extends Utils.YieldWrap<Effect.Effect<any, any, any>>, A extends React.ReactNode, P extends {} = {}>( <Eff extends Utils.YieldWrap<Effect.Effect<any, any, any>>, A extends React.ReactNode, P extends {} = {}>(
body: (props: P) => Generator<Eff, A, never> body: (props: P) => Generator<Eff, A, never>
@@ -337,11 +323,6 @@ export declare namespace make {
} }
} }
/**
* Creates an Effect-based React component.
*
* Follows the `Effect.fn` API. Supports both generator syntax (recommended) and direct Effect composition.
*/
export const make: ( export const make: (
& make.Gen & make.Gen
& make.NonGen & make.NonGen
@@ -370,12 +351,6 @@ export const make: (
} }
} }
/**
* Same as `make` but creates an untraced version (no automatic span created).
* Useful for very low-level utilities or when you want full control over tracing.
*
* Follows the `Effect.fnUntraced` API.
*/
export const makeUntraced: ( export const makeUntraced: (
& make.Gen & make.Gen
& make.NonGen & make.NonGen
@@ -397,9 +372,6 @@ export const makeUntraced: (
) )
) )
/**
* Creates a new component with modified options while preserving original behavior.
*/
export const withOptions: { export const withOptions: {
<T extends Component<any, any, any, any>>( <T extends Component<any, any, any, any>>(
options: Partial<Component.Options> options: Partial<Component.Options>
@@ -416,45 +388,12 @@ export const withOptions: {
Object.getPrototypeOf(self), Object.getPrototypeOf(self),
)) ))
/**
* Wraps an Effect-FC `Component` and turns it into a regular React function component
* that serves as an **entrypoint** into an Effect-FC component hierarchy.
*
* This is the recommended way to connect Effect-FC components to the rest of your React app,
* especially when using routers (TanStack Router, React Router, etc.), lazy-loaded routes,
* or any place where a standard React component is expected.
*
* The runtime is obtained from the provided React Context, allowing you to:
* - Provide dependencies once at a high level
* - Use the same runtime across an entire route tree or feature
*
* @example Using TanStack Router
* ```tsx
* // Main
* export const runtime = ReactRuntime.make(Layer.empty)
* function App() {
* return (
* <ReactRuntime.Provider runtime={runtime}>
* <RouterProvider router={router} />
* </ReactRuntime.Provider>
* )
* }
*
* // Route
* export const Route = createFileRoute("/")({
* component: withRuntime(HomePage, runtime.context),
* })
* ```
*
* @param self - The Effect-FC Component you want to render as a regular React component.
* @param context - React Context that holds the Runtime to use for this component tree. See the `ReactRuntime` module to create one.
*/
export const withRuntime: { export const withRuntime: {
<P extends {}, A extends React.ReactNode, E, R>( <P extends {}, A extends React.ReactNode, E, R>(
context: React.Context<Runtime.Runtime<R>>, context: React.Context<Runtime.Runtime<R>>,
): (self: Component<P, A, E, Scope.Scope | NoInfer<R>>) => (props: P) => A ): (self: Component<P, A, E, Types.NoInfer<R>>) => (props: P) => A
<P extends {}, A extends React.ReactNode, E, R>( <P extends {}, A extends React.ReactNode, E, R>(
self: Component<P, A, E, Scope.Scope | NoInfer<R>>, self: Component<P, A, E, Types.NoInfer<R>>,
context: React.Context<Runtime.Runtime<R>>, context: React.Context<Runtime.Runtime<R>>,
): (props: P) => A ): (props: P) => A
} = Function.dual(2, <P extends {}, A extends React.ReactNode, E, R>( } = Function.dual(2, <P extends {}, A extends React.ReactNode, E, R>(
@@ -468,11 +407,11 @@ export const withRuntime: {
}) })
export class ScopeMap extends Effect.Service<ScopeMap>()("@effect-fc/Component/ScopeMap", { export class ScopeMap extends Effect.Service<ScopeMap>()("effect-fc/Component/ScopeMap", {
effect: Effect.bind(Effect.Do, "ref", () => Ref.make(HashMap.empty<object, ScopeMap.Entry>())) effect: Effect.bind(Effect.Do, "ref", () => Ref.make(HashMap.empty<string, ScopeMap.Entry>()))
}) {} }) {}
export declare namespace ScopeMap { export namespace ScopeMap {
export interface Entry { export interface Entry {
readonly scope: Scope.CloseableScope readonly scope: Scope.CloseableScope
readonly closeFiber: Option.Option<Fiber.RuntimeFiber<void>> readonly closeFiber: Option.Option<Fiber.RuntimeFiber<void>>
@@ -480,42 +419,35 @@ export declare namespace ScopeMap {
} }
export declare namespace useScope { export const useScope: {
export interface Options { (
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
readonly finalizerExecutionDebounce?: Duration.DurationInput
}
}
export const useScope = Effect.fnUntraced(function*(
deps: React.DependencyList, deps: React.DependencyList,
options?: useScope.Options, options?: ScopeOptions,
): Effect.fn.Return<Scope.Scope> { ): Effect.Effect<Scope.Scope>
} = Effect.fnUntraced(function*(deps, options) {
// biome-ignore lint/style/noNonNullAssertion: context initialization // biome-ignore lint/style/noNonNullAssertion: context initialization
const runtimeRef = React.useRef<Runtime.Runtime<never>>(null!) const runtimeRef = React.useRef<Runtime.Runtime<never>>(null!)
runtimeRef.current = yield* Effect.runtime() runtimeRef.current = yield* Effect.runtime()
const key = React.useId()
const scopeMap = yield* ScopeMap as unknown as Effect.Effect<ScopeMap> const scopeMap = yield* ScopeMap as unknown as Effect.Effect<ScopeMap>
const [key, scope] = React.useMemo(() => Runtime.runSync(runtimeRef.current)(Effect.andThen( const scope = React.useMemo(() => Runtime.runSync(runtimeRef.current)(Effect.andThen(
Effect.all([Effect.succeed({}), scopeMap.ref]), scopeMap.ref,
([key, map]) => Effect.andThen( map => Option.match(HashMap.get(map, key), {
Option.match(HashMap.get(map, key), {
onSome: entry => Effect.succeed(entry.scope), onSome: entry => Effect.succeed(entry.scope),
onNone: () => Effect.tap( onNone: () => Effect.tap(
Scope.make(options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy), Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential),
scope => Ref.update(scopeMap.ref, HashMap.set(key, { scope => Ref.update(scopeMap.ref, HashMap.set(key, {
scope, scope,
closeFiber: Option.none(), closeFiber: Option.none(),
})), }))
), ),
}), }),
scope => [key, scope] as const,
),
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList // biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
)), deps) )), deps)
// biome-ignore lint/correctness/useExhaustiveDependencies: only reactive on "key" // biome-ignore lint/correctness/useExhaustiveDependencies: only reactive on "scope"
React.useEffect(() => Runtime.runSync(runtimeRef.current)(scopeMap.ref.pipe( React.useEffect(() => Runtime.runSync(runtimeRef.current)(scopeMap.ref.pipe(
Effect.andThen(HashMap.get(key)), Effect.andThen(HashMap.get(key)),
Effect.tap(entry => Option.match(entry.closeFiber, { Effect.tap(entry => Option.match(entry.closeFiber, {
@@ -527,7 +459,7 @@ export const useScope = Effect.fnUntraced(function*(
})), })),
Effect.map(({ scope }) => Effect.map(({ scope }) =>
() => Runtime.runSync(runtimeRef.current)(Effect.andThen( () => Runtime.runSync(runtimeRef.current)(Effect.andThen(
Effect.forkDaemon(Effect.sleep(options?.finalizerExecutionDebounce ?? defaultOptions.finalizerExecutionDebounce).pipe( Effect.forkDaemon(Effect.sleep("100 millis").pipe(
Effect.andThen(Scope.close(scope, Exit.void)), Effect.andThen(Scope.close(scope, Exit.void)),
Effect.andThen(Ref.update(scopeMap.ref, HashMap.remove(key))), Effect.andThen(Ref.update(scopeMap.ref, HashMap.remove(key))),
)), )),
@@ -537,63 +469,17 @@ export const useScope = Effect.fnUntraced(function*(
})), })),
)) ))
), ),
)), [key]) )), [scope])
return scope return scope
}) })
export const useOnMount = Effect.fnUntraced(function* <A, E, R>( const closeScope = (
f: () => Effect.Effect<A, E, R> scope: Scope.CloseableScope,
): Effect.fn.Return<A, E, R> { runtime: Runtime.Runtime<never>,
const runtime = yield* Effect.runtime<R>() options?: ScopeOptions,
return yield* React.useState(() => Runtime.runSync(runtime)(Effect.cached(f())))[0] ) => {
}) switch (options?.finalizerExecutionMode ?? "sync") {
export declare namespace useOnChange {
export interface Options extends useScope.Options {}
}
export const useOnChange = Effect.fnUntraced(function* <A, E, R>(
f: () => Effect.Effect<A, E, R>,
deps: React.DependencyList,
options?: useOnChange.Options,
): Effect.fn.Return<A, E, Exclude<R, Scope.Scope>> {
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
const scope = yield* useScope(deps, options)
// biome-ignore lint/correctness/useExhaustiveDependencies: only reactive on "scope"
return yield* React.useMemo(() => Runtime.runSync(runtime)(
Effect.cached(Effect.provideService(f(), Scope.Scope, scope))
), [scope])
})
export declare namespace useReactEffect {
export interface Options {
readonly finalizerExecutionMode?: "sync" | "fork"
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
}
}
export const useReactEffect = Effect.fnUntraced(function* <E, R>(
f: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: useReactEffect.Options,
): Effect.fn.Return<void, never, Exclude<R, Scope.Scope>> {
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
React.useEffect(() => runReactEffect(runtime, f, options), deps)
})
const runReactEffect = <E, R>(
runtime: Runtime.Runtime<Exclude<R, Scope.Scope>>,
f: () => Effect.Effect<void, E, R>,
options?: useReactEffect.Options,
) => Effect.Do.pipe(
Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy)),
Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(f(), Scope.Scope, scope))),
Effect.map(({ scope }) =>
() => {
switch (options?.finalizerExecutionMode ?? "fork") {
case "sync": case "sync":
Runtime.runSync(runtime)(Scope.close(scope, Exit.void)) Runtime.runSync(runtime)(Scope.close(scope, Exit.void))
break break
@@ -602,40 +488,89 @@ const runReactEffect = <E, R>(
break break
} }
} }
),
Runtime.runSync(runtime),
)
export declare namespace useReactLayoutEffect { export const useOnMount: {
export interface Options extends useReactEffect.Options {} <A, E, R>(
} f: () => Effect.Effect<A, E, R>
): Effect.Effect<A, E, R>
export const useReactLayoutEffect = Effect.fnUntraced(function* <E, R>( } = Effect.fnUntraced(function* <A, E, R>(
f: () => Effect.Effect<void, E, R>, f: () => Effect.Effect<A, E, R>
deps?: React.DependencyList, ) {
options?: useReactLayoutEffect.Options, const runtime = yield* Effect.runtime<R>()
): Effect.fn.Return<void, never, Exclude<R, Scope.Scope>> { return yield* React.useState(() => Runtime.runSync(runtime)(Effect.cached(f())))[0]
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
React.useLayoutEffect(() => runReactEffect(runtime, f, options), deps)
}) })
export const useRunSync = <R = never>(): Effect.Effect< export const useOnChange: {
<A, E = never>(effect: Effect.Effect<A, E, Scope.Scope | R>) => A, <A, E, R>(
never, f: () => Effect.Effect<A, E, R>,
Scope.Scope | R deps: React.DependencyList,
> => Effect.andThen(Effect.runtime(), Runtime.runSync) ): Effect.Effect<A, E, R>
} = Effect.fnUntraced(function* <A, E, R>(
f: () => Effect.Effect<A, E, R>,
deps: React.DependencyList,
) {
const runtime = yield* Effect.runtime<R>()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
return yield* React.useMemo(() => Runtime.runSync(runtime)(Effect.cached(f())), deps)
})
export const useRunPromise = <R = never>(): Effect.Effect< export const useReactEffect: {
<A, E = never>(effect: Effect.Effect<A, E, Scope.Scope | R>) => Promise<A>, <E, R>(
never, f: () => Effect.Effect<void, E, R>,
Scope.Scope | R deps?: React.DependencyList,
> => Effect.andThen(Effect.runtime(), context => Runtime.runPromise(context)) options?: ScopeOptions,
): Effect.Effect<void, never, Exclude<R, Scope.Scope>>
} = Effect.fnUntraced(function* <E, R>(
f: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: ScopeOptions,
) {
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
export const useCallbackSync = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>( React.useEffect(() => Effect.Do.pipe(
Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)),
Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(f(), Scope.Scope, scope))),
Effect.map(({ scope }) =>
() => closeScope(scope, runtime, options)
),
Runtime.runSync(runtime),
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
), deps)
})
export const useReactLayoutEffect: {
<E, R>(
f: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: ScopeOptions,
): Effect.Effect<void, never, Exclude<R, Scope.Scope>>
} = Effect.fnUntraced(function* <E, R>(
f: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: ScopeOptions,
) {
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
React.useLayoutEffect(() => Effect.Do.pipe(
Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)),
Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(f(), Scope.Scope, scope))),
Effect.map(({ scope }) =>
() => closeScope(scope, runtime, options)
),
Runtime.runSync(runtime),
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
), deps)
})
export const useCallbackSync: {
<Args extends unknown[], A, E, R>(
f: (...args: Args) => Effect.Effect<A, E, R>, f: (...args: Args) => Effect.Effect<A, E, R>,
deps: React.DependencyList, deps: React.DependencyList,
): Effect.fn.Return<(...args: Args) => A, never, R> { ): Effect.Effect<(...args: Args) => A, never, R>
} = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>(
f: (...args: Args) => Effect.Effect<A, E, R>,
deps: React.DependencyList,
) {
// biome-ignore lint/style/noNonNullAssertion: context initialization // biome-ignore lint/style/noNonNullAssertion: context initialization
const runtimeRef = React.useRef<Runtime.Runtime<R>>(null!) const runtimeRef = React.useRef<Runtime.Runtime<R>>(null!)
runtimeRef.current = yield* Effect.runtime<R>() runtimeRef.current = yield* Effect.runtime<R>()
@@ -644,10 +579,15 @@ export const useCallbackSync = Effect.fnUntraced(function* <Args extends unknown
return React.useCallback((...args: Args) => Runtime.runSync(runtimeRef.current)(f(...args)), deps) return React.useCallback((...args: Args) => Runtime.runSync(runtimeRef.current)(f(...args)), deps)
}) })
export const useCallbackPromise = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>( export const useCallbackPromise: {
<Args extends unknown[], A, E, R>(
f: (...args: Args) => Effect.Effect<A, E, R>, f: (...args: Args) => Effect.Effect<A, E, R>,
deps: React.DependencyList, deps: React.DependencyList,
): Effect.fn.Return<(...args: Args) => Promise<A>, never, R> { ): Effect.Effect<(...args: Args) => Promise<A>, never, R>
} = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>(
f: (...args: Args) => Effect.Effect<A, E, R>,
deps: React.DependencyList,
) {
// biome-ignore lint/style/noNonNullAssertion: context initialization // biome-ignore lint/style/noNonNullAssertion: context initialization
const runtimeRef = React.useRef<Runtime.Runtime<R>>(null!) const runtimeRef = React.useRef<Runtime.Runtime<R>>(null!)
runtimeRef.current = yield* Effect.runtime<R>() runtimeRef.current = yield* Effect.runtime<R>()
@@ -656,16 +596,22 @@ export const useCallbackPromise = Effect.fnUntraced(function* <Args extends unkn
return React.useCallback((...args: Args) => Runtime.runPromise(runtimeRef.current)(f(...args)), deps) return React.useCallback((...args: Args) => Runtime.runPromise(runtimeRef.current)(f(...args)), deps)
}) })
export declare namespace useContext { export const useContext: {
export interface Options extends useOnChange.Options {} <ROut, E, RIn>(
}
export const useContext = <ROut, E, RIn>(
layer: Layer.Layer<ROut, E, RIn>, layer: Layer.Layer<ROut, E, RIn>,
options?: useContext.Options, options?: ScopeOptions,
): Effect.Effect<Context.Context<ROut>, E, Scope.Scope | RIn> => useOnChange(() => Effect.context<RIn>().pipe( ): Effect.Effect<Context.Context<ROut>, E, RIn>
} = Effect.fnUntraced(function* <ROut, E, RIn>(
layer: Layer.Layer<ROut, E, RIn>,
options?: ScopeOptions,
) {
const scope = yield* useScope([layer], options)
return yield* useOnChange(() => Effect.context<RIn>().pipe(
Effect.map(context => ManagedRuntime.make(Layer.provide(layer, Layer.succeedContext(context)))), Effect.map(context => ManagedRuntime.make(Layer.provide(layer, Layer.succeedContext(context)))),
Effect.tap(runtime => Effect.addFinalizer(() => runtime.disposeEffect)), Effect.tap(runtime => Effect.addFinalizer(() => runtime.disposeEffect)),
Effect.andThen(runtime => runtime.runtimeEffect), Effect.andThen(runtime => runtime.runtimeEffect),
Effect.andThen(runtime => runtime.context), Effect.andThen(runtime => runtime.context),
), [layer], options) Effect.provideService(Scope.Scope, scope),
), [scope])
})

View File

@@ -1,62 +0,0 @@
import { type Cause, Context, Effect, Exit, Layer, Option, Pipeable, Predicate, PubSub, type Queue, type Scope, Supervisor } from "effect"
export const TypeId: unique symbol = Symbol.for("@effect-fc/ErrorObserver/ErrorObserver")
export type TypeId = typeof TypeId
export interface ErrorObserver<in out E = never> extends Pipeable.Pipeable {
readonly [TypeId]: TypeId
handle<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
readonly subscribe: Effect.Effect<Queue.Dequeue<Cause.Cause<E>>, never, Scope.Scope>
}
export const ErrorObserver = <E = never>(): Context.Tag<ErrorObserver, ErrorObserver<E>> => Context.GenericTag("@effect-fc/ErrorObserver/ErrorObserver")
class ErrorObserverImpl<in out E = never>
extends Pipeable.Class() implements ErrorObserver<E> {
readonly [TypeId]: TypeId = TypeId
readonly subscribe: Effect.Effect<Queue.Dequeue<Cause.Cause<E>>, never, Scope.Scope>
constructor(
readonly pubsub: PubSub.PubSub<Cause.Cause<E>>
) {
super()
this.subscribe = pubsub.subscribe
}
handle<A, EffE, R>(effect: Effect.Effect<A, EffE, R>): Effect.Effect<A, EffE, R> {
return Effect.tapErrorCause(effect, cause => PubSub.publish(this.pubsub, cause as Cause.Cause<E>))
}
}
class ErrorObserverSupervisorImpl extends Supervisor.AbstractSupervisor<void> {
readonly value = Effect.void
constructor(readonly pubsub: PubSub.PubSub<Cause.Cause<never>>) {
super()
}
onEnd<A, E>(_value: Exit.Exit<A, E>): void {
if (Exit.isFailure(_value)) {
Effect.runSync(PubSub.publish(this.pubsub, _value.cause as Cause.Cause<never>))
}
}
}
export const isErrorObserver = (u: unknown): u is ErrorObserver<unknown> => Predicate.hasProperty(u, TypeId)
export const layer: Layer.Layer<ErrorObserver> = Layer.unwrapEffect(Effect.map(
PubSub.unbounded<Cause.Cause<never>>(),
pubsub => Layer.merge(
Supervisor.addSupervisor(new ErrorObserverSupervisorImpl(pubsub)),
Layer.succeed(ErrorObserver(), new ErrorObserverImpl(pubsub)),
),
))
export const handle = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => Effect.andThen(
Effect.serviceOption(ErrorObserver()),
Option.match({
onSome: observer => observer.handle(effect),
onNone: () => effect,
}),
)

View File

@@ -1,237 +1,219 @@
import { Array, Cause, Chunk, type Context, type Duration, Effect, Equal, Exit, Fiber, flow, Hash, HashMap, identity, Option, ParseResult, Pipeable, Predicate, Ref, Schema, type Scope, Stream } from "effect" import * as AsyncData from "@typed/async-data"
import type * as React from "react" import { Array, Cause, Chunk, type Duration, Effect, Equal, Exit, Fiber, flow, identity, Option, ParseResult, Pipeable, Predicate, Ref, Schema, type Scope, Stream } from "effect"
import type { NoSuchElementException } from "effect/Cause"
import * as React from "react"
import * as Component from "./Component.js" import * as Component from "./Component.js"
import * as Mutation from "./Mutation.js"
import * as PropertyPath from "./PropertyPath.js" import * as PropertyPath from "./PropertyPath.js"
import * as Result from "./Result.js"
import * as Subscribable from "./Subscribable.js" import * as Subscribable from "./Subscribable.js"
import * as SubscriptionRef from "./SubscriptionRef.js" import * as SubscriptionRef from "./SubscriptionRef.js"
import * as SubscriptionSubRef from "./SubscriptionSubRef.js" import * as SubscriptionSubRef from "./SubscriptionSubRef.js"
export const FormTypeId: unique symbol = Symbol.for("@effect-fc/Form/Form") export const FormTypeId: unique symbol = Symbol.for("effect-fc/Form/Form")
export type FormTypeId = typeof FormTypeId export type FormTypeId = typeof FormTypeId
export interface Form<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never> export interface Form<in out A, in out I = A, out R = never, in out SA = void, in out SE = A, out SR = never>
extends Pipeable.Pipeable { extends Pipeable.Pipeable {
readonly [FormTypeId]: FormTypeId readonly [FormTypeId]: FormTypeId
readonly schema: Schema.Schema<A, I, R> readonly schema: Schema.Schema<A, I, R>
readonly context: Context.Context<Scope.Scope | R> readonly onSubmit: (value: NoInfer<A>) => Effect.Effect<SA, SE, SR>
readonly mutation: Mutation.Mutation<
readonly [value: A, form: Form<A, I, R, unknown, unknown, unknown>],
MA, ME, MR, MP
>
readonly autosubmit: boolean readonly autosubmit: boolean
readonly debounce: Option.Option<Duration.DurationInput> readonly debounce: Option.Option<Duration.DurationInput>
readonly value: Subscribable.Subscribable<Option.Option<A>> readonly valueRef: SubscriptionRef.SubscriptionRef<Option.Option<A>>
readonly encodedValue: SubscriptionRef.SubscriptionRef<I> readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>
readonly error: Subscribable.Subscribable<Option.Option<ParseResult.ParseError>> readonly errorRef: SubscriptionRef.SubscriptionRef<Option.Option<ParseResult.ParseError>>
readonly validationFiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, ParseResult.ParseError>>> readonly validationFiberRef: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<void, never>>>
readonly submitStateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<SA, SE>>
readonly canSubmit: Subscribable.Subscribable<boolean> readonly canSubmitSubscribable: Subscribable.Subscribable<boolean>
field<const P extends PropertyPath.Paths<I>>(
path: P
): Effect.Effect<FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>>
readonly run: Effect.Effect<void>
readonly submit: Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException>
} }
export class FormImpl<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never> class FormImpl<in out A, in out I = A, out R = never, in out SA = void, in out SE = A, out SR = never>
extends Pipeable.Class() implements Form<A, I, R, MA, ME, MR, MP> { extends Pipeable.Class() implements Form<A, I, R, SA, SE, SR> {
readonly [FormTypeId]: FormTypeId = FormTypeId readonly [FormTypeId]: FormTypeId = FormTypeId
constructor( constructor(
readonly schema: Schema.Schema<A, I, R>, readonly schema: Schema.Schema<A, I, R>,
readonly context: Context.Context<Scope.Scope | R>, readonly onSubmit: (value: NoInfer<A>) => Effect.Effect<SA, SE, SR>,
readonly mutation: Mutation.Mutation<
readonly [value: A, form: Form<A, I, R, unknown, unknown, unknown>],
MA, ME, MR, MP
>,
readonly autosubmit: boolean, readonly autosubmit: boolean,
readonly debounce: Option.Option<Duration.DurationInput>, readonly debounce: Option.Option<Duration.DurationInput>,
readonly value: SubscriptionRef.SubscriptionRef<Option.Option<A>>, readonly valueRef: SubscriptionRef.SubscriptionRef<Option.Option<A>>,
readonly encodedValue: SubscriptionRef.SubscriptionRef<I>, readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>,
readonly error: SubscriptionRef.SubscriptionRef<Option.Option<ParseResult.ParseError>>, readonly errorRef: SubscriptionRef.SubscriptionRef<Option.Option<ParseResult.ParseError>>,
readonly validationFiber: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, ParseResult.ParseError>>>, readonly validationFiberRef: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<void, never>>>,
readonly submitStateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<SA, SE>>,
readonly runSemaphore: Effect.Semaphore, readonly canSubmitSubscribable: Subscribable.Subscribable<boolean>,
readonly fieldCache: Ref.Ref<HashMap.HashMap<FormFieldKey, FormField<unknown, unknown>>>,
) { ) {
super() super()
this.canSubmit = Subscribable.map(
Subscribable.zipLatestAll(this.value, this.error, this.validationFiber, this.mutation.result),
([value, error, validationFiber, result]) => (
Option.isSome(value) &&
Option.isNone(error) &&
Option.isNone(validationFiber) &&
!(Result.isRunning(result) || Result.hasRefreshingFlag(result))
),
)
}
field<const P extends PropertyPath.Paths<I>>(
path: P
): Effect.Effect<FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>> {
const key = new FormFieldKey(path)
return this.fieldCache.pipe(
Effect.map(HashMap.get(key)),
Effect.flatMap(Option.match({
onSome: v => Effect.succeed(v as FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>),
onNone: () => Effect.tap(
Effect.succeed(makeFormField(this as Form<A, I, R, MA, ME, MR, MP>, path)),
v => Ref.update(this.fieldCache, HashMap.set(key, v as FormField<unknown, unknown>)),
),
})),
)
}
readonly canSubmit: Subscribable.Subscribable<boolean>
get run(): Effect.Effect<void> {
return this.runSemaphore.withPermits(1)(Stream.runForEach(
this.encodedValue.changes.pipe(
Option.isSome(this.debounce) ? Stream.debounce(this.debounce.value) : identity
),
encodedValue => this.validationFiber.pipe(
Effect.andThen(Option.match({
onSome: Fiber.interrupt,
onNone: () => Effect.void,
})),
Effect.andThen(
Effect.forkScoped(Effect.onExit(
Schema.decode(this.schema, { errors: "all" })(encodedValue),
exit => Effect.andThen(
Exit.matchEffect(exit, {
onSuccess: v => Effect.andThen(
Ref.set(this.value, Option.some(v)),
Ref.set(this.error, Option.none()),
),
onFailure: c => Option.match(Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError"), {
onSome: e => Ref.set(this.error, Option.some(e)),
onNone: () => Effect.void,
}),
}),
Ref.set(this.validationFiber, Option.none()),
),
)).pipe(
Effect.tap(fiber => Ref.set(this.validationFiber, Option.some(fiber))),
Effect.andThen(Fiber.join),
Effect.andThen(value => this.autosubmit
? Effect.asVoid(Effect.forkScoped(this.submitValue(value)))
: Effect.void
),
Effect.forkScoped,
)
),
Effect.provide(this.context),
),
))
}
get submit(): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException> {
return this.value.pipe(
Effect.andThen(identity),
Effect.andThen(value => this.submitValue(value)),
)
}
submitValue(value: A): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>> {
return Effect.whenEffect(
Effect.tap(
this.mutation.mutate([value, this as any]),
result => Result.isFailure(result)
? Option.match(
Chunk.findFirst(
Cause.failures(result.cause as Cause.Cause<ParseResult.ParseError>),
e => e._tag === "ParseError",
),
{
onSome: e => Ref.set(this.error, Option.some(e)),
onNone: () => Effect.void,
},
)
: Effect.void
),
this.canSubmit.get,
)
} }
} }
export const isForm = (u: unknown): u is Form<unknown, unknown, unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, FormTypeId) export const isForm = (u: unknown): u is Form<unknown, unknown, unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, FormTypeId)
export declare namespace make { export namespace make {
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never> export interface Options<in out A, in out I, in out R, in out SA = void, in out SE = A, out SR = never> {
extends Mutation.make.Options<
readonly [value: NoInfer<A>, form: Form<NoInfer<A>, NoInfer<I>, NoInfer<R>, unknown, unknown, unknown>],
MA, ME, MR, MP
> {
readonly schema: Schema.Schema<A, I, R> readonly schema: Schema.Schema<A, I, R>
readonly initialEncodedValue: NoInfer<I> readonly initialEncodedValue: NoInfer<I>
readonly onSubmit: (
this: Form<NoInfer<A>, NoInfer<I>, NoInfer<R>, unknown, unknown, unknown>,
value: NoInfer<A>,
) => Effect.Effect<SA, SE, SR>
readonly autosubmit?: boolean readonly autosubmit?: boolean
readonly debounce?: Duration.DurationInput readonly debounce?: Duration.DurationInput
} }
} }
export const make = Effect.fnUntraced(function* <A, I = A, R = never, MA = void, ME = never, MR = never, MP = never>( export const make: {
options: make.Options<A, I, R, MA, ME, MR, MP> <A, I = A, R = never, SA = void, SE = A, SR = never>(
): Effect.fn.Return< options: make.Options<A, I, R, SA, SE, SR>
Form<A, I, R, MA, ME, Result.forkEffect.OutputContext<MA, ME, MR, MP>, MP>, ): Effect.Effect<Form<A, I, R, SA, SE, SR>>
never, } = Effect.fnUntraced(function* <A, I = A, R = never, SA = void, SE = A, SR = never>(
Scope.Scope | R | Result.forkEffect.OutputContext<MA, ME, MR, MP> options: make.Options<A, I, R, SA, SE, SR>
> { ) {
const valueRef = yield* SubscriptionRef.make(Option.none<A>())
const errorRef = yield* SubscriptionRef.make(Option.none<ParseResult.ParseError>())
const validationFiberRef = yield* SubscriptionRef.make(Option.none<Fiber.Fiber<void, never>>())
const submitStateRef = yield* SubscriptionRef.make(AsyncData.noData<SA, SE>())
return new FormImpl( return new FormImpl(
options.schema, options.schema,
yield* Effect.context<Scope.Scope | R>(), options.onSubmit,
yield* Mutation.make(options),
options.autosubmit ?? false, options.autosubmit ?? false,
Option.fromNullable(options.debounce), Option.fromNullable(options.debounce),
yield* SubscriptionRef.make(Option.none<A>()), valueRef,
yield* SubscriptionRef.make(options.initialEncodedValue), yield* SubscriptionRef.make(options.initialEncodedValue),
yield* SubscriptionRef.make(Option.none<ParseResult.ParseError>()), errorRef,
yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, ParseResult.ParseError>>()), validationFiberRef,
submitStateRef,
yield* Effect.makeSemaphore(1), Subscribable.map(
yield* Ref.make(HashMap.empty<FormFieldKey, FormField<unknown, unknown>>()), Subscribable.zipLatestAll(valueRef, errorRef, validationFiberRef, submitStateRef),
([value, error, validationFiber, submitState]) => (
Option.isSome(value) &&
Option.isNone(error) &&
Option.isNone(validationFiber) &&
!AsyncData.isLoading(submitState)
),
),
) )
}) })
export declare namespace service { export const run = <A, I, R, SA, SE, SR>(
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never> self: Form<A, I, R, SA, SE, SR>
extends make.Options<A, I, R, MA, ME, MR, MP> {} ): Effect.Effect<void, never, Scope.Scope | R | SR> => Stream.runForEach(
self.encodedValueRef.changes.pipe(
Option.isSome(self.debounce) ? Stream.debounce(self.debounce.value) : identity
),
encodedValue => self.validationFiberRef.pipe(
Effect.andThen(Option.match({
onSome: Fiber.interrupt,
onNone: () => Effect.void,
})),
Effect.andThen(
Effect.addFinalizer(() => Ref.set(self.validationFiberRef, Option.none())).pipe(
Effect.andThen(Schema.decode(self.schema, { errors: "all" })(encodedValue)),
Effect.exit,
Effect.andThen(flow(
Exit.matchEffect({
onSuccess: v => Ref.set(self.valueRef, Option.some(v)).pipe(
Effect.andThen(Ref.set(self.errorRef, Option.none())),
Effect.as(Option.some(v)),
),
onFailure: c => Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError").pipe(
Option.match({
onSome: e => Ref.set(self.errorRef, Option.some(e)),
onNone: () => Effect.void,
}),
Effect.as(Option.none<A>()),
),
}),
Effect.uninterruptible,
)),
Effect.scoped,
Effect.andThen(value => Option.isSome(value) && self.autosubmit
? Effect.asVoid(Effect.forkScoped(submit(self)))
: Effect.void
),
Effect.forkScoped,
)
),
Effect.andThen(fiber => Ref.set(self.validationFiberRef, Option.some(fiber)))
),
)
export const submit = <A, I, R, SA, SE, SR>(
self: Form<A, I, R, SA, SE, SR>
): Effect.Effect<Option.Option<AsyncData.AsyncData<SA, SE>>, NoSuchElementException, SR> => Effect.whenEffect(
self.valueRef.pipe(
Effect.andThen(identity),
Effect.tap(Ref.set(self.submitStateRef, AsyncData.loading())),
Effect.andThen(flow(
self.onSubmit as (value: NoInfer<A>) => Effect.Effect<SA, SE | ParseResult.ParseError, SR>,
Effect.tapErrorTag("ParseError", e => Ref.set(self.errorRef, Option.some(e as ParseResult.ParseError))),
Effect.exit,
Effect.map(Exit.match({
onSuccess: a => AsyncData.success(a),
onFailure: e => AsyncData.failure(e as Cause.Cause<SE>),
})),
Effect.tap(v => Ref.set(self.submitStateRef, v)),
)),
),
self.canSubmitSubscribable.get,
)
export namespace service {
export interface Options<in out A, in out I, in out R, in out SA = void, in out SE = A, out SR = never>
extends make.Options<A, I, R, SA, SE, SR> {}
} }
export const service = <A, I = A, R = never, MA = void, ME = never, MR = never, MP = never>( export const service = <A, I = A, R = never, SA = void, SE = A, SR = never>(
options: service.Options<A, I, R, MA, ME, MR, MP> options: service.Options<A, I, R, SA, SE, SR>
): Effect.Effect< ): Effect.Effect<Form<A, I, R, SA, SE, SR>, never, Scope.Scope | R | SR> => Effect.tap(
Form<A, I, R, MA, ME, Result.forkEffect.OutputContext<MA, ME, MR, MP>, MP>,
never,
Scope.Scope | R | Result.forkEffect.OutputContext<MA, ME, MR, MP>
> => Effect.tap(
make(options), make(options),
form => Effect.forkScoped(form.run), form => Effect.forkScoped(run(form)),
)
export const field = <A, I, R, SA, SE, SR, const P extends PropertyPath.Paths<NoInfer<I>>>(
self: Form<A, I, R, SA, SE, SR>,
path: P,
): FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>> => new FormFieldImpl(
Subscribable.mapEffect(self.valueRef, Option.match({
onSome: v => Option.map(PropertyPath.get(v, path), Option.some),
onNone: () => Option.some(Option.none()),
})),
SubscriptionSubRef.makeFromPath(self.encodedValueRef, path),
Subscribable.mapEffect(self.errorRef, Option.match({
onSome: flow(
ParseResult.ArrayFormatter.formatError,
Effect.map(Array.filter(issue => PropertyPath.equivalence(issue.path, path))),
),
onNone: () => Effect.succeed([]),
})),
Subscribable.map(self.validationFiberRef, Option.isSome),
Subscribable.map(self.submitStateRef, AsyncData.isLoading)
) )
export const FormFieldTypeId: unique symbol = Symbol.for("@effect-fc/Form/FormField") export const FormFieldTypeId: unique symbol = Symbol.for("effect-fc/FormField")
export type FormFieldTypeId = typeof FormFieldTypeId export type FormFieldTypeId = typeof FormFieldTypeId
export interface FormField<in out A, in out I = A> export interface FormField<in out A, in out I = A>
extends Pipeable.Pipeable { extends Pipeable.Pipeable {
readonly [FormFieldTypeId]: FormFieldTypeId readonly [FormFieldTypeId]: FormFieldTypeId
readonly value: Subscribable.Subscribable<Option.Option<A>, Cause.NoSuchElementException> readonly valueSubscribable: Subscribable.Subscribable<Option.Option<A>, NoSuchElementException>
readonly encodedValue: SubscriptionRef.SubscriptionRef<I> readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>
readonly issues: Subscribable.Subscribable<readonly ParseResult.ArrayFormatterIssue[]> readonly issuesSubscribable: Subscribable.Subscribable<readonly ParseResult.ArrayFormatterIssue[]>
readonly isValidating: Subscribable.Subscribable<boolean> readonly isValidatingSubscribable: Subscribable.Subscribable<boolean>
readonly isSubmitting: Subscribable.Subscribable<boolean> readonly isSubmittingSubscribable: Subscribable.Subscribable<boolean>
} }
class FormFieldImpl<in out A, in out I = A> class FormFieldImpl<in out A, in out I = A>
@@ -239,77 +221,61 @@ extends Pipeable.Class() implements FormField<A, I> {
readonly [FormFieldTypeId]: FormFieldTypeId = FormFieldTypeId readonly [FormFieldTypeId]: FormFieldTypeId = FormFieldTypeId
constructor( constructor(
readonly value: Subscribable.Subscribable<Option.Option<A>, Cause.NoSuchElementException>, readonly valueSubscribable: Subscribable.Subscribable<Option.Option<A>, NoSuchElementException>,
readonly encodedValue: SubscriptionRef.SubscriptionRef<I>, readonly encodedValueRef: SubscriptionRef.SubscriptionRef<I>,
readonly issues: Subscribable.Subscribable<readonly ParseResult.ArrayFormatterIssue[]>, readonly issuesSubscribable: Subscribable.Subscribable<readonly ParseResult.ArrayFormatterIssue[]>,
readonly isValidating: Subscribable.Subscribable<boolean>, readonly isValidatingSubscribable: Subscribable.Subscribable<boolean>,
readonly isSubmitting: Subscribable.Subscribable<boolean>, readonly isSubmittingSubscribable: Subscribable.Subscribable<boolean>,
) { ) {
super() super()
} }
} }
const FormFieldKeyTypeId: unique symbol = Symbol.for("@effect-fc/Form/FormFieldKey")
type FormFieldKeyTypeId = typeof FormFieldKeyTypeId
class FormFieldKey implements Equal.Equal {
readonly [FormFieldKeyTypeId]: FormFieldKeyTypeId = FormFieldKeyTypeId
constructor(readonly path: PropertyPath.PropertyPath) {}
[Equal.symbol](that: Equal.Equal) {
return isFormFieldKey(that) && PropertyPath.equivalence(this.path, that.path)
}
[Hash.symbol]() {
return Hash.array(this.path)
}
}
export const isFormField = (u: unknown): u is FormField<unknown, unknown> => Predicate.hasProperty(u, FormFieldTypeId) export const isFormField = (u: unknown): u is FormField<unknown, unknown> => Predicate.hasProperty(u, FormFieldTypeId)
const isFormFieldKey = (u: unknown): u is FormFieldKey => Predicate.hasProperty(u, FormFieldKeyTypeId)
export const makeFormField = <A, I, R, MA, ME, MR, MP, const P extends PropertyPath.Paths<NoInfer<I>>>(
self: Form<A, I, R, MA, ME, MR, MP>, export const useSubmit = <A, I, R, SA, SE, SR>(
self: Form<A, I, R, SA, SE, SR>
): Effect.Effect<
() => Promise<Option.Option<AsyncData.AsyncData<SA, SE>>>,
never,
SR
> => Component.useCallbackPromise(() => submit(self), [self])
export const useField = <A, I, R, SA, SE, SR, const P extends PropertyPath.Paths<NoInfer<I>>>(
self: Form<A, I, R, SA, SE, SR>,
path: P, path: P,
): FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>> => { ): FormField<
return new FormFieldImpl( PropertyPath.ValueFromPath<A, P>,
Subscribable.mapEffect(self.value, Option.match({ PropertyPath.ValueFromPath<I, P>
onSome: v => Option.map(PropertyPath.get(v, path), Option.some), // biome-ignore lint/correctness/useExhaustiveDependencies: individual path components need to be compared
onNone: () => Option.some(Option.none()), > => React.useMemo(() => field(self, path), [self, ...path])
})),
SubscriptionSubRef.makeFromPath(self.encodedValue, path),
Subscribable.mapEffect(self.error, Option.match({
onSome: flow(
ParseResult.ArrayFormatter.formatError,
Effect.map(Array.filter(issue => PropertyPath.equivalence(issue.path, path))),
),
onNone: () => Effect.succeed([]),
})),
Subscribable.map(self.validationFiber, Option.isSome),
Subscribable.map(self.mutation.result, result => Result.isRunning(result) || Result.hasRefreshingFlag(result)),
)
}
export namespace useInput { export namespace useInput {
export interface Options { export interface Options {
readonly debounce?: Duration.DurationInput readonly debounce?: Duration.DurationInput
} }
export interface Success<T> { export interface Result<T> {
readonly value: T readonly value: T
readonly setValue: React.Dispatch<React.SetStateAction<T>> readonly setValue: React.Dispatch<React.SetStateAction<T>>
} }
} }
export const useInput = Effect.fnUntraced(function* <A, I>( export const useInput: {
<A, I>(
field: FormField<A, I>, field: FormField<A, I>,
options?: useInput.Options, options?: useInput.Options,
): Effect.fn.Return<useInput.Success<I>, Cause.NoSuchElementException, Scope.Scope> { ): Effect.Effect<useInput.Result<I>, NoSuchElementException, Scope.Scope>
} = Effect.fnUntraced(function* <A, I>(
field: FormField<A, I>,
options?: useInput.Options,
) {
const internalValueRef = yield* Component.useOnChange(() => Effect.tap( const internalValueRef = yield* Component.useOnChange(() => Effect.tap(
Effect.andThen(field.encodedValue, SubscriptionRef.make), Effect.andThen(field.encodedValueRef, SubscriptionRef.make),
internalValueRef => Effect.forkScoped(Effect.all([ internalValueRef => Effect.forkScoped(Effect.all([
Stream.runForEach( Stream.runForEach(
Stream.drop(field.encodedValue, 1), Stream.drop(field.encodedValueRef, 1),
upstreamEncodedValue => Effect.whenEffect( upstreamEncodedValue => Effect.whenEffect(
Ref.set(internalValueRef, upstreamEncodedValue), Ref.set(internalValueRef, upstreamEncodedValue),
Effect.andThen(internalValueRef, internalValue => !Equal.equals(upstreamEncodedValue, internalValue)), Effect.andThen(internalValueRef, internalValue => !Equal.equals(upstreamEncodedValue, internalValue)),
@@ -322,7 +288,7 @@ export const useInput = Effect.fnUntraced(function* <A, I>(
Stream.changesWith(Equal.equivalence()), Stream.changesWith(Equal.equivalence()),
options?.debounce ? Stream.debounce(options.debounce) : identity, options?.debounce ? Stream.debounce(options.debounce) : identity,
), ),
internalValue => Ref.set(field.encodedValue, internalValue), internalValue => Ref.set(field.encodedValueRef, internalValue),
), ),
], { concurrency: "unbounded" })), ], { concurrency: "unbounded" })),
), [field, options?.debounce]) ), [field, options?.debounce])
@@ -336,19 +302,24 @@ export namespace useOptionalInput {
readonly defaultValue: T readonly defaultValue: T
} }
export interface Success<T> extends useInput.Success<T> { export interface Result<T> extends useInput.Result<T> {
readonly enabled: boolean readonly enabled: boolean
readonly setEnabled: React.Dispatch<React.SetStateAction<boolean>> readonly setEnabled: React.Dispatch<React.SetStateAction<boolean>>
} }
} }
export const useOptionalInput = Effect.fnUntraced(function* <A, I>( export const useOptionalInput: {
<A, I>(
field: FormField<A, Option.Option<I>>, field: FormField<A, Option.Option<I>>,
options: useOptionalInput.Options<I>, options: useOptionalInput.Options<I>,
): Effect.fn.Return<useOptionalInput.Success<I>, Cause.NoSuchElementException, Scope.Scope> { ): Effect.Effect<useOptionalInput.Result<I>, NoSuchElementException, Scope.Scope>
} = Effect.fnUntraced(function* <A, I>(
field: FormField<A, Option.Option<I>>,
options: useOptionalInput.Options<I>,
) {
const [enabledRef, internalValueRef] = yield* Component.useOnChange(() => Effect.tap( const [enabledRef, internalValueRef] = yield* Component.useOnChange(() => Effect.tap(
Effect.andThen( Effect.andThen(
field.encodedValue, field.encodedValueRef,
Option.match({ Option.match({
onSome: v => Effect.all([SubscriptionRef.make(true), SubscriptionRef.make(v)]), onSome: v => Effect.all([SubscriptionRef.make(true), SubscriptionRef.make(v)]),
onNone: () => Effect.all([SubscriptionRef.make(false), SubscriptionRef.make(options.defaultValue)]), onNone: () => Effect.all([SubscriptionRef.make(false), SubscriptionRef.make(options.defaultValue)]),
@@ -357,7 +328,7 @@ export const useOptionalInput = Effect.fnUntraced(function* <A, I>(
([enabledRef, internalValueRef]) => Effect.forkScoped(Effect.all([ ([enabledRef, internalValueRef]) => Effect.forkScoped(Effect.all([
Stream.runForEach( Stream.runForEach(
Stream.drop(field.encodedValue, 1), Stream.drop(field.encodedValueRef, 1),
upstreamEncodedValue => Effect.whenEffect( upstreamEncodedValue => Effect.whenEffect(
Option.match(upstreamEncodedValue, { Option.match(upstreamEncodedValue, {
@@ -385,7 +356,7 @@ export const useOptionalInput = Effect.fnUntraced(function* <A, I>(
Stream.changesWith(Equal.equivalence()), Stream.changesWith(Equal.equivalence()),
options?.debounce ? Stream.debounce(options.debounce) : identity, options?.debounce ? Stream.debounce(options.debounce) : identity,
), ),
([enabled, internalValue]) => Ref.set(field.encodedValue, enabled ? Option.some(internalValue) : Option.none()), ([enabled, internalValue]) => Ref.set(field.encodedValueRef, enabled ? Option.some(internalValue) : Option.none()),
), ),
], { concurrency: "unbounded" })), ], { concurrency: "unbounded" })),
), [field, options.debounce]) ), [field, options.debounce])

View File

@@ -0,0 +1,7 @@
import type { ExecutionStrategy } from "effect"
export interface ScopeOptions {
readonly finalizerExecutionMode?: "sync" | "fork"
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
}

View File

@@ -0,0 +1,16 @@
export * from "./input/index.js"
export * from "./ScopeOptions.js"
export * from "./useCallbackPromise.js"
export * from "./useCallbackSync.js"
export * from "./useContext.js"
export * from "./useEffect.js"
export * from "./useFork.js"
export * from "./useLayoutEffect.js"
export * from "./useMemo.js"
export * from "./useOnce.js"
export * from "./useRefFromState.js"
export * from "./useRefState.js"
export * from "./useScope.js"
export * from "./useStreamFromReactiveValues.js"
export * from "./useSubscribables.js"
export * from "./useSubscribeStream.js"

View File

@@ -0,0 +1,2 @@
export * from "./useInput.js"
export * from "./useOptionalInput.js"

View File

@@ -0,0 +1,67 @@
import { type Duration, Effect, Equal, Equivalence, flow, identity, Option, type ParseResult, Ref, Schema, Stream, SubscriptionRef } from "effect"
import * as React from "react"
import { useFork } from "../useFork.js"
import { useOnce } from "../useOnce.js"
import { useRefState } from "../useRefState.js"
export namespace useInput {
export interface Options<A, R> {
readonly schema: Schema.Schema<A, string, R>
readonly equivalence?: Equivalence.Equivalence<A>
readonly ref: SubscriptionRef.SubscriptionRef<A>
readonly debounce?: Duration.DurationInput
}
export interface Result {
readonly value: string
readonly setValue: React.Dispatch<React.SetStateAction<string>>
readonly error: Option.Option<ParseResult.ParseError>
}
}
export const useInput: {
<A, R>(options: useInput.Options<A, R>): Effect.Effect<useInput.Result, ParseResult.ParseError, R>
} = Effect.fnUntraced(function* <A, R>(options: useInput.Options<A, R>) {
const internalRef = yield* useOnce(() => options.ref.pipe(
Effect.andThen(Schema.encode(options.schema)),
Effect.andThen(SubscriptionRef.make),
))
const [error, setError] = React.useState(Option.none<ParseResult.ParseError>())
yield* useFork(() => Effect.all([
// Sync the upstream state with the internal state
// Only mutate the internal state if the upstream value is actually different. This avoids infinite re-render loops.
Stream.runForEach(Stream.changesWith(options.ref.changes, Equivalence.strict()), upstreamValue =>
Effect.whenEffect(
Effect.andThen(
Schema.encode(options.schema)(upstreamValue),
encodedUpstreamValue => Ref.set(internalRef, encodedUpstreamValue),
),
internalRef.pipe(
Effect.andThen(Schema.decode(options.schema)),
Effect.andThen(decodedInternalValue => !(options.equivalence ?? Equal.equals)(upstreamValue, decodedInternalValue)),
Effect.catchTag("ParseError", () => Effect.succeed(false)),
),
)
),
// Sync all changes to the internal state with upstream
Stream.runForEach(
internalRef.changes.pipe(
Stream.changesWith(Equivalence.strict()),
options.debounce ? Stream.debounce(options.debounce) : identity,
Stream.drop(1),
),
flow(
Schema.decode(options.schema),
Effect.andThen(v => Ref.set(options.ref, v)),
Effect.andThen(() => setError(Option.none())),
Effect.catchTag("ParseError", e => Effect.sync(() => setError(Option.some(e)))),
),
),
], { concurrency: "unbounded" }), [options.schema, options.equivalence, options.ref, options.debounce, internalRef])
const [value, setValue] = yield* useRefState(internalRef)
return { value, setValue, error }
})

View File

@@ -0,0 +1,107 @@
import { type Duration, Effect, Equal, Equivalence, flow, identity, Option, type ParseResult, Ref, Schema, Stream, SubscriptionRef } from "effect"
import * as React from "react"
import * as SetStateAction from "../../SetStateAction.js"
import { useCallbackSync } from "../useCallbackSync.js"
import { useFork } from "../useFork.js"
import { useOnce } from "../useOnce.js"
import { useRefState } from "../useRefState.js"
import { useSubscribables } from "../useSubscribables.js"
export namespace useOptionalInput {
export interface Options<A, R> {
readonly schema: Schema.Schema<A, string, R>
readonly defaultValue?: A
readonly equivalence?: Equivalence.Equivalence<A>
readonly ref: SubscriptionRef.SubscriptionRef<Option.Option<A>>
readonly debounce?: Duration.DurationInput
}
export interface Result {
readonly value: string
readonly setValue: React.Dispatch<React.SetStateAction<string>>
readonly enabled: boolean
readonly setEnabled: React.Dispatch<React.SetStateAction<boolean>>
readonly error: Option.Option<ParseResult.ParseError>
}
}
export const useOptionalInput: {
<A, R>(options: useOptionalInput.Options<A, R>): Effect.Effect<useOptionalInput.Result, ParseResult.ParseError, R>
} = Effect.fnUntraced(function* <A, R>(options: useOptionalInput.Options<A, R>) {
const [internalRef, enabledRef] = yield* useOnce(() => Effect.andThen(options.ref, upstreamValue =>
Effect.all([
Effect.andThen(
Option.match(upstreamValue, {
onSome: Schema.encode(options.schema),
onNone: () => options.defaultValue
? Schema.encode(options.schema)(options.defaultValue)
: Effect.succeed(""),
}),
SubscriptionRef.make,
),
SubscriptionRef.make(Option.isSome(upstreamValue)),
])
))
const [error, setError] = React.useState(Option.none<ParseResult.ParseError>())
yield* useFork(() => Effect.all([
// Sync the upstream state with the internal state
// Only mutate the internal state if the upstream value is actually different. This avoids infinite re-render loops.
Stream.runForEach(Stream.changesWith(options.ref.changes, Equivalence.strict()), Option.match({
onSome: upstreamValue => Effect.andThen(
Ref.set(enabledRef, true),
Effect.whenEffect(
Effect.andThen(
Schema.encode(options.schema)(upstreamValue),
encodedUpstreamValue => Ref.set(internalRef, encodedUpstreamValue),
),
internalRef.pipe(
Effect.andThen(Schema.decode(options.schema)),
Effect.andThen(decodedInternalValue => !(options.equivalence ?? Equal.equals)(upstreamValue, decodedInternalValue)),
Effect.catchTag("ParseError", () => Effect.succeed(false)),
),
),
),
onNone: () => Ref.set(enabledRef, false),
})),
// Sync all changes to the internal state with upstream
Stream.runForEach(
internalRef.changes.pipe(
Stream.changesWith(Equivalence.strict()),
options.debounce ? Stream.debounce(options.debounce) : identity,
Stream.drop(1),
),
flow(
Schema.decode(options.schema),
Effect.andThen(v => Ref.set(options.ref, Option.some(v))),
Effect.andThen(() => setError(Option.none())),
Effect.catchTag("ParseError", e => Effect.sync(() => setError(Option.some(e)))),
),
),
], { concurrency: "unbounded" }), [options.schema, options.equivalence, options.ref, options.debounce, internalRef])
const setEnabled = yield* useCallbackSync(
(setStateAction: React.SetStateAction<boolean>) => Effect.andThen(
Ref.updateAndGet(enabledRef, prevState => SetStateAction.value(setStateAction, prevState)),
enabled => enabled
? internalRef.pipe(
Effect.andThen(Schema.decode(options.schema)),
Effect.andThen(v => Ref.set(options.ref, Option.some(v))),
Effect.andThen(() => setError(Option.none())),
Effect.catchTag("ParseError", e => Effect.sync(() => setError(Option.some(e)))),
)
: Ref.set(options.ref, Option.none()),
),
[options.schema, options.ref, internalRef, enabledRef],
)
const [enabled] = yield* useSubscribables(enabledRef)
const [value, setValue] = yield* useRefState(internalRef)
return { value, setValue, enabled, setEnabled, error }
})

View File

@@ -0,0 +1,18 @@
import { Exit, Runtime, Scope } from "effect"
import type { ScopeOptions } from "./ScopeOptions.js"
export const closeScope = (
scope: Scope.CloseableScope,
runtime: Runtime.Runtime<never>,
options?: ScopeOptions,
) => {
switch (options?.finalizerExecutionMode ?? "sync") {
case "sync":
Runtime.runSync(runtime)(Scope.close(scope, Exit.void))
break
case "fork":
Runtime.runFork(runtime)(Scope.close(scope, Exit.void))
break
}
}

View File

@@ -0,0 +1,20 @@
import { Effect, Runtime } from "effect"
import * as React from "react"
export const useCallbackPromise: {
<Args extends unknown[], A, E, R>(
callback: (...args: Args) => Effect.Effect<A, E, R>,
deps: React.DependencyList,
): Effect.Effect<(...args: Args) => Promise<A>, never, R>
} = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>(
callback: (...args: Args) => Effect.Effect<A, E, R>,
deps: React.DependencyList,
) {
// biome-ignore lint/style/noNonNullAssertion: context initialization
const runtimeRef = React.useRef<Runtime.Runtime<R>>(null!)
runtimeRef.current = yield* Effect.runtime<R>()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
return React.useCallback((...args: Args) => Runtime.runPromise(runtimeRef.current)(callback(...args)), deps)
})

View File

@@ -0,0 +1,20 @@
import { Effect, Runtime } from "effect"
import * as React from "react"
export const useCallbackSync: {
<Args extends unknown[], A, E, R>(
callback: (...args: Args) => Effect.Effect<A, E, R>,
deps: React.DependencyList,
): Effect.Effect<(...args: Args) => A, never, R>
} = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>(
callback: (...args: Args) => Effect.Effect<A, E, R>,
deps: React.DependencyList,
) {
// biome-ignore lint/style/noNonNullAssertion: context initialization
const runtimeRef = React.useRef<Runtime.Runtime<R>>(null!)
runtimeRef.current = yield* Effect.runtime<R>()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
return React.useCallback((...args: Args) => Runtime.runSync(runtimeRef.current)(callback(...args)), deps)
})

View File

@@ -0,0 +1,25 @@
import { type Context, Effect, Layer, ManagedRuntime, Scope } from "effect"
import type { ScopeOptions } from "./ScopeOptions.js"
import { useMemo } from "./useMemo.js"
import { useScope } from "./useScope.js"
export const useContext: {
<ROut, E, RIn>(
layer: Layer.Layer<ROut, E, RIn>,
options?: ScopeOptions,
): Effect.Effect<Context.Context<ROut>, E, RIn>
} = Effect.fnUntraced(function* <ROut, E, RIn>(
layer: Layer.Layer<ROut, E, RIn>,
options?: ScopeOptions,
) {
const scope = yield* useScope([layer], options)
return yield* useMemo(() => Effect.context<RIn>().pipe(
Effect.map(context => ManagedRuntime.make(Layer.provide(layer, Layer.succeedContext(context)))),
Effect.tap(runtime => Effect.addFinalizer(() => runtime.disposeEffect)),
Effect.andThen(runtime => runtime.runtimeEffect),
Effect.andThen(runtime => runtime.context),
Effect.provideService(Scope.Scope, scope),
), [scope])
})

View File

@@ -0,0 +1,29 @@
import { Effect, ExecutionStrategy, Runtime, Scope } from "effect"
import * as React from "react"
import { closeScope } from "./internal.js"
import type { ScopeOptions } from "./ScopeOptions.js"
export const useEffect: {
<E, R>(
effect: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: ScopeOptions,
): Effect.Effect<void, never, Exclude<R, Scope.Scope>>
} = Effect.fnUntraced(function* <E, R>(
effect: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: ScopeOptions,
) {
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
React.useEffect(() => Effect.Do.pipe(
Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)),
Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(effect(), Scope.Scope, scope))),
Effect.map(({ scope }) =>
() => closeScope(scope, runtime, options)
),
Runtime.runSync(runtime),
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
), deps)
})

View File

@@ -0,0 +1,32 @@
import { Effect, ExecutionStrategy, Runtime, Scope } from "effect"
import * as React from "react"
import { closeScope } from "./internal.js"
import type { ScopeOptions } from "./ScopeOptions.js"
export const useFork: {
<E, R>(
effect: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: Runtime.RunForkOptions & ScopeOptions,
): Effect.Effect<void, never, Exclude<R, Scope.Scope>>
} = Effect.fnUntraced(function* <E, R>(
effect: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: Runtime.RunForkOptions & ScopeOptions,
) {
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
React.useEffect(() => {
const scope = Runtime.runSync(runtime)(options?.scope
? Scope.fork(options.scope, options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)
: Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)
)
Runtime.runFork(runtime)(Effect.provideService(effect(), Scope.Scope, scope), { ...options, scope })
return () => closeScope(scope, runtime, {
...options,
finalizerExecutionMode: options?.finalizerExecutionMode ?? "fork",
})
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
}, deps)
})

View File

@@ -0,0 +1,29 @@
import { Effect, ExecutionStrategy, Runtime, Scope } from "effect"
import * as React from "react"
import { closeScope } from "./internal.js"
import type { ScopeOptions } from "./ScopeOptions.js"
export const useLayoutEffect: {
<E, R>(
effect: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: ScopeOptions,
): Effect.Effect<void, never, Exclude<R, Scope.Scope>>
} = Effect.fnUntraced(function* <E, R>(
effect: () => Effect.Effect<void, E, R>,
deps?: React.DependencyList,
options?: ScopeOptions,
) {
const runtime = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
React.useLayoutEffect(() => Effect.Do.pipe(
Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)),
Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(effect(), Scope.Scope, scope))),
Effect.map(({ scope }) =>
() => closeScope(scope, runtime, options)
),
Runtime.runSync(runtime),
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
), deps)
})

View File

@@ -0,0 +1,17 @@
import { Effect, Runtime } from "effect"
import * as React from "react"
export const useMemo: {
<A, E, R>(
factory: () => Effect.Effect<A, E, R>,
deps: React.DependencyList,
): Effect.Effect<A, E, R>
} = Effect.fnUntraced(function* <A, E, R>(
factory: () => Effect.Effect<A, E, R>,
deps: React.DependencyList,
) {
const runtime = yield* Effect.runtime()
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
return yield* React.useMemo(() => Runtime.runSync(runtime)(Effect.cached(factory())), deps)
})

View File

@@ -0,0 +1,11 @@
import { Effect } from "effect"
import { useMemo } from "./useMemo.js"
export const useOnce: {
<A, E, R>(factory: () => Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
} = Effect.fnUntraced(function* <A, E, R>(
factory: () => Effect.Effect<A, E, R>
) {
return yield* useMemo(factory, [])
})

View File

@@ -0,0 +1,20 @@
import { Effect, Equivalence, Ref, Stream, SubscriptionRef } from "effect"
import type * as React from "react"
import { useEffect } from "./useEffect.js"
import { useFork } from "./useFork.js"
import { useOnce } from "./useOnce.js"
export const useRefFromState: {
<A>(state: readonly [A, React.Dispatch<React.SetStateAction<A>>]): Effect.Effect<SubscriptionRef.SubscriptionRef<A>>
} = Effect.fnUntraced(function*([value, setValue]) {
const ref = yield* useOnce(() => SubscriptionRef.make(value))
yield* useEffect(() => Ref.set(ref, value), [value])
yield* useFork(() => Stream.runForEach(
Stream.changesWith(ref.changes, Equivalence.strict()),
v => Effect.sync(() => setValue(v)),
), [setValue])
return ref
})

View File

@@ -0,0 +1,29 @@
import { Effect, Equivalence, Ref, Stream, type SubscriptionRef } from "effect"
import * as React from "react"
import * as SetStateAction from "../SetStateAction.js"
import { useCallbackSync } from "./useCallbackSync.js"
import { useFork } from "./useFork.js"
import { useOnce } from "./useOnce.js"
export const useRefState: {
<A>(
ref: SubscriptionRef.SubscriptionRef<A>
): Effect.Effect<readonly [A, React.Dispatch<React.SetStateAction<A>>]>
} = Effect.fnUntraced(function* <A>(ref: SubscriptionRef.SubscriptionRef<A>) {
const [reactStateValue, setReactStateValue] = React.useState(yield* useOnce(() => ref))
yield* useFork(() => Stream.runForEach(
Stream.changesWith(ref.changes, Equivalence.strict()),
v => Effect.sync(() => setReactStateValue(v)),
), [ref])
const setValue = yield* useCallbackSync((setStateAction: React.SetStateAction<A>) =>
Effect.andThen(
Ref.updateAndGet(ref, prevState => SetStateAction.value(setStateAction, prevState)),
v => setReactStateValue(v),
),
[ref])
return [reactStateValue, setValue]
})

View File

@@ -0,0 +1,38 @@
import { Effect, ExecutionStrategy, Ref, Runtime, Scope } from "effect"
import * as React from "react"
import { closeScope } from "./internal.js"
import type { ScopeOptions } from "./ScopeOptions.js"
export const useScope: {
(
deps: React.DependencyList,
options?: ScopeOptions,
): Effect.Effect<Scope.Scope>
} = Effect.fnUntraced(function*(deps, options) {
const runtime = yield* Effect.runtime()
// biome-ignore lint/correctness/useExhaustiveDependencies: no reactivity needed
const [isInitialRun, initialScope] = React.useMemo(() => Runtime.runSync(runtime)(Effect.all([
Ref.make(true),
Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential),
])), [])
const [scope, setScope] = React.useState(initialScope)
React.useEffect(() => Runtime.runSync(runtime)(
Effect.if(isInitialRun, {
onTrue: () => Effect.as(
Ref.set(isInitialRun, false),
() => closeScope(scope, runtime, options),
),
onFalse: () => Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential).pipe(
Effect.tap(scope => Effect.sync(() => setScope(scope))),
Effect.map(scope => () => closeScope(scope, runtime, options)),
),
})
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
), deps)
return scope
})

View File

@@ -0,0 +1,30 @@
import { Effect, PubSub, Ref, type Scope, Stream } from "effect"
import type * as React from "react"
import { useEffect } from "./useEffect.js"
import { useOnce } from "./useOnce.js"
export const useStreamFromReactiveValues: {
<const A extends React.DependencyList>(
values: A
): Effect.Effect<Stream.Stream<A>, never, Scope.Scope>
} = Effect.fnUntraced(function* <const A extends React.DependencyList>(values: A) {
const { latest, pubsub, stream } = yield* useOnce(() => Effect.Do.pipe(
Effect.bind("latest", () => Ref.make(values)),
Effect.bind("pubsub", () => Effect.acquireRelease(PubSub.unbounded<A>(), PubSub.shutdown)),
Effect.let("stream", ({ latest, pubsub }) => latest.pipe(
Effect.flatMap(a => Effect.map(
Stream.fromPubSub(pubsub, { scoped: true }),
s => Stream.concat(Stream.make(a), s),
)),
Stream.unwrapScoped,
)),
))
yield* useEffect(() => Ref.set(latest, values).pipe(
Effect.andThen(PubSub.publish(pubsub, values)),
Effect.unlessEffect(PubSub.isShutdown(pubsub)),
), values)
return stream
})

View File

@@ -0,0 +1,31 @@
import { Effect, Equivalence, pipe, Stream, type Subscribable } from "effect"
import * as React from "react"
import { useFork } from "./useFork.js"
import { useOnce } from "./useOnce.js"
export const useSubscribables: {
<const T extends readonly Subscribable.Subscribable<any, any, any>[]>(
...elements: T
): Effect.Effect<
{ [K in keyof T]: Effect.Effect.Success<T[K]["get"]> | Stream.Stream.Success<T[K]["changes"]> },
Effect.Effect.Error<T[number]["get"]> | Stream.Stream.Error<T[number]["changes"]>,
Effect.Effect.Context<T[number]["get"]> | Stream.Stream.Context<T[number]["changes"]>
>
} = Effect.fnUntraced(function* <const T extends readonly Subscribable.Subscribable<any, any, any>[]>(
...elements: T
) {
const [reactStateValue, setReactStateValue] = React.useState(yield* useOnce(() =>
Effect.all(elements.map(v => v.get))
))
yield* useFork(() => pipe(
elements.map(ref => Stream.changesWith(ref.changes, Equivalence.strict())),
streams => Stream.zipLatestAll(...streams),
Stream.runForEach(v =>
Effect.sync(() => setReactStateValue(v))
),
), elements)
return reactStateValue as any
})

View File

@@ -1,9 +1,9 @@
import { Effect, Equivalence, Option, Stream } from "effect" import { Effect, Equivalence, Option, Stream } from "effect"
import * as React from "react" import * as React from "react"
import * as Component from "./Component.js" import { useFork } from "./useFork.js"
export const useStream: { export const useSubscribeStream: {
<A, E, R>( <A, E, R>(
stream: Stream.Stream<A, E, R> stream: Stream.Stream<A, E, R>
): Effect.Effect<Option.Option<A>, never, R> ): Effect.Effect<Option.Option<A>, never, R>
@@ -15,19 +15,18 @@ export const useStream: {
stream: Stream.Stream<A, E, R>, stream: Stream.Stream<A, E, R>,
initialValue?: A, initialValue?: A,
) { ) {
const [reactStateValue, setReactStateValue] = React.useState(() => initialValue const [reactStateValue, setReactStateValue] = React.useState(
// biome-ignore lint/correctness/useExhaustiveDependencies: no reactivity needed
React.useMemo(() => initialValue
? Option.some(initialValue) ? Option.some(initialValue)
: Option.none() : Option.none(),
[])
) )
yield* Component.useReactEffect(() => Effect.forkScoped( yield* useFork(() => Stream.runForEach(
Stream.runForEach(
Stream.changesWith(stream, Equivalence.strict()), Stream.changesWith(stream, Equivalence.strict()),
v => Effect.sync(() => setReactStateValue(Option.some(v))), v => Effect.sync(() => setReactStateValue(Option.some(v))),
)
), [stream]) ), [stream])
return reactStateValue as Option.Some<A> return reactStateValue as Option.Some<A>
}) })
export * from "effect/Stream"

View File

@@ -3,7 +3,7 @@ import { type Equivalence, Function, Predicate } from "effect"
import type * as Component from "./Component.js" import type * as Component from "./Component.js"
export const TypeId: unique symbol = Symbol.for("@effect-fc/Memoized/Memoized") export const TypeId: unique symbol = Symbol.for("effect-fc/Memoized/Memoized")
export type TypeId = typeof TypeId export type TypeId = typeof TypeId
export interface Memoized<P> extends Memoized.Options<P> { export interface Memoized<P> extends Memoized.Options<P> {

View File

@@ -1,128 +0,0 @@
import { type Context, Effect, Equal, type Fiber, Option, Pipeable, Predicate, type Scope, Stream, type Subscribable, SubscriptionRef } from "effect"
import * as Result from "./Result.js"
export const MutationTypeId: unique symbol = Symbol.for("@effect-fc/Mutation/Mutation")
export type MutationTypeId = typeof MutationTypeId
export interface Mutation<in out K extends Mutation.AnyKey, in out A, in out E = never, in out R = never, in out P = never>
extends Pipeable.Pipeable {
readonly [MutationTypeId]: MutationTypeId
readonly context: Context.Context<Scope.Scope | R>
readonly f: (key: K) => Effect.Effect<A, E, R>
readonly initialProgress: P
readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
readonly latestFinalResult: Subscribable.Subscribable<Option.Option<Result.Final<A, E, P>>>
mutate(key: K): Effect.Effect<Result.Final<A, E, P>>
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>>
}
export declare namespace Mutation {
export type AnyKey = readonly any[]
}
export class MutationImpl<in out K extends Mutation.AnyKey, in out A, in out E = never, in out R = never, in out P = never>
extends Pipeable.Class() implements Mutation<K, A, E, R, P> {
readonly [MutationTypeId]: MutationTypeId = MutationTypeId
constructor(
readonly context: Context.Context<Scope.Scope | R>,
readonly f: (key: K) => Effect.Effect<A, E, R>,
readonly initialProgress: P,
readonly latestKey: SubscriptionRef.SubscriptionRef<Option.Option<K>>,
readonly fiber: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, E>>>,
readonly result: SubscriptionRef.SubscriptionRef<Result.Result<A, E, P>>,
readonly latestFinalResult: SubscriptionRef.SubscriptionRef<Option.Option<Result.Final<A, E, P>>>,
) {
super()
}
mutate(key: K): Effect.Effect<Result.Final<A, E, P>> {
return SubscriptionRef.set(this.latestKey, Option.some(key)).pipe(
Effect.andThen(this.start(key)),
Effect.andThen(sub => this.watch(sub)),
Effect.provide(this.context),
)
}
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>> {
return SubscriptionRef.set(this.latestKey, Option.some(key)).pipe(
Effect.andThen(this.start(key)),
Effect.tap(sub => Effect.forkScoped(this.watch(sub))),
Effect.provide(this.context),
)
}
start(key: K): Effect.Effect<
Subscribable.Subscribable<Result.Result<A, E, P>>,
never,
Scope.Scope | R
> {
return this.latestFinalResult.pipe(
Effect.andThen(initial => Result.unsafeForkEffect(
Effect.onExit(this.f(key), () => Effect.andThen(
Effect.all([Effect.fiberId, this.fiber]),
([currentFiberId, fiber]) => Option.match(fiber, {
onSome: v => Equal.equals(currentFiberId, v.id())
? SubscriptionRef.set(this.fiber, Option.none())
: Effect.void,
onNone: () => Effect.void,
}),
)),
{
initial: Option.isSome(initial) ? Result.willFetch(initial.value) : Result.initial(),
initialProgress: this.initialProgress,
} as Result.unsafeForkEffect.Options<A, E, P>,
)),
Effect.tap(([, fiber]) => SubscriptionRef.set(this.fiber, Option.some(fiber))),
Effect.map(([sub]) => sub),
)
}
watch(
sub: Subscribable.Subscribable<Result.Result<A, E, P>>
): Effect.Effect<Result.Final<A, E, P>> {
return sub.get.pipe(
Effect.andThen(initial => Stream.runFoldEffect(
sub.changes,
initial,
(_, result) => Effect.as(SubscriptionRef.set(this.result, result), result),
) as Effect.Effect<Result.Final<A, E, P>>),
Effect.tap(result => SubscriptionRef.set(this.latestFinalResult, Option.some(result))),
)
}
}
export const isMutation = (u: unknown): u is Mutation<readonly unknown[], unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, MutationTypeId)
export declare namespace make {
export interface Options<K extends Mutation.AnyKey = never, A = void, E = never, R = never, P = never> {
readonly f: (key: K) => Effect.Effect<A, E, Result.forkEffect.InputContext<R, NoInfer<P>>>
readonly initialProgress?: P
}
}
export const make = Effect.fnUntraced(function* <const K extends Mutation.AnyKey = never, A = void, E = never, R = never, P = never>(
options: make.Options<K, A, E, R, P>
): Effect.fn.Return<
Mutation<K, A, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
never,
Scope.Scope | Result.forkEffect.OutputContext<A, E, R, P>
> {
return new MutationImpl(
yield* Effect.context<Scope.Scope | Result.forkEffect.OutputContext<A, E, R, P>>(),
options.f as any,
options.initialProgress as P,
yield* SubscriptionRef.make(Option.none<K>()),
yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>()),
yield* SubscriptionRef.make(Result.initial<A, E, P>()),
yield* SubscriptionRef.make(Option.none<Result.Final<A, E, P>>()),
)
})

View File

@@ -1,14 +0,0 @@
import { Effect, PubSub, type Scope } from "effect"
import type * as React from "react"
import * as Component from "./Component.js"
export const usePubSubFromReactiveValues = Effect.fnUntraced(function* <const A extends React.DependencyList>(
values: A
): Effect.fn.Return<PubSub.PubSub<A>, never, Scope.Scope> {
const pubsub = yield* Component.useOnMount(() => Effect.acquireRelease(PubSub.unbounded<A>(), PubSub.shutdown))
yield* Component.useReactEffect(() => Effect.unlessEffect(PubSub.publish(pubsub, values), PubSub.isShutdown(pubsub)), values)
return pubsub
})
export * from "effect/PubSub"

View File

@@ -1,316 +0,0 @@
import { type Cause, type Context, type Duration, Effect, Equal, Fiber, identity, Option, Pipeable, Predicate, type Scope, Stream, Subscribable, SubscriptionRef } from "effect"
import * as QueryClient from "./QueryClient.js"
import * as Result from "./Result.js"
export const QueryTypeId: unique symbol = Symbol.for("@effect-fc/Query/Query")
export type QueryTypeId = typeof QueryTypeId
export interface Query<in out K extends Query.AnyKey, in out A, in out E = never, in out R = never, in out P = never>
extends Pipeable.Pipeable {
readonly [QueryTypeId]: QueryTypeId
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | R>
readonly key: Stream.Stream<K>
readonly f: (key: K) => Effect.Effect<A, E, R>
readonly initialProgress: P
readonly staleTime: Duration.DurationInput
readonly refreshOnWindowFocus: boolean
readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
readonly latestFinalResult: Subscribable.Subscribable<Option.Option<Result.Final<A, E, P>>>
readonly run: Effect.Effect<void>
fetch(key: K): Effect.Effect<Result.Final<A, E, P>>
fetchSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>>
readonly refresh: Effect.Effect<Result.Final<A, E, P>, Cause.NoSuchElementException>
readonly refreshSubscribable: Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>, Cause.NoSuchElementException>
readonly invalidateCache: Effect.Effect<void>
invalidateCacheEntry(key: K): Effect.Effect<void>
}
export declare namespace Query {
export type AnyKey = readonly any[]
}
export class QueryImpl<in out K extends Query.AnyKey, in out A, in out E = never, in out R = never, in out P = never>
extends Pipeable.Class() implements Query<K, A, E, R, P> {
readonly [QueryTypeId]: QueryTypeId = QueryTypeId
constructor(
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | R>,
readonly key: Stream.Stream<K>,
readonly f: (key: K) => Effect.Effect<A, E, R>,
readonly initialProgress: P,
readonly staleTime: Duration.DurationInput,
readonly refreshOnWindowFocus: boolean,
readonly latestKey: SubscriptionRef.SubscriptionRef<Option.Option<K>>,
readonly fiber: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, E>>>,
readonly result: SubscriptionRef.SubscriptionRef<Result.Result<A, E, P>>,
readonly latestFinalResult: SubscriptionRef.SubscriptionRef<Option.Option<Result.Final<A, E, P>>>,
readonly runSemaphore: Effect.Semaphore,
) {
super()
}
get run(): Effect.Effect<void> {
return Effect.all([
Stream.runForEach(this.key, key => this.fetchSubscribable(key)),
Effect.promise(() => import("@effect/platform-browser")).pipe(
Effect.andThen(({ BrowserStream }) => this.refreshOnWindowFocus
? Stream.runForEach(
BrowserStream.fromEventListenerWindow("focus"),
() => this.refreshSubscribable,
)
: Effect.void
),
Effect.catchAllDefect(() => Effect.void),
),
], { concurrency: "unbounded" }).pipe(
Effect.ignore,
this.runSemaphore.withPermits(1),
)
}
get interrupt(): Effect.Effect<void> {
return Effect.andThen(this.fiber, Option.match({
onSome: Fiber.interrupt,
onNone: () => Effect.void,
}))
}
fetch(key: K): Effect.Effect<Result.Final<A, E, P>> {
return this.interrupt.pipe(
Effect.andThen(SubscriptionRef.set(this.latestKey, Option.some(key))),
Effect.andThen(this.latestFinalResult),
Effect.andThen(previous => this.startCached(key, Option.isSome(previous)
? Result.willFetch(previous.value) as Result.Final<A, E, P>
: Result.initial()
)),
Effect.andThen(sub => this.watch(key, sub)),
Effect.provide(this.context),
)
}
fetchSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>> {
return this.interrupt.pipe(
Effect.andThen(SubscriptionRef.set(this.latestKey, Option.some(key))),
Effect.andThen(this.latestFinalResult),
Effect.andThen(previous => this.startCached(key, Option.isSome(previous)
? Result.willFetch(previous.value) as Result.Final<A, E, P>
: Result.initial()
)),
Effect.tap(sub => Effect.forkScoped(this.watch(key, sub))),
Effect.provide(this.context),
)
}
get refresh(): Effect.Effect<Result.Final<A, E, P>, Cause.NoSuchElementException> {
return this.interrupt.pipe(
Effect.andThen(Effect.Do),
Effect.bind("latestKey", () => Effect.andThen(this.latestKey, identity)),
Effect.bind("latestFinalResult", () => this.latestFinalResult),
Effect.bind("subscribable", ({ latestKey, latestFinalResult }) =>
this.startCached(latestKey, Option.isSome(latestFinalResult)
? Result.willRefresh(latestFinalResult.value) as Result.Final<A, E, P>
: Result.initial()
)
),
Effect.andThen(({ latestKey, subscribable }) => this.watch(latestKey, subscribable)),
Effect.provide(this.context),
)
}
get refreshSubscribable(): Effect.Effect<
Subscribable.Subscribable<Result.Result<A, E, P>>,
Cause.NoSuchElementException
> {
return this.interrupt.pipe(
Effect.andThen(Effect.Do),
Effect.bind("latestKey", () => Effect.andThen(this.latestKey, identity)),
Effect.bind("latestFinalResult", () => this.latestFinalResult),
Effect.bind("subscribable", ({ latestKey, latestFinalResult }) =>
this.startCached(latestKey, Option.isSome(latestFinalResult)
? Result.willRefresh(latestFinalResult.value) as Result.Final<A, E, P>
: Result.initial()
)
),
Effect.tap(({ latestKey, subscribable }) => Effect.forkScoped(this.watch(latestKey, subscribable))),
Effect.map(({ subscribable }) => subscribable),
Effect.provide(this.context),
)
}
startCached(
key: K,
initial: Result.Initial | Result.Final<A, E, P>,
): Effect.Effect<
Subscribable.Subscribable<Result.Result<A, E, P>>,
never,
Scope.Scope | QueryClient.QueryClient | R
> {
return Effect.andThen(this.getCacheEntry(key), Option.match({
onSome: entry => Effect.andThen(
QueryClient.isQueryClientCacheEntryStale(entry),
isStale => isStale
? this.start(key, Result.willRefresh(entry.result) as Result.Final<A, E, P>)
: Effect.succeed(Subscribable.make({
get: Effect.succeed(entry.result as Result.Result<A, E, P>),
get changes() { return Stream.make(entry.result as Result.Result<A, E, P>) },
})),
),
onNone: () => this.start(key, initial),
}))
}
start(
key: K,
initial: Result.Initial | Result.Final<A, E, P>,
): Effect.Effect<
Subscribable.Subscribable<Result.Result<A, E, P>>,
never,
Scope.Scope | R
> {
return Result.unsafeForkEffect(
Effect.onExit(this.f(key), () => Effect.andThen(
Effect.all([Effect.fiberId, this.fiber]),
([currentFiberId, fiber]) => Option.match(fiber, {
onSome: v => Equal.equals(currentFiberId, v.id())
? SubscriptionRef.set(this.fiber, Option.none())
: Effect.void,
onNone: () => Effect.void,
}),
)),
{
initial,
initialProgress: this.initialProgress,
} as Result.unsafeForkEffect.Options<A, E, P>,
).pipe(
Effect.tap(([, fiber]) => SubscriptionRef.set(this.fiber, Option.some(fiber))),
Effect.map(([sub]) => sub),
)
}
watch(
key: K,
sub: Subscribable.Subscribable<Result.Result<A, E, P>>
): Effect.Effect<Result.Final<A, E, P>, never, QueryClient.QueryClient> {
return sub.get.pipe(
Effect.andThen(initial => Stream.runFoldEffect(
sub.changes,
initial,
(_, result) => Effect.as(SubscriptionRef.set(this.result, result), result),
) as Effect.Effect<Result.Final<A, E, P>>),
Effect.tap(result => SubscriptionRef.set(this.latestFinalResult, Option.some(result))),
Effect.tap(result => Result.isSuccess(result)
? this.setCacheEntry(key, result)
: Effect.void
),
)
}
makeCacheKey(key: K): QueryClient.QueryClientCacheKey {
return new QueryClient.QueryClientCacheKey(key, this.f as (key: Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>)
}
getCacheEntry(
key: K
): Effect.Effect<Option.Option<QueryClient.QueryClientCacheEntry>, never, QueryClient.QueryClient> {
return Effect.andThen(
Effect.all([
Effect.succeed(this.makeCacheKey(key)),
QueryClient.QueryClient,
]),
([key, client]) => client.getCacheEntry(key),
)
}
setCacheEntry(
key: K,
result: Result.Success<A>,
): Effect.Effect<QueryClient.QueryClientCacheEntry, never, QueryClient.QueryClient> {
return Effect.andThen(
Effect.all([
Effect.succeed(this.makeCacheKey(key)),
QueryClient.QueryClient,
]),
([key, client]) => client.setCacheEntry(key, result, this.staleTime),
)
}
get invalidateCache(): Effect.Effect<void> {
return QueryClient.QueryClient.pipe(
Effect.andThen(client => client.invalidateCacheEntries(this.f as (key: Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>)),
Effect.provide(this.context),
)
}
invalidateCacheEntry(key: K): Effect.Effect<void> {
return Effect.all([
Effect.succeed(this.makeCacheKey(key)),
QueryClient.QueryClient,
]).pipe(
Effect.andThen(([key, client]) => client.invalidateCacheEntry(key)),
Effect.provide(this.context),
)
}
}
export const isQuery = (u: unknown): u is Query<readonly unknown[], unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, QueryTypeId)
export declare namespace make {
export interface Options<K extends Query.AnyKey, A, E = never, R = never, P = never> {
readonly key: Stream.Stream<K>
readonly f: (key: NoInfer<K>) => Effect.Effect<A, E, Result.forkEffect.InputContext<R, NoInfer<P>>>
readonly initialProgress?: P
readonly staleTime?: Duration.DurationInput
readonly refreshOnWindowFocus?: boolean
}
}
export const make = Effect.fnUntraced(function* <K extends Query.AnyKey, A, E = never, R = never, P = never>(
options: make.Options<K, A, E, R, P>
): Effect.fn.Return<
Query<K, A, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
never,
Scope.Scope | QueryClient.QueryClient | Result.forkEffect.OutputContext<A, E, R, P>
> {
const client = yield* QueryClient.QueryClient
return new QueryImpl(
yield* Effect.context<Scope.Scope | QueryClient.QueryClient | Result.forkEffect.OutputContext<A, E, R, P>>(),
options.key,
options.f as any,
options.initialProgress as P,
options.staleTime ?? client.defaultStaleTime,
options.refreshOnWindowFocus ?? client.defaultRefreshOnWindowFocus,
yield* SubscriptionRef.make(Option.none<K>()),
yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>()),
yield* SubscriptionRef.make(Result.initial<A, E, P>()),
yield* SubscriptionRef.make(Option.none<Result.Final<A, E, P>>()),
yield* Effect.makeSemaphore(1),
)
})
export const service = <K extends Query.AnyKey, A, E = never, R = never, P = never>(
options: make.Options<K, A, E, R, P>
): Effect.Effect<
Query<K, A, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
never,
Scope.Scope | QueryClient.QueryClient | Result.forkEffect.OutputContext<A, E, R, P>
> => Effect.tap(
make(options),
query => Effect.forkScoped(query.run),
)

View File

@@ -1,173 +0,0 @@
import { DateTime, Duration, Effect, Equal, Equivalence, Hash, HashMap, type Option, Pipeable, Predicate, Schedule, type Scope, type Subscribable, SubscriptionRef } from "effect"
import type * as Query from "./Query.js"
import type * as Result from "./Result.js"
export const QueryClientServiceTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientService")
export type QueryClientServiceTypeId = typeof QueryClientServiceTypeId
export interface QueryClientService extends Pipeable.Pipeable {
readonly [QueryClientServiceTypeId]: QueryClientServiceTypeId
readonly cache: Subscribable.Subscribable<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>
readonly cacheGcTime: Duration.DurationInput
readonly defaultStaleTime: Duration.DurationInput
readonly defaultRefreshOnWindowFocus: boolean
readonly run: Effect.Effect<void>
getCacheEntry(key: QueryClientCacheKey): Effect.Effect<Option.Option<QueryClientCacheEntry>>
setCacheEntry(
key: QueryClientCacheKey,
result: Result.Success<unknown>,
staleTime: Duration.DurationInput,
): Effect.Effect<QueryClientCacheEntry>
invalidateCacheEntries(f: (key: Query.Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>): Effect.Effect<void>
invalidateCacheEntry(key: QueryClientCacheKey): Effect.Effect<void>
}
export class QueryClient extends Effect.Service<QueryClient>()("@effect-fc/QueryClient/QueryClient", {
scoped: Effect.suspend(() => service())
}) {}
export class QueryClientServiceImpl
extends Pipeable.Class()
implements QueryClientService {
readonly [QueryClientServiceTypeId]: QueryClientServiceTypeId = QueryClientServiceTypeId
constructor(
readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>,
readonly cacheGcTime: Duration.DurationInput,
readonly defaultStaleTime: Duration.DurationInput,
readonly defaultRefreshOnWindowFocus: boolean,
readonly runSemaphore: Effect.Semaphore,
) {
super()
}
get run(): Effect.Effect<void> {
return this.runSemaphore.withPermits(1)(Effect.repeat(
Effect.andThen(
DateTime.now,
now => SubscriptionRef.update(this.cache, HashMap.filter(entry =>
Duration.lessThan(
DateTime.distanceDuration(entry.lastAccessedAt, now),
Duration.sum(entry.staleTime, this.cacheGcTime),
)
)),
),
Schedule.spaced("30 second"),
))
}
getCacheEntry(key: QueryClientCacheKey): Effect.Effect<Option.Option<QueryClientCacheEntry>> {
return Effect.all([
Effect.andThen(this.cache, HashMap.get(key)),
DateTime.now,
]).pipe(
Effect.map(([entry, now]) => new QueryClientCacheEntry(entry.result, entry.staleTime, entry.createdAt, now)),
Effect.tap(entry => SubscriptionRef.update(this.cache, HashMap.set(key, entry))),
Effect.option,
)
}
setCacheEntry(
key: QueryClientCacheKey,
result: Result.Success<unknown>,
staleTime: Duration.DurationInput,
): Effect.Effect<QueryClientCacheEntry> {
return DateTime.now.pipe(
Effect.map(now => new QueryClientCacheEntry(result, staleTime, now, now)),
Effect.tap(entry => SubscriptionRef.update(this.cache, HashMap.set(key, entry))),
)
}
invalidateCacheEntries(f: (key: Query.Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>): Effect.Effect<void> {
return SubscriptionRef.update(this.cache, HashMap.filter((_, key) => !Equivalence.strict()(key.f, f)))
}
invalidateCacheEntry(key: QueryClientCacheKey): Effect.Effect<void> {
return SubscriptionRef.update(this.cache, HashMap.remove(key))
}
}
export const isQueryClientService = (u: unknown): u is QueryClientService => Predicate.hasProperty(u, QueryClientServiceTypeId)
export declare namespace make {
export interface Options {
readonly cacheGcTime?: Duration.DurationInput
readonly defaultStaleTime?: Duration.DurationInput
readonly defaultRefreshOnWindowFocus?: boolean
}
}
export const make = Effect.fnUntraced(function* (options: make.Options = {}): Effect.fn.Return<QueryClientService> {
return new QueryClientServiceImpl(
yield* SubscriptionRef.make(HashMap.empty<QueryClientCacheKey, QueryClientCacheEntry>()),
options.cacheGcTime ?? "5 minutes",
options.defaultStaleTime ?? "0 minutes",
options.defaultRefreshOnWindowFocus ?? true,
yield* Effect.makeSemaphore(1),
)
})
export declare namespace service {
export interface Options extends make.Options {}
}
export const service = (options?: service.Options): Effect.Effect<QueryClientService, never, Scope.Scope> => Effect.tap(
make(options),
client => Effect.forkScoped(client.run),
)
export const QueryClientCacheKeyTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientCacheKey")
export type QueryClientCacheKeyTypeId = typeof QueryClientCacheKeyTypeId
export class QueryClientCacheKey
extends Pipeable.Class()
implements Pipeable.Pipeable, Equal.Equal {
readonly [QueryClientCacheKeyTypeId]: QueryClientCacheKeyTypeId = QueryClientCacheKeyTypeId
constructor(
readonly key: Query.Query.AnyKey,
readonly f: (key: Query.Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>,
) {
super()
}
[Equal.symbol](that: Equal.Equal) {
return isQueryClientCacheKey(that) && Equivalence.array(Equal.equivalence())(this.key, that.key) && Equivalence.strict()(this.f, that.f)
}
[Hash.symbol]() {
return Hash.combine(Hash.hash(this.f))(Hash.array(this.key))
}
}
export const isQueryClientCacheKey = (u: unknown): u is QueryClientCacheKey => Predicate.hasProperty(u, QueryClientCacheKeyTypeId)
export const QueryClientCacheEntryTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientCacheEntry")
export type QueryClientCacheEntryTypeId = typeof QueryClientCacheEntryTypeId
export class QueryClientCacheEntry
extends Pipeable.Class()
implements Pipeable.Pipeable {
readonly [QueryClientCacheEntryTypeId]: QueryClientCacheEntryTypeId = QueryClientCacheEntryTypeId
constructor(
readonly result: Result.Success<unknown>,
readonly staleTime: Duration.DurationInput,
readonly createdAt: DateTime.DateTime,
readonly lastAccessedAt: DateTime.DateTime,
) {
super()
}
}
export const isQueryClientCacheEntry = (u: unknown): u is QueryClientCacheEntry => Predicate.hasProperty(u, QueryClientCacheEntryTypeId)
export const isQueryClientCacheEntryStale = (
self: QueryClientCacheEntry
): Effect.Effect<boolean> => Effect.andThen(
DateTime.now,
now => Duration.greaterThanOrEqualTo(DateTime.distanceDuration(self.createdAt, now), self.staleTime),
)

View File

@@ -1,12 +1,10 @@
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ /** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
import { Effect, Layer, ManagedRuntime, Predicate, Runtime, Scope } from "effect" import { Effect, Layer, ManagedRuntime, Predicate, type Runtime } from "effect"
import * as React from "react" import * as React from "react"
import * as Component from "./Component.js" import * as Component from "./Component.js"
import * as ErrorObserver from "./ErrorObserver.js"
import * as QueryClient from "./QueryClient.js"
export const TypeId: unique symbol = Symbol.for("@effect-fc/ReactRuntime/ReactRuntime") export const TypeId: unique symbol = Symbol.for("effect-fc/ReactRuntime/ReactRuntime")
export type TypeId = typeof TypeId export type TypeId = typeof TypeId
export interface ReactRuntime<R, ER> { export interface ReactRuntime<R, ER> {
@@ -18,26 +16,16 @@ export interface ReactRuntime<R, ER> {
const ReactRuntimeProto = Object.freeze({ [TypeId]: TypeId } as const) const ReactRuntimeProto = Object.freeze({ [TypeId]: TypeId } as const)
export const Prelude: Layer.Layer<
| Component.ScopeMap
| ErrorObserver.ErrorObserver
| QueryClient.QueryClient
> = Layer.mergeAll(
Component.ScopeMap.Default,
ErrorObserver.layer,
QueryClient.QueryClient.Default,
)
export const isReactRuntime = (u: unknown): u is ReactRuntime<unknown, unknown> => Predicate.hasProperty(u, TypeId) export const isReactRuntime = (u: unknown): u is ReactRuntime<unknown, unknown> => Predicate.hasProperty(u, TypeId)
export const make = <R, ER>( export const make = <R, ER>(
layer: Layer.Layer<R, ER>, layer: Layer.Layer<R, ER>,
memoMap?: Layer.MemoMap, memoMap?: Layer.MemoMap,
): ReactRuntime<Layer.Layer.Success<typeof Prelude> | R, ER> => Object.setPrototypeOf( ): ReactRuntime<R | Component.ScopeMap, ER> => Object.setPrototypeOf(
Object.assign(function() {}, { Object.assign(function() {}, {
runtime: ManagedRuntime.make( runtime: ManagedRuntime.make(
Layer.merge(layer, Prelude), Layer.merge(layer, Component.ScopeMap.Default),
memoMap, memoMap,
), ),
// biome-ignore lint/style/noNonNullAssertion: context initialization // biome-ignore lint/style/noNonNullAssertion: context initialization
@@ -66,20 +54,16 @@ export const Provider = <R, ER>(
) )
} }
const ProviderInner = <R, ER>( interface ProviderInnerProps<R, ER> {
{ runtime, promise, children }: {
readonly runtime: ReactRuntime<R, ER> readonly runtime: ReactRuntime<R, ER>
readonly promise: Promise<Runtime.Runtime<R>> readonly promise: Promise<Runtime.Runtime<R>>
readonly children?: React.ReactNode readonly children?: React.ReactNode
} }
): React.ReactNode => {
const effectRuntime = React.use(promise)
const scope = Runtime.runSync(effectRuntime)(Component.useScope([effectRuntime]))
Runtime.runSync(effectRuntime)(Effect.provideService(
Component.useOnChange(() => Effect.addFinalizer(() => runtime.runtime.disposeEffect), [scope]),
Scope.Scope,
scope,
))
return React.createElement(runtime.context, { value: effectRuntime }, children) const ProviderInner = <R, ER>(
} { runtime, promise, children }: ProviderInnerProps<R, ER>
): React.ReactNode => React.createElement(
runtime.context,
{ value: React.use(promise) },
children,
)

View File

@@ -1,279 +0,0 @@
import { Cause, Context, Data, Effect, Equal, Exit, type Fiber, Hash, Layer, Match, Pipeable, Predicate, PubSub, pipe, Ref, type Scope, Stream, Subscribable } from "effect"
export const ResultTypeId: unique symbol = Symbol.for("@effect-fc/Result/Result")
export type ResultTypeId = typeof ResultTypeId
export type Result<A, E = never, P = never> = (
| Initial
| Running<P>
| Final<A, E, P>
)
// biome-ignore lint/complexity/noBannedTypes: "{}" is relevant here
export type Final<A, E = never, P = never> = (Success<A> | Failure<E>) & ({} | Flags<P>)
export type Flags<P = never> = WillFetch | WillRefresh | Refreshing<P>
export declare namespace Result {
export interface Prototype extends Pipeable.Pipeable, Equal.Equal {
readonly [ResultTypeId]: ResultTypeId
}
export type Success<R extends Result<any, any, any>> = [R] extends [Result<infer A, infer _E, infer _P>] ? A : never
export type Failure<R extends Result<any, any, any>> = [R] extends [Result<infer _A, infer E, infer _P>] ? E : never
export type Progress<R extends Result<any, any, any>> = [R] extends [Result<infer _A, infer _E, infer P>] ? P : never
}
export declare namespace Flags {
export type Keys = keyof WillFetch & WillRefresh & Refreshing<any>
}
export interface Initial extends Result.Prototype {
readonly _tag: "Initial"
}
export interface Running<P = never> extends Result.Prototype {
readonly _tag: "Running"
readonly progress: P
}
export interface Success<A> extends Result.Prototype {
readonly _tag: "Success"
readonly value: A
}
export interface Failure<E = never> extends Result.Prototype {
readonly _tag: "Failure"
readonly cause: Cause.Cause<E>
}
export interface WillFetch {
readonly _flag: "WillFetch"
}
export interface WillRefresh {
readonly _flag: "WillRefresh"
}
export interface Refreshing<P = never> {
readonly _flag: "Refreshing"
readonly progress: P
}
const ResultPrototype = Object.freeze({
...Pipeable.Prototype,
[ResultTypeId]: ResultTypeId,
[Equal.symbol](this: Result<any, any, any>, that: Result<any, any, any>): boolean {
if (this._tag !== that._tag || (this as Flags)._flag !== (that as Flags)._flag)
return false
if (hasRefreshingFlag(this) && !Equal.equals(this.progress, (that as Refreshing<any>).progress))
return false
return Match.value(this).pipe(
Match.tag("Initial", () => true),
Match.tag("Running", self => Equal.equals(self.progress, (that as Running<any>).progress)),
Match.tag("Success", self => Equal.equals(self.value, (that as Success<any>).value)),
Match.tag("Failure", self => Equal.equals(self.cause, (that as Failure<any>).cause)),
Match.exhaustive,
)
},
[Hash.symbol](this: Result<any, any, any>): number {
return pipe(Hash.string(this._tag),
tagHash => Match.value(this).pipe(
Match.tag("Initial", () => tagHash),
Match.tag("Running", self => Hash.combine(Hash.hash(self.progress))(tagHash)),
Match.tag("Success", self => Hash.combine(Hash.hash(self.value))(tagHash)),
Match.tag("Failure", self => Hash.combine(Hash.hash(self.cause))(tagHash)),
Match.exhaustive,
),
Hash.combine(Hash.hash((this as Flags)._flag)),
hash => hasRefreshingFlag(this)
? Hash.combine(Hash.hash(this.progress))(hash)
: hash,
Hash.cached(this),
)
},
} as const satisfies Result.Prototype)
export const isResult = (u: unknown): u is Result<unknown, unknown, unknown> => Predicate.hasProperty(u, ResultTypeId)
export const isFinal = (u: unknown): u is Final<unknown, unknown, unknown> => isResult(u) && (isSuccess(u) || isFailure(u))
export const isInitial = (u: unknown): u is Initial => isResult(u) && u._tag === "Initial"
export const isRunning = (u: unknown): u is Running<unknown> => isResult(u) && u._tag === "Running"
export const isSuccess = (u: unknown): u is Success<unknown> => isResult(u) && u._tag === "Success"
export const isFailure = (u: unknown): u is Failure<unknown> => isResult(u) && u._tag === "Failure"
export const hasFlag = (u: unknown): u is Flags => isResult(u) && Predicate.hasProperty(u, "_flag")
export const hasWillFetchFlag = (u: unknown): u is WillFetch => isResult(u) && Predicate.hasProperty(u, "_flag") && u._flag === "WillFetch"
export const hasWillRefreshFlag = (u: unknown): u is WillRefresh => isResult(u) && Predicate.hasProperty(u, "_flag") && u._flag === "WillRefresh"
export const hasRefreshingFlag = (u: unknown): u is Refreshing<unknown> => isResult(u) && Predicate.hasProperty(u, "_flag") && u._flag === "Refreshing"
export const initial: {
(): Initial
<A, E = never, P = never>(): Result<A, E, P>
} = (): Initial => Object.setPrototypeOf({ _tag: "Initial" }, ResultPrototype)
export const running = <P = never>(progress?: P): Running<P> => Object.setPrototypeOf({ _tag: "Running", progress }, ResultPrototype)
export const succeed = <A>(value: A): Success<A> => Object.setPrototypeOf({ _tag: "Success", value }, ResultPrototype)
export const fail = <E>(cause: Cause.Cause<E> ): Failure<E> => Object.setPrototypeOf({ _tag: "Failure", cause }, ResultPrototype)
export const willFetch = <R extends Final<any, any, any>>(
result: R
): Omit<R, keyof Flags.Keys> & WillFetch => Object.setPrototypeOf(
Object.assign({}, result, { _flag: "WillFetch" }),
Object.getPrototypeOf(result),
)
export const willRefresh = <R extends Final<any, any, any>>(
result: R
): Omit<R, keyof Flags.Keys> & WillRefresh => Object.setPrototypeOf(
Object.assign({}, result, { _flag: "WillRefresh" }),
Object.getPrototypeOf(result),
)
export const refreshing = <R extends Final<any, any, any>, P = never>(
result: R,
progress?: P,
): Omit<R, keyof Flags.Keys> & Refreshing<P> => Object.setPrototypeOf(
Object.assign({}, result, { _flag: "Refreshing", progress }),
Object.getPrototypeOf(result),
)
export const fromExit: {
<A, E>(exit: Exit.Success<A, E>): Success<A>
<A, E>(exit: Exit.Failure<A, E>): Failure<E>
<A, E>(exit: Exit.Exit<A, E>): Success<A> | Failure<E>
} = exit => (exit._tag === "Success" ? succeed(exit.value) : fail(exit.cause)) as any
export const toExit: {
<A>(self: Success<A>): Exit.Success<A, never>
<E>(self: Failure<E>): Exit.Failure<never, E>
<A, E, P>(self: Final<A, E, P>): Exit.Exit<A, E>
<A, E, P>(self: Result<A, E, P>): Exit.Exit<A, E | Cause.NoSuchElementException>
} = <A, E, P>(self: Result<A, E, P>): any => {
switch (self._tag) {
case "Success":
return Exit.succeed(self.value)
case "Failure":
return Exit.failCause(self.cause)
default:
return Exit.fail(new Cause.NoSuchElementException())
}
}
export interface State<A, E = never, P = never> {
readonly get: Effect.Effect<Result<A, E, P>>
readonly set: (v: Result<A, E, P>) => Effect.Effect<void>
}
export const State = <A, E = never, P = never>(): Context.Tag<State<A, E, P>, State<A, E, P>> => Context.GenericTag("@effect-fc/Result/State")
export interface Progress<P = never> {
readonly update: <E, R>(
f: (previous: P) => Effect.Effect<P, E, R>
) => Effect.Effect<void, PreviousResultNotRunningNorRefreshing | E, R>
}
export class PreviousResultNotRunningNorRefreshing extends Data.TaggedError("@effect-fc/Result/PreviousResultNotRunningNorRefreshing")<{
readonly previous: Result<unknown, unknown, unknown>
}> {}
export const Progress = <P = never>(): Context.Tag<Progress<P>, Progress<P>> => Context.GenericTag("@effect-fc/Result/Progress")
export const makeProgressLayer = <A, E, P = never>(): Layer.Layer<
Progress<P>,
never,
State<A, E, P>
> => Layer.effect(Progress<P>(), Effect.gen(function*() {
const state = yield* State<A, E, P>()
return {
update: <FE, FR>(f: (previous: P) => Effect.Effect<P, FE, FR>) => Effect.Do.pipe(
Effect.bind("previous", () => Effect.andThen(state.get, previous =>
(isRunning(previous) || hasRefreshingFlag(previous))
? Effect.succeed(previous)
: Effect.fail(new PreviousResultNotRunningNorRefreshing({ previous })),
)),
Effect.bind("progress", ({ previous }) => f(previous.progress)),
Effect.let("next", ({ previous, progress }) => isRunning(previous)
? running(progress)
: refreshing(previous, progress) as Final<A, E, P> & Refreshing<P>
),
Effect.andThen(({ next }) => state.set(next)),
),
}
}))
export namespace unsafeForkEffect {
export type OutputContext<A, E, R, P> = Exclude<R, State<A, E, P> | Progress<P> | Progress<never>>
export interface Options<A, E, P> {
readonly initial?: Initial | Final<A, E, P>
readonly initialProgress?: P
}
}
export const unsafeForkEffect = <A, E, R, P = never>(
effect: Effect.Effect<A, E, R>,
options?: unsafeForkEffect.Options<NoInfer<A>, NoInfer<E>, P>,
): Effect.Effect<
readonly [result: Subscribable.Subscribable<Result<A, E, P>, never, never>, fiber: Fiber.Fiber<A, E>],
never,
Scope.Scope | unsafeForkEffect.OutputContext<A, E, R, P>
> => Effect.Do.pipe(
Effect.bind("ref", () => Ref.make(options?.initial ?? initial<A, E, P>())),
Effect.bind("pubsub", () => PubSub.unbounded<Result<A, E, P>>()),
Effect.bind("fiber", ({ ref, pubsub }) => Effect.forkScoped(State<A, E, P>().pipe(
Effect.andThen(state => state.set(
(isFinal(options?.initial) && hasWillRefreshFlag(options?.initial))
? refreshing(options.initial, options?.initialProgress) as Result<A, E, P>
: running(options?.initialProgress)
).pipe(
Effect.andThen(effect),
Effect.onExit(exit => Effect.andThen(
state.set(fromExit(exit)),
Effect.forkScoped(PubSub.shutdown(pubsub)),
)),
)),
Effect.provide(Layer.empty.pipe(
Layer.provideMerge(makeProgressLayer<A, E, P>()),
Layer.provideMerge(Layer.succeed(State<A, E, P>(), {
get: ref,
set: v => Effect.andThen(Ref.set(ref, v), PubSub.publish(pubsub, v))
})),
)),
))),
Effect.map(({ ref, pubsub, fiber }) => [
Subscribable.make({
get: ref,
changes: Stream.unwrapScoped(Effect.map(
Effect.all([ref, Stream.fromPubSub(pubsub, { scoped: true })]),
([latest, stream]) => Stream.concat(Stream.make(latest), stream),
)),
}),
fiber,
]),
) as Effect.Effect<
readonly [result: Subscribable.Subscribable<Result<A, E, P>, never, never>, fiber: Fiber.Fiber<A, E>],
never,
Scope.Scope | unsafeForkEffect.OutputContext<A, E, R, P>
>
export namespace forkEffect {
export type InputContext<R, P> = R extends Progress<infer X> ? [X] extends [P] ? R : never : R
export type OutputContext<A, E, R, P> = unsafeForkEffect.OutputContext<A, E, R, P>
export interface Options<A, E, P> extends unsafeForkEffect.Options<A, E, P> {}
}
export const forkEffect: {
<A, E, R, P = never>(
effect: Effect.Effect<A, E, forkEffect.InputContext<R, NoInfer<P>>>,
options?: forkEffect.Options<NoInfer<A>, NoInfer<E>, P>,
): Effect.Effect<
readonly [result: Subscribable.Subscribable<Result<A, E, P>, never, never>, fiber: Fiber.Fiber<A, E>],
never,
Scope.Scope | forkEffect.OutputContext<A, E, R, P>
>
} = unsafeForkEffect

View File

@@ -1,4 +1,4 @@
import { Effect, Equivalence, Stream, Subscribable } from "effect" import { Effect, Equivalence, pipe, type Scope, Stream, Subscribable } from "effect"
import * as React from "react" import * as React from "react"
import * as Component from "./Component.js" import * as Component from "./Component.js"
@@ -16,35 +16,30 @@ export const zipLatestAll = <const T extends readonly Subscribable.Subscribable<
changes: Stream.zipLatestAll(...elements.map(v => v.changes)), changes: Stream.zipLatestAll(...elements.map(v => v.changes)),
}) as any }) as any
export declare namespace useSubscribables { export const useSubscribables: {
export type Success<T extends readonly Subscribable.Subscribable<any, any, any>[]> = [T[number]] extends [never] <const T extends readonly Subscribable.Subscribable<any, any, any>[]>(
...elements: T
): Effect.Effect<
[T[number]] extends [never]
? never ? never
: { [K in keyof T]: T[K] extends Subscribable.Subscribable<infer A, infer _E, infer _R> ? A : never } : { [K in keyof T]: T[K] extends Subscribable.Subscribable<infer A, infer _E, infer _R> ? A : never },
export interface Options<A> {
readonly equivalence?: Equivalence.Equivalence<A>
}
}
export const useSubscribables = Effect.fnUntraced(function* <const T extends readonly Subscribable.Subscribable<any, any, any>[]>(
elements: T,
options?: useSubscribables.Options<useSubscribables.Success<NoInfer<T>>>,
): Effect.fn.Return<
useSubscribables.Success<T>,
[T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable<infer _A, infer E, infer _R> ? E : never, [T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable<infer _A, infer E, infer _R> ? E : never,
[T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable<infer _A, infer _E, infer R> ? R : never ([T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable<infer _A, infer _E, infer R> ? R : never) | Scope.Scope
> { >
} = Effect.fnUntraced(function* <const T extends readonly Subscribable.Subscribable<any, any, any>[]>(
...elements: T
) {
const [reactStateValue, setReactStateValue] = React.useState( const [reactStateValue, setReactStateValue] = React.useState(
yield* Component.useOnMount(() => Effect.all(elements.map(v => v.get))) yield* Component.useOnMount(() => Effect.all(elements.map(v => v.get)))
) )
yield* Component.useReactEffect(() => Stream.zipLatestAll(...elements.map(ref => ref.changes)).pipe( yield* Component.useOnChange(() => Effect.forkScoped(pipe(
Stream.changesWith((options?.equivalence as Equivalence.Equivalence<any[]> | undefined) ?? Equivalence.array(Equivalence.strict())), elements.map(ref => Stream.changesWith(ref.changes, Equivalence.strict())),
streams => Stream.zipLatestAll(...streams),
Stream.runForEach(v => Stream.runForEach(v =>
Effect.sync(() => setReactStateValue(v)) Effect.sync(() => setReactStateValue(v))
), ),
Effect.forkScoped, )), elements)
), elements)
return reactStateValue as any return reactStateValue as any
}) })

View File

@@ -1,60 +1,42 @@
import { Effect, Equivalence, Ref, Stream, SubscriptionRef } from "effect" import { Effect, Equivalence, Ref, type Scope, Stream, SubscriptionRef } from "effect"
import * as React from "react" import * as React from "react"
import * as Component from "./Component.js" import * as Component from "./Component.js"
import * as SetStateAction from "./SetStateAction.js" import * as SetStateAction from "./SetStateAction.js"
export declare namespace useSubscriptionRefState { export const useSubscriptionRefState: {
export interface Options<A> { <A>(
readonly equivalence?: Equivalence.Equivalence<A> ref: SubscriptionRef.SubscriptionRef<A>
} ): Effect.Effect<readonly [A, React.Dispatch<React.SetStateAction<A>>], never, Scope.Scope>
} } = Effect.fnUntraced(function* <A>(ref: SubscriptionRef.SubscriptionRef<A>) {
export const useSubscriptionRefState = Effect.fnUntraced(function* <A>(
ref: SubscriptionRef.SubscriptionRef<A>,
options?: useSubscriptionRefState.Options<NoInfer<A>>,
): Effect.fn.Return<readonly [A, React.Dispatch<React.SetStateAction<A>>]> {
const [reactStateValue, setReactStateValue] = React.useState(yield* Component.useOnMount(() => ref)) const [reactStateValue, setReactStateValue] = React.useState(yield* Component.useOnMount(() => ref))
yield* Component.useReactEffect(() => Effect.forkScoped( yield* Component.useOnChange(() => Effect.forkScoped(Stream.runForEach(
Stream.runForEach( Stream.changesWith(ref.changes, Equivalence.strict()),
Stream.changesWith(ref.changes, options?.equivalence ?? Equivalence.strict()),
v => Effect.sync(() => setReactStateValue(v)), v => Effect.sync(() => setReactStateValue(v)),
) )), [ref])
), [ref])
const setValue = yield* Component.useCallbackSync( const setValue = yield* Component.useCallbackSync((setStateAction: React.SetStateAction<A>) =>
(setStateAction: React.SetStateAction<A>) => Effect.andThen( Effect.andThen(
Ref.updateAndGet(ref, prevState => SetStateAction.value(setStateAction, prevState)), Ref.updateAndGet(ref, prevState => SetStateAction.value(setStateAction, prevState)),
v => setReactStateValue(v), v => setReactStateValue(v),
), ),
[ref], [ref])
)
return [reactStateValue, setValue] return [reactStateValue, setValue]
}) })
export declare namespace useSubscriptionRefFromState { export const useSubscriptionRefFromState: {
export interface Options<A> { <A>(state: readonly [A, React.Dispatch<React.SetStateAction<A>>]): Effect.Effect<SubscriptionRef.SubscriptionRef<A>, never, Scope.Scope>
readonly equivalence?: Equivalence.Equivalence<A> } = Effect.fnUntraced(function*([value, setValue]) {
} const ref = yield* Component.useOnMount(() => SubscriptionRef.make(value))
}
export const useSubscriptionRefFromState = Effect.fnUntraced(function* <A>( yield* Component.useOnChange(() => Effect.forkScoped(Stream.runForEach(
[value, setValue]: readonly [A, React.Dispatch<React.SetStateAction<A>>], Stream.changesWith(ref.changes, Equivalence.strict()),
options?: useSubscriptionRefFromState.Options<NoInfer<A>>,
): Effect.fn.Return<SubscriptionRef.SubscriptionRef<A>> {
const ref = yield* Component.useOnChange(() => Effect.tap(
SubscriptionRef.make(value),
ref => Effect.forkScoped(
Stream.runForEach(
Stream.changesWith(ref.changes, options?.equivalence ?? Equivalence.strict()),
v => Effect.sync(() => setValue(v)), v => Effect.sync(() => setValue(v)),
) )), [setValue])
),
), [setValue])
yield* Component.useReactEffect(() => Ref.set(ref, value), [value]) yield* Component.useReactEffect(() => Ref.set(ref, value), [value])
return ref return ref
}) })

View File

@@ -2,7 +2,7 @@ import { Chunk, Effect, Effectable, Option, Predicate, Readable, Ref, Stream, Su
import * as PropertyPath from "./PropertyPath.js" import * as PropertyPath from "./PropertyPath.js"
export const SubscriptionSubRefTypeId: unique symbol = Symbol.for("@effect-fc/SubscriptionSubRef/SubscriptionSubRef") export const SubscriptionSubRefTypeId: unique symbol = Symbol.for("effect-fc/SubscriptionSubRef/SubscriptionSubRef")
export type SubscriptionSubRefTypeId = typeof SubscriptionSubRefTypeId export type SubscriptionSubRefTypeId = typeof SubscriptionSubRefTypeId
export interface SubscriptionSubRef<in out A, in out B extends SubscriptionRef.SubscriptionRef<any>> export interface SubscriptionSubRef<in out A, in out B extends SubscriptionRef.SubscriptionRef<any>>

View File

@@ -1,17 +1,11 @@
export * as Async from "./Async.js" export * as Async from "./Async.js"
export * as Component from "./Component.js" export * as Component from "./Component.js"
export * as ErrorObserver from "./ErrorObserver.js"
export * as Form from "./Form.js" export * as Form from "./Form.js"
export * as Hooks from "./Hooks/index.js"
export * as Memoized from "./Memoized.js" export * as Memoized from "./Memoized.js"
export * as Mutation from "./Mutation.js"
export * as PropertyPath from "./PropertyPath.js" export * as PropertyPath from "./PropertyPath.js"
export * as PubSub from "./PubSub.js"
export * as Query from "./Query.js"
export * as QueryClient from "./QueryClient.js"
export * as ReactRuntime from "./ReactRuntime.js" export * as ReactRuntime from "./ReactRuntime.js"
export * as Result from "./Result.js"
export * as SetStateAction from "./SetStateAction.js" export * as SetStateAction from "./SetStateAction.js"
export * as Stream from "./Stream.js"
export * as Subscribable from "./Subscribable.js" export * as Subscribable from "./Subscribable.js"
export * as SubscriptionRef from "./SubscriptionRef.js" export * as SubscriptionRef from "./SubscriptionRef.js"
export * as SubscriptionSubRef from "./SubscriptionSubRef.js" export * as SubscriptionSubRef from "./SubscriptionSubRef.js"

View File

@@ -13,30 +13,32 @@
"clean:modules": "rm -rf node_modules" "clean:modules": "rm -rf node_modules"
}, },
"devDependencies": { "devDependencies": {
"@tanstack/react-router": "^1.139.12", "@tanstack/react-router": "^1.132.31",
"@tanstack/react-router-devtools": "^1.139.12", "@tanstack/react-router-devtools": "^1.132.31",
"@tanstack/router-plugin": "^1.139.12", "@tanstack/router-plugin": "^1.132.31",
"@types/react": "^19.2.7", "@types/react": "^19.2.0",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^5.1.1", "@vitejs/plugin-react": "^5.0.4",
"globals": "^17.0.0", "globals": "^16.4.0",
"react": "^19.2.0", "react": "^19.2.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.0",
"type-fest": "^5.2.0", "type-fest": "^5.0.1",
"vite": "^7.2.6" "vite": "^7.1.8"
}, },
"dependencies": { "dependencies": {
"@effect/platform": "^0.94.0", "@effect/platform": "^0.92.1",
"@effect/platform-browser": "^0.74.0", "@effect/platform-browser": "^0.72.0",
"@radix-ui/themes": "^3.2.1", "@radix-ui/themes": "^3.2.1",
"@typed/async-data": "^0.13.1",
"@typed/id": "^0.17.2", "@typed/id": "^0.17.2",
"effect": "^3.19.8", "@typed/lazy-ref": "^0.3.3",
"effect": "^3.18.1",
"effect-fc": "workspace:*", "effect-fc": "workspace:*",
"react-icons": "^5.5.0" "react-icons": "^5.5.0"
}, },
"overrides": { "overrides": {
"@types/react": "^19.2.7", "@types/react": "^19.2.0",
"effect": "^3.19.8", "effect": "^3.18.1",
"react": "^19.2.0" "react": "^19.2.0"
} }
} }

View File

@@ -1,6 +1,6 @@
import { Callout, Flex, Spinner, Switch, TextField } from "@radix-ui/themes" import { Callout, Flex, Spinner, Switch, TextField } from "@radix-ui/themes"
import { Array, Option, Struct } from "effect" import { Array, Option, Struct } from "effect"
import { Component, Form, Subscribable } from "effect-fc" import { Component, Form, Hooks } from "effect-fc"
interface Props interface Props
@@ -18,21 +18,22 @@ extends Omit<TextField.RootProps, "optional" | "defaultValue">, Form.useOptional
export type TextFieldFormInputProps = Props | OptionalProps export type TextFieldFormInputProps = Props | OptionalProps
export class TextFieldFormInput extends Component.makeUntraced("TextFieldFormInput")(function*(props: TextFieldFormInputProps) { export class TextFieldFormInput extends Component.makeUntraced("TextFieldFormInput")(
function*(props: TextFieldFormInputProps) {
const input: ( const input: (
| { readonly optional: true } & Form.useOptionalInput.Success<string> | { readonly optional: true } & Form.useOptionalInput.Result<string>
| { readonly optional: false } & Form.useInput.Success<string> | { readonly optional: false } & Form.useInput.Result<string>
) = props.optional ) = props.optional
// biome-ignore lint/correctness/useHookAtTopLevel: "optional" reactivity not supported // biome-ignore lint/correctness/useHookAtTopLevel: "optional" reactivity not supported
? { optional: true, ...yield* Form.useOptionalInput(props.field, props) } ? { optional: true, ...yield* Form.useOptionalInput(props.field, props) }
// biome-ignore lint/correctness/useHookAtTopLevel: "optional" reactivity not supported // biome-ignore lint/correctness/useHookAtTopLevel: "optional" reactivity not supported
: { optional: false, ...yield* Form.useInput(props.field, props) } : { optional: false, ...yield* Form.useInput(props.field, props) }
const [issues, isValidating, isSubmitting] = yield* Subscribable.useSubscribables([ const [issues, isValidating, isSubmitting] = yield* Hooks.useSubscribables(
props.field.issues, props.field.issuesSubscribable,
props.field.isValidating, props.field.isValidatingSubscribable,
props.field.isSubmitting, props.field.isSubmittingSubscribable,
]) )
return ( return (
<Flex direction="column" gap="1"> <Flex direction="column" gap="1">
@@ -72,4 +73,5 @@ export class TextFieldFormInput extends Component.makeUntraced("TextFieldFormInp
})} })}
</Flex> </Flex>
) )
}) {} }
) {}

View File

@@ -9,25 +9,12 @@
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
import { Route as rootRouteImport } from './routes/__root' import { Route as rootRouteImport } from './routes/__root'
import { Route as ResultRouteImport } from './routes/result'
import { Route as QueryRouteImport } from './routes/query'
import { Route as FormRouteImport } from './routes/form' import { Route as FormRouteImport } from './routes/form'
import { Route as BlankRouteImport } from './routes/blank' import { Route as BlankRouteImport } from './routes/blank'
import { Route as IndexRouteImport } from './routes/index' import { Route as IndexRouteImport } from './routes/index'
import { Route as DevMemoRouteImport } from './routes/dev/memo' import { Route as DevMemoRouteImport } from './routes/dev/memo'
import { Route as DevContextRouteImport } from './routes/dev/context'
import { Route as DevAsyncRenderingRouteImport } from './routes/dev/async-rendering' import { Route as DevAsyncRenderingRouteImport } from './routes/dev/async-rendering'
const ResultRoute = ResultRouteImport.update({
id: '/result',
path: '/result',
getParentRoute: () => rootRouteImport,
} as any)
const QueryRoute = QueryRouteImport.update({
id: '/query',
path: '/query',
getParentRoute: () => rootRouteImport,
} as any)
const FormRoute = FormRouteImport.update({ const FormRoute = FormRouteImport.update({
id: '/form', id: '/form',
path: '/form', path: '/form',
@@ -48,11 +35,6 @@ const DevMemoRoute = DevMemoRouteImport.update({
path: '/dev/memo', path: '/dev/memo',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
} as any) } as any)
const DevContextRoute = DevContextRouteImport.update({
id: '/dev/context',
path: '/dev/context',
getParentRoute: () => rootRouteImport,
} as any)
const DevAsyncRenderingRoute = DevAsyncRenderingRouteImport.update({ const DevAsyncRenderingRoute = DevAsyncRenderingRouteImport.update({
id: '/dev/async-rendering', id: '/dev/async-rendering',
path: '/dev/async-rendering', path: '/dev/async-rendering',
@@ -63,20 +45,14 @@ export interface FileRoutesByFullPath {
'/': typeof IndexRoute '/': typeof IndexRoute
'/blank': typeof BlankRoute '/blank': typeof BlankRoute
'/form': typeof FormRoute '/form': typeof FormRoute
'/query': typeof QueryRoute
'/result': typeof ResultRoute
'/dev/async-rendering': typeof DevAsyncRenderingRoute '/dev/async-rendering': typeof DevAsyncRenderingRoute
'/dev/context': typeof DevContextRoute
'/dev/memo': typeof DevMemoRoute '/dev/memo': typeof DevMemoRoute
} }
export interface FileRoutesByTo { export interface FileRoutesByTo {
'/': typeof IndexRoute '/': typeof IndexRoute
'/blank': typeof BlankRoute '/blank': typeof BlankRoute
'/form': typeof FormRoute '/form': typeof FormRoute
'/query': typeof QueryRoute
'/result': typeof ResultRoute
'/dev/async-rendering': typeof DevAsyncRenderingRoute '/dev/async-rendering': typeof DevAsyncRenderingRoute
'/dev/context': typeof DevContextRoute
'/dev/memo': typeof DevMemoRoute '/dev/memo': typeof DevMemoRoute
} }
export interface FileRoutesById { export interface FileRoutesById {
@@ -84,42 +60,20 @@ export interface FileRoutesById {
'/': typeof IndexRoute '/': typeof IndexRoute
'/blank': typeof BlankRoute '/blank': typeof BlankRoute
'/form': typeof FormRoute '/form': typeof FormRoute
'/query': typeof QueryRoute
'/result': typeof ResultRoute
'/dev/async-rendering': typeof DevAsyncRenderingRoute '/dev/async-rendering': typeof DevAsyncRenderingRoute
'/dev/context': typeof DevContextRoute
'/dev/memo': typeof DevMemoRoute '/dev/memo': typeof DevMemoRoute
} }
export interface FileRouteTypes { export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: fullPaths: '/' | '/blank' | '/form' | '/dev/async-rendering' | '/dev/memo'
| '/'
| '/blank'
| '/form'
| '/query'
| '/result'
| '/dev/async-rendering'
| '/dev/context'
| '/dev/memo'
fileRoutesByTo: FileRoutesByTo fileRoutesByTo: FileRoutesByTo
to: to: '/' | '/blank' | '/form' | '/dev/async-rendering' | '/dev/memo'
| '/'
| '/blank'
| '/form'
| '/query'
| '/result'
| '/dev/async-rendering'
| '/dev/context'
| '/dev/memo'
id: id:
| '__root__' | '__root__'
| '/' | '/'
| '/blank' | '/blank'
| '/form' | '/form'
| '/query'
| '/result'
| '/dev/async-rendering' | '/dev/async-rendering'
| '/dev/context'
| '/dev/memo' | '/dev/memo'
fileRoutesById: FileRoutesById fileRoutesById: FileRoutesById
} }
@@ -127,29 +81,12 @@ export interface RootRouteChildren {
IndexRoute: typeof IndexRoute IndexRoute: typeof IndexRoute
BlankRoute: typeof BlankRoute BlankRoute: typeof BlankRoute
FormRoute: typeof FormRoute FormRoute: typeof FormRoute
QueryRoute: typeof QueryRoute
ResultRoute: typeof ResultRoute
DevAsyncRenderingRoute: typeof DevAsyncRenderingRoute DevAsyncRenderingRoute: typeof DevAsyncRenderingRoute
DevContextRoute: typeof DevContextRoute
DevMemoRoute: typeof DevMemoRoute DevMemoRoute: typeof DevMemoRoute
} }
declare module '@tanstack/react-router' { declare module '@tanstack/react-router' {
interface FileRoutesByPath { interface FileRoutesByPath {
'/result': {
id: '/result'
path: '/result'
fullPath: '/result'
preLoaderRoute: typeof ResultRouteImport
parentRoute: typeof rootRouteImport
}
'/query': {
id: '/query'
path: '/query'
fullPath: '/query'
preLoaderRoute: typeof QueryRouteImport
parentRoute: typeof rootRouteImport
}
'/form': { '/form': {
id: '/form' id: '/form'
path: '/form' path: '/form'
@@ -178,13 +115,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DevMemoRouteImport preLoaderRoute: typeof DevMemoRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
'/dev/context': {
id: '/dev/context'
path: '/dev/context'
fullPath: '/dev/context'
preLoaderRoute: typeof DevContextRouteImport
parentRoute: typeof rootRouteImport
}
'/dev/async-rendering': { '/dev/async-rendering': {
id: '/dev/async-rendering' id: '/dev/async-rendering'
path: '/dev/async-rendering' path: '/dev/async-rendering'
@@ -199,10 +129,7 @@ const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute, IndexRoute: IndexRoute,
BlankRoute: BlankRoute, BlankRoute: BlankRoute,
FormRoute: FormRoute, FormRoute: FormRoute,
QueryRoute: QueryRoute,
ResultRoute: ResultRoute,
DevAsyncRenderingRoute: DevAsyncRenderingRoute, DevAsyncRenderingRoute: DevAsyncRenderingRoute,
DevContextRoute: DevContextRoute,
DevMemoRoute: DevMemoRoute, DevMemoRoute: DevMemoRoute,
} }
export const routeTree = rootRouteImport export const routeTree = rootRouteImport

View File

@@ -1,42 +0,0 @@
import { Container, Flex, Text, TextField } from "@radix-ui/themes"
import { createFileRoute } from "@tanstack/react-router"
import { Console, Effect } from "effect"
import { Component } from "effect-fc"
import * as React from "react"
import { runtime } from "@/runtime"
class SubService extends Effect.Service<SubService>()("SubService", {
effect: (value: string) => Effect.succeed({ value })
}) {}
const SubComponent = Component.makeUntraced("SubComponent")(function*() {
const service = yield* SubService
yield* Component.useOnMount(() => Effect.gen(function*() {
yield* Effect.addFinalizer(() => Console.log("SubComponent unmounted"))
yield* Console.log("SubComponent mounted")
}))
return <Text>{service.value}</Text>
})
const ContextView = Component.makeUntraced("ContextView")(function*() {
const [serviceValue, setServiceValue] = React.useState("test")
const SubServiceLayer = React.useMemo(() => SubService.Default(serviceValue), [serviceValue])
const SubComponentFC = yield* Effect.provide(SubComponent, yield* Component.useContext(SubServiceLayer))
return (
<Container>
<Flex direction="column" align="center">
<TextField.Root value={serviceValue} onChange={e => setServiceValue(e.target.value)} />
<SubComponentFC />
</Flex>
</Container>
)
}).pipe(
Component.withRuntime(runtime.context)
)
export const Route = createFileRoute("/dev/context")({
component: ContextView
})

View File

@@ -1,6 +1,6 @@
import { Button, Container, Flex, Text } from "@radix-ui/themes" import { Button, Container, Flex } from "@radix-ui/themes"
import { createFileRoute } from "@tanstack/react-router" import { createFileRoute } from "@tanstack/react-router"
import { Console, Effect, Match, Option, ParseResult, Schema } from "effect" import { Console, Effect, Option, ParseResult, Schema } from "effect"
import { Component, Form, Subscribable } from "effect-fc" import { Component, Form, Subscribable } from "effect-fc"
import { TextFieldFormInput } from "@/lib/form/TextFieldFormInput" import { TextFieldFormInput } from "@/lib/form/TextFieldFormInput"
import { DateTimeUtcFromZonedInput } from "@/lib/schema" import { DateTimeUtcFromZonedInput } from "@/lib/schema"
@@ -23,21 +23,6 @@ const RegisterFormSchema = Schema.Struct({
birth: Schema.OptionFromSelf(DateTimeUtcFromZonedInput), birth: Schema.OptionFromSelf(DateTimeUtcFromZonedInput),
}) })
const RegisterFormSubmitSchema = Schema.Struct({
email: Schema.transformOrFail(
Schema.String,
Schema.String,
{
decode: (input, _options, ast) => input !== "admin@admin.com"
? ParseResult.succeed(input)
: ParseResult.fail(new ParseResult.Type(ast, input, "This email is already in use.")),
encode: ParseResult.succeed,
},
),
password: Schema.String,
birth: Schema.OptionFromSelf(Schema.DateTimeUtcFromSelf),
})
class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", { class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", {
scoped: Form.service({ scoped: Form.service({
schema: RegisterFormSchema.pipe( schema: RegisterFormSchema.pipe(
@@ -54,22 +39,19 @@ class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", {
), ),
initialEncodedValue: { email: "", password: "", birth: Option.none() }, initialEncodedValue: { email: "", password: "", birth: Option.none() },
f: Effect.fnUntraced(function*([value]) { onSubmit: v => Effect.sleep("500 millis").pipe(
yield* Effect.sleep("500 millis") Effect.andThen(Console.log(v)),
return yield* Schema.decode(RegisterFormSubmitSchema)(value) Effect.andThen(Effect.sync(() => alert("Done!"))),
}), ),
debounce: "500 millis", debounce: "500 millis",
}) })
}) {} }) {}
class RegisterFormView extends Component.makeUntraced("RegisterFormView")(function*() { class RegisterFormView extends Component.makeUntraced("RegisterFormView")(function*() {
const form = yield* RegisterForm const form = yield* RegisterForm
const [canSubmit, submitResult] = yield* Subscribable.useSubscribables([ const submit = yield* Form.useSubmit(form)
form.canSubmit, const [canSubmit] = yield* Subscribable.useSubscribables(form.canSubmitSubscribable)
form.mutation.result,
])
const runPromise = yield* Component.useRunPromise()
const TextFieldFormInputFC = yield* TextFieldFormInput const TextFieldFormInputFC = yield* TextFieldFormInput
yield* Component.useOnMount(() => Effect.gen(function*() { yield* Component.useOnMount(() => Effect.gen(function*() {
@@ -82,35 +64,27 @@ class RegisterFormView extends Component.makeUntraced("RegisterFormView")(functi
<Container width="300"> <Container width="300">
<form onSubmit={e => { <form onSubmit={e => {
e.preventDefault() e.preventDefault()
void runPromise(form.submit) void submit()
}}> }}>
<Flex direction="column" gap="2"> <Flex direction="column" gap="2">
<TextFieldFormInputFC <TextFieldFormInputFC
field={yield* form.field(["email"])} field={Form.useField(form, ["email"])}
/> />
<TextFieldFormInputFC <TextFieldFormInputFC
field={yield* form.field(["password"])} field={Form.useField(form, ["password"])}
/> />
<TextFieldFormInputFC <TextFieldFormInputFC
optional optional
type="datetime-local" type="datetime-local"
field={yield* form.field(["birth"])} field={Form.useField(form, ["birth"])}
defaultValue="" defaultValue=""
/> />
<Button disabled={!canSubmit}>Submit</Button> <Button disabled={!canSubmit}>Submit</Button>
</Flex> </Flex>
</form> </form>
{Match.value(submitResult).pipe(
Match.tag("Initial", () => <></>),
Match.tag("Running", () => <Text>Submitting...</Text>),
Match.tag("Success", () => <Text>Submitted successfully!</Text>),
Match.tag("Failure", e => <Text>Error: {e.cause.toString()}</Text>),
Match.exhaustive,
)}
</Container> </Container>
) )
}) {} }) {}

View File

@@ -1,116 +0,0 @@
import { HttpClient, type HttpClientError } from "@effect/platform"
import { Button, Container, Flex, Heading, Slider, Text } from "@radix-ui/themes"
import { createFileRoute } from "@tanstack/react-router"
import { Array, Cause, Chunk, Console, Effect, flow, Match, Option, Schema, Stream } from "effect"
import { Component, ErrorObserver, Mutation, Query, Result, Subscribable, SubscriptionRef } from "effect-fc"
import { runtime } from "@/runtime"
const Post = Schema.Struct({
userId: Schema.Int,
id: Schema.Int,
title: Schema.String,
body: Schema.String,
})
const ResultView = Component.makeUntraced("Result")(function*() {
const runPromise = yield* Component.useRunPromise()
const [idRef, query, mutation] = yield* Component.useOnMount(() => Effect.gen(function*() {
const idRef = yield* SubscriptionRef.make(1)
const query = yield* Query.service({
key: Stream.zipLatest(Stream.make("posts" as const), idRef.changes),
f: ([, id]) => HttpClient.HttpClient.pipe(
Effect.tap(Effect.sleep("500 millis")),
Effect.andThen(client => client.get(`https://jsonplaceholder.typicode.com/posts/${ id }`)),
Effect.andThen(response => response.json),
Effect.andThen(Schema.decodeUnknown(Post)),
),
staleTime: "10 seconds",
})
const mutation = yield* Mutation.make({
f: ([id]: readonly [id: number]) => HttpClient.HttpClient.pipe(
Effect.tap(Effect.sleep("500 millis")),
Effect.andThen(client => client.get(`https://jsonplaceholder.typicode.com/posts/${ id }`)),
Effect.andThen(response => response.json),
Effect.andThen(Schema.decodeUnknown(Post)),
),
})
return [idRef, query, mutation] as const
}))
const [id, setId] = yield* SubscriptionRef.useSubscriptionRefState(idRef)
const [queryResult, mutationResult] = yield* Subscribable.useSubscribables([query.result, mutation.result])
yield* Component.useOnMount(() => ErrorObserver.ErrorObserver<HttpClientError.HttpClientError>().pipe(
Effect.andThen(observer => observer.subscribe),
Effect.andThen(Stream.fromQueue),
Stream.unwrapScoped,
Stream.runForEach(flow(
Cause.failures,
Chunk.findFirst(e => e._tag === "RequestError" || e._tag === "ResponseError"),
Option.match({
onSome: e => Console.log("ResultView HttpClient error", e),
onNone: () => Effect.void,
}),
)),
Effect.forkScoped,
))
return (
<Container>
<Flex direction="column" align="center" gap="2">
<Slider
value={[id]}
onValueChange={flow(Array.head, Option.getOrThrow, setId)}
/>
<div>
{Match.value(queryResult).pipe(
Match.tag("Running", () => <Text>Loading...</Text>),
Match.tag("Success", result => <>
<Heading>{result.value.title}</Heading>
<Text>{result.value.body}</Text>
{Result.hasRefreshingFlag(result) && <Text>Refreshing...</Text>}
</>),
Match.tag("Failure", result =>
<Text>An error has occured: {result.cause.toString()}</Text>
),
Match.orElse(() => <></>),
)}
</div>
<Flex direction="row" justify="center" align="center" gap="1">
<Button onClick={() => runPromise(query.refresh)}>Refresh</Button>
<Button onClick={() => runPromise(query.invalidateCache)}>Invalidate cache</Button>
</Flex>
<div>
{Match.value(mutationResult).pipe(
Match.tag("Running", () => <Text>Loading...</Text>),
Match.tag("Success", result => <>
<Heading>{result.value.title}</Heading>
<Text>{result.value.body}</Text>
{Result.hasRefreshingFlag(result) && <Text>Refreshing...</Text>}
</>),
Match.tag("Failure", result =>
<Text>An error has occured: {result.cause.toString()}</Text>
),
Match.orElse(() => <></>),
)}
</div>
<Flex direction="row" justify="center" align="center" gap="1">
<Button onClick={() => runPromise(Effect.andThen(idRef, id => mutation.mutate([id])))}>Mutate</Button>
</Flex>
</Flex>
</Container>
)
})
export const Route = createFileRoute("/query")({
component: Component.withRuntime(ResultView, runtime.context)
})

View File

@@ -1,60 +0,0 @@
import { HttpClient, type HttpClientError } from "@effect/platform"
import { Container, Heading, Text } from "@radix-ui/themes"
import { createFileRoute } from "@tanstack/react-router"
import { Cause, Chunk, Console, Effect, flow, Match, Option, Schema, Stream } from "effect"
import { Component, ErrorObserver, Result, Subscribable } from "effect-fc"
import { runtime } from "@/runtime"
const Post = Schema.Struct({
userId: Schema.Int,
id: Schema.Int,
title: Schema.String,
body: Schema.String,
})
const ResultView = Component.makeUntraced("Result")(function*() {
const [resultSubscribable] = yield* Component.useOnMount(() => HttpClient.HttpClient.pipe(
Effect.andThen(client => client.get("https://jsonplaceholder.typicode.com/posts/1")),
Effect.andThen(response => response.json),
Effect.andThen(Schema.decodeUnknown(Post)),
Effect.tap(Effect.sleep("250 millis")),
Result.forkEffect,
))
const [result] = yield* Subscribable.useSubscribables([resultSubscribable])
yield* Component.useOnMount(() => ErrorObserver.ErrorObserver<HttpClientError.HttpClientError>().pipe(
Effect.andThen(observer => observer.subscribe),
Effect.andThen(Stream.fromQueue),
Stream.unwrapScoped,
Stream.runForEach(flow(
Cause.failures,
Chunk.findFirst(e => e._tag === "RequestError" || e._tag === "ResponseError"),
Option.match({
onSome: e => Console.log("ResultView HttpClient error", e),
onNone: () => Effect.void,
}),
)),
Effect.forkScoped,
))
return (
<Container>
{Match.value(result).pipe(
Match.tag("Running", () => <Text>Loading...</Text>),
Match.tag("Success", result => <>
<Heading>{result.value.title}</Heading>
<Text>{result.value.body}</Text>
</>),
Match.tag("Failure", result =>
<Text>An error has occured: {result.cause.toString()}</Text>
),
Match.orElse(() => <></>),
)}
</Container>
)
})
export const Route = createFileRoute("/result")({
component: Component.withRuntime(ResultView, runtime.context)
})

View File

@@ -1,6 +1,6 @@
import { Box, Button, Flex, IconButton } from "@radix-ui/themes" import { Box, Button, Flex, IconButton } from "@radix-ui/themes"
import { GetRandomValues, makeUuid4 } from "@typed/id" import { GetRandomValues, makeUuid4 } from "@typed/id"
import { Chunk, type DateTime, Effect, Match, Option, Ref, Schema, Stream } from "effect" import { Chunk, Effect, Match, Option, Ref, Runtime, Schema, Stream } from "effect"
import { Component, Form, Subscribable } from "effect-fc" import { Component, Form, Subscribable } from "effect-fc"
import { FaArrowDown, FaArrowUp } from "react-icons/fa" import { FaArrowDown, FaArrowUp } from "react-icons/fa"
import { FaDeleteLeft } from "react-icons/fa6" import { FaDeleteLeft } from "react-icons/fa6"
@@ -31,6 +31,7 @@ export type TodoProps = (
) )
export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoProps) { export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoProps) {
const runtime = yield* Effect.runtime()
const state = yield* TodosState const state = yield* TodosState
const [ const [
@@ -40,7 +41,7 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr
completedAtField, completedAtField,
] = yield* Component.useOnChange(() => Effect.gen(function*() { ] = yield* Component.useOnChange(() => Effect.gen(function*() {
const indexRef = Match.value(props).pipe( const indexRef = Match.value(props).pipe(
Match.tag("new", () => Subscribable.make({ get: Effect.succeed(-1), changes: Stream.make(-1) })), Match.tag("new", () => Subscribable.make({ get: Effect.succeed(-1), changes: Stream.empty })),
Match.tag("edit", ({ id }) => state.getIndexSubscribable(id)), Match.tag("edit", ({ id }) => state.getIndexSubscribable(id)),
Match.exhaustive, Match.exhaustive,
) )
@@ -54,15 +55,17 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr
Match.exhaustive, Match.exhaustive,
) )
), ),
f: ([todo, form]) => Match.value(props).pipe( onSubmit: function(todo) {
return Match.value(props).pipe(
Match.tag("new", () => Ref.update(state.ref, Chunk.prepend(todo)).pipe( Match.tag("new", () => Ref.update(state.ref, Chunk.prepend(todo)).pipe(
Effect.andThen(makeTodo), Effect.andThen(makeTodo),
Effect.andThen(Schema.encode(TodoFormSchema)), Effect.andThen(Schema.encode(TodoFormSchema)),
Effect.andThen(v => Ref.set(form.encodedValue, v)), Effect.andThen(v => Ref.set(this.encodedValueRef, v)),
)), )),
Match.tag("edit", ({ id }) => Ref.set(state.getElementRef(id), todo)), Match.tag("edit", ({ id }) => Ref.set(state.getElementRef(id), todo)),
Match.exhaustive, Match.exhaustive,
), )
},
autosubmit: props._tag === "edit", autosubmit: props._tag === "edit",
debounce: "250 millis", debounce: "250 millis",
}) })
@@ -70,19 +73,13 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr
return [ return [
indexRef, indexRef,
form, form,
yield* form.field(["content"]), Form.field(form, ["content"]),
yield* form.field(["completedAt"]), Form.field(form, ["completedAt"]),
] as const ] as const
}), [props._tag, props._tag === "edit" ? props.id : undefined]) }), [props._tag, props._tag === "edit" ? props.id : undefined])
const [index, size, canSubmit] = yield* Subscribable.useSubscribables([ const [index, size, canSubmit] = yield* Subscribable.useSubscribables(indexRef, state.sizeSubscribable, form.canSubmitSubscribable)
indexRef, const submit = yield* Form.useSubmit(form)
state.sizeSubscribable,
form.canSubmit,
])
const runSync = yield* Component.useRunSync()
const runPromise = yield* Component.useRunPromise<DateTime.CurrentTimeZone>()
const TextFieldFormInputFC = yield* TextFieldFormInput const TextFieldFormInputFC = yield* TextFieldFormInput
@@ -101,7 +98,7 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr
/> />
{props._tag === "new" && {props._tag === "new" &&
<Button disabled={!canSubmit} onClick={() => void runPromise(form.submit)}> <Button disabled={!canSubmit} onClick={() => submit()}>
Add Add
</Button> </Button>
} }
@@ -113,19 +110,19 @@ export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoPr
<Flex direction="column" justify="center" align="center" gap="1"> <Flex direction="column" justify="center" align="center" gap="1">
<IconButton <IconButton
disabled={index <= 0} disabled={index <= 0}
onClick={() => runSync(state.moveLeft(props.id))} onClick={() => Runtime.runSync(runtime)(state.moveLeft(props.id))}
> >
<FaArrowUp /> <FaArrowUp />
</IconButton> </IconButton>
<IconButton <IconButton
disabled={index >= size - 1} disabled={index >= size - 1}
onClick={() => runSync(state.moveRight(props.id))} onClick={() => Runtime.runSync(runtime)(state.moveRight(props.id))}
> >
<FaArrowDown /> <FaArrowDown />
</IconButton> </IconButton>
<IconButton onClick={() => runSync(state.remove(props.id))}> <IconButton onClick={() => Runtime.runSync(runtime)(state.remove(props.id))}>
<FaDeleteLeft /> <FaDeleteLeft />
</IconButton> </IconButton>
</Flex> </Flex>

View File

@@ -7,7 +7,7 @@ import { TodosState } from "./TodosState.service"
export class Todos extends Component.makeUntraced("Todos")(function*() { export class Todos extends Component.makeUntraced("Todos")(function*() {
const state = yield* TodosState const state = yield* TodosState
const [todos] = yield* Subscribable.useSubscribables([state.ref]) const [todos] = yield* Subscribable.useSubscribables(state.ref)
yield* Component.useOnMount(() => Effect.andThen( yield* Component.useOnMount(() => Effect.andThen(
Console.log("Todos mounted"), Console.log("Todos mounted"),