diff --git a/.gitea/workflows/lint.yaml b/.gitea/workflows/lint.yaml index c13cd5d..0a3d7b6 100644 --- a/.gitea/workflows/lint.yaml +++ b/.gitea/workflows/lint.yaml @@ -16,3 +16,5 @@ jobs: run: bun lint:tsc - name: Lint Biome run: bun lint:biome + - name: Test + run: bun run test diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml index f20291c..4154609 100644 --- a/.gitea/workflows/publish.yaml +++ b/.gitea/workflows/publish.yaml @@ -11,14 +11,26 @@ jobs: steps: - name: Setup Bun uses: oven-sh/setup-bun@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to Container Registry + uses: docker/login-action@v3 + with: + registry: docker.valverde.cloud + username: ${{ secrets.DOCKER_REGISTRY_USERNAME }} + password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} + - name: Clone repo uses: actions/checkout@v6 - name: Install dependencies run: bun install --frozen-lockfile + - name: Lint TypeScript run: bun lint:tsc - name: Lint Biome run: bun lint:biome + - name: Test + run: bun run test - name: Build run: bun run build - name: Publish effect-fc @@ -28,3 +40,30 @@ jobs: access: public token: ${{ secrets.NPM_TOKEN }} registry: https://registry.npmjs.org + + - name: Clean before Docker build + run: | + bun clean:cache + bun clean:dist + bun clean:modules + - name: Generate Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: | + docker.valverde.cloud/${{ gitea.repository }} + tags: | + type=ref,event=branch + type=ref,event=tag + type=ref,event=pr + type=sha + flavor: | + latest=true + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.gitea/workflows/test-build.yaml b/.gitea/workflows/test-build.yaml index 729eb00..87f6c74 100644 --- a/.gitea/workflows/test-build.yaml +++ b/.gitea/workflows/test-build.yaml @@ -12,16 +12,49 @@ jobs: - name: Setup Node uses: actions/setup-node@v6 with: - node-version: "24" + node-version: "22" + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Clone repo uses: actions/checkout@v6 - name: Install dependencies run: bun install --frozen-lockfile + - name: Lint TypeScript run: bun lint:tsc - name: Lint Biome run: bun lint:biome + - name: Test + run: bun run test - name: Build run: bun run build - name: Pack run: bun pack + + - name: Clean before Docker build + run: | + bun clean:cache + bun clean:dist + bun clean:modules + - name: Generate Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: | + docker.valverde.cloud/${{ gitea.repository }} + tags: | + type=ref,event=branch + type=ref,event=tag + type=ref,event=pr + type=sha + flavor: | + latest=true + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: false + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6dac0e3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM oven/bun:1.3.12-debian@sha256:1b709c9dd883fc1af38c210f7ea5222c552a8d470ea73efbd4b8fcfee798a64b AS bun + +FROM node:22.21.1-trixie-slim@sha256:98e1429d1a0b99378b4de43fa385f0746fd6276faf4feeb6104d91f6bad290f9 +COPY --from=bun /usr/local/bin/bun /usr/local/bin/bunx /usr/local/bin/ +COPY . /app +WORKDIR /app + +RUN bun install --frozen-lockfile && \ + bun run build && \ + bun clean:cache && \ + bun clean:modules && \ + bun install --production --frozen-lockfile diff --git a/EFFECT_FC_NEXT_ERROR_HANDLING_REPORT.md b/EFFECT_FC_NEXT_ERROR_HANDLING_REPORT.md new file mode 100644 index 0000000..246b1a5 --- /dev/null +++ b/EFFECT_FC_NEXT_ERROR_HANDLING_REPORT.md @@ -0,0 +1,175 @@ +# Effect FC Next error-handling review + +## Verdict + +`ErrorObserver` is a reasonable *opt-in failure notification bus*, but it is +not an application error handler. It neither recovers from errors nor, in +`effect-fc-next`, observes the application's effects by default. Keeping it +as the central error-handling mechanism would make error delivery implicit, +incomplete, and easy to duplicate. + +The better model is: + +1. Handle expected, typed failures where the operation is rendered or invoked. +2. Report unhandled/background failures through one explicit runtime boundary. +3. Let React error boundaries render defects and render-time failures. + +In particular, queries, mutations, and forms should keep their current +`AsyncResult`/validation state as the user-facing error path; a global service +should not replace that state. + +## What exists today + +`packages/effect-fc-next/src/ErrorObserver.ts` provides a context service +backed by an unbounded `PubSub>`: + +- `handle(effect)` uses `Effect.tapCause` to publish every non-successful + cause, then preserves the original result; +- `subscribe` exposes a scoped subscription; +- module-level `handle(effect)` is a no-op when the service is absent. + +This is narrower than the similarly named service in the legacy +`packages/effect-fc` package. The legacy default runtime layer installs an +Effect supervisor that attempts to publish every failed fiber. The Next +runtime's `preludeLayer` contains only `Component.ScopeMap`; it does not +install `ErrorObserver.layer`. There are also no `ErrorObserver.handle(...)` +call sites in `effect-fc-next`. + +Therefore, as checked at this revision, a consumer can create and subscribe to +the service manually, but no failure is automatically delivered to it. It is +not currently an app-wide error mechanism. + +## What is good about the pattern + +- It keeps the original failure intact. Observability does not accidentally + turn a failing effect into a successful one. +- It publishes `Cause`, not only `E`, so defects, interruption, parallel + failures, and traces are not discarded. +- The service is optional, which is useful for a library: applications that do + not want reporting do not need to install a logger/telemetry dependency. +- A scoped subscription has the right basic lifetime shape for a React + component or a root-level reporting worker. + +## Main issues + +### It is opt-in at every execution site + +Wrapping effects with `ErrorObserver.handle` is both easy to forget and +ambiguous. It does not cover failures from `Component.useCallbackPromise`, +`Async.async`, `useReactEffect`, or a fork unless each path explicitly wraps +the relevant effect. Conversely, adding wrappers at multiple levels reports +the same failure more than once. + +### Its type promise is unsound + +`handle` accepts any `E1` then casts its `Cause` to +`Cause`. A value retrieved as `ErrorObserver` can receive a +`ValidationError` or a defect. `Cause` is correctly broader than a single +app-error type, but the generic parameter suggests filtering that the service +does not perform. + +### "Error" and "handle" blur distinct responsibilities + +The code only observes/reports failures; it does not decide a fallback, show a +toast, retry, recover, log, or rethrow. Calling it a handler encourages using +a global side channel for errors that should remain part of local UI state. + +### An unbounded, raw pub/sub is a risky public policy + +A slow or absent subscriber can retain an unbounded backlog. Consumers must +also inspect every `Cause`, decide whether interruption is meaningful, dedupe +retries, redact data, and ensure their own reporting failure does not affect +the application. Those are application policy choices, not library defaults. + +### It is not a React error boundary + +React error boundaries cover render/lifecycle errors in the React tree. They +do not replace reporting of failures from detached/background Effect fibers, +and an Effect failure should not be blindly thrown into render merely to reach +one. These are complementary boundaries. + +## Recommended replacement + +Replace the public observer with a small **`FailureReporter`** service. Make +reporting explicit at the handful of Effect-to-JavaScript runtime boundaries, +not at every business effect. + +```ts +interface FailureReporter { + readonly report: (event: FailureEvent) => Effect.Effect +} + +interface FailureEvent { + readonly cause: Cause.Cause + readonly source: "event" | "effect" | "async-component" | "background" + readonly componentName?: string + readonly operation?: string +} +``` + +The default implementation should be a no-op. Application layers can add +logging, Sentry/OpenTelemetry, a toast dispatcher, or a bounded in-memory +development sink. `report` should be made best-effort at the boundary +(`Effect.ignore`/equivalent after recording its own diagnostics) so reporting +outages never replace the original failure. + +Provide one internal combinator, for example `reportFailure(effect, metadata)`, +which reports only a non-interruption failure and then re-fails with exactly +the original cause. Use it in these adapters: + +- `Component.useCallbackPromise` and any promise-returning event callback; +- `Component.useReactEffect` / layout-effect execution; +- `Async.async` before the promise is handed to React; +- library-created detached fibers whose failures are not represented in an + `AsyncResult`. + +Do **not** use it for query/mutation/form operations whose failure is already +captured and displayed in `AsyncResult`; report only when the caller abandons +or explicitly escalates that result. This avoids a failed request producing a +toast/log and an inline error merely because it was expected. + +At the application root, pair this with a normal React `ErrorBoundary` that +reports render defects and presents the recovery UI. Keep its reporting +separate from the Effect service; optionally normalize both into the same +application telemetry event schema. + +## Lower-risk incremental path + +If replacing the API now is too disruptive: + +1. Do not add `ErrorObserver.layer` to the Next prelude merely to make it look + global. A hidden global bus still has unclear coverage and duplicate-event + semantics. +2. Rename `handle` to `observeFailure` and document that it is an explicit + notification wrapper, not recovery or global supervision. +3. Remove the generic `E`, or expose `Cause.Cause`; alternatively + accept a predicate/decoder that actually filters before publication. +4. Make the queue policy explicit: preferably no public queue, or a bounded, + dropping development event sink with a dropped-event counter. +5. Add tests for: preservation of the original exit, defects, interruption + filtering, a failing reporter, duplicate wrapping, and teardown of a scoped + subscriber. + +## Names + +`ErrorHandler` is inaccurate, and `ErrorObserver` is acceptable only for the +current low-level notification primitive. Recommended names by role: + +| Role | Recommended name | Why | +| --- | --- | --- | +| Application service that sends telemetry/logs | `FailureReporter` | Says it reports an Effect failure without claiming recovery. | +| Wrapper combinator | `reportFailure` | Describes the side effect and retains the original failure. | +| Optional stream-like dev/testing primitive | `FailureEvents` or `FailureEventBus` | Makes the pub/sub nature explicit. | +| React UI component | `AppErrorBoundary` | Uses React's established boundary terminology. | + +I would use **`FailureReporter`** for the replacement. "Failure" is more +accurate than "error" in Effect because it can intentionally retain the full +`Cause`, while "reporter" makes the non-recovery responsibility clear. + +## Decision + +Treat `ErrorObserver` as an experimental diagnostic primitive, not the app +error architecture. Design expected errors into local state, add a +best-effort `FailureReporter` at the few execution boundaries, and use a React +error boundary for render failures. This gives complete, testable coverage +without turning every domain failure into a global event. diff --git a/EFFECT_REACT_LIFECYCLE_REPORT.md b/EFFECT_REACT_LIFECYCLE_REPORT.md new file mode 100644 index 0000000..216c7f0 --- /dev/null +++ b/EFFECT_REACT_LIFECYCLE_REPORT.md @@ -0,0 +1,484 @@ +# Effect–React Render Lifecycle Report + +## Purpose + +This report describes the lifecycle problem in `effect-fc-next`, why abandoned React renders leak Effect scopes, what the experimental implementations attempted, why those implementations are not satisfactory, and how a robust system should be designed. + +The experimental implementation discussed here has been removed from the source tree. This document is intended as design material for a clean reimplementation. + +## Executive summary + +The fundamental problem is not scope disposal by itself. It is that `effect-fc-next` performs Effect work and creates resource scopes while React is rendering. + +React distinguishes between two broad phases: + +1. **Render:** React evaluates components and builds a prospective tree. React may retry, pause, duplicate, or permanently abandon this work. +2. **Commit:** React accepts a rendered tree and runs layout and passive effects. Cleanup callbacks only exist for work that reached this phase. + +The existing `Component.useScope` creates and registers an Effect scope during render, but installs its cleanup from `React.useEffect`. If React abandons the render, the effect is never mounted, its cleanup is never installed, and the render-created scope remains registered indefinitely. + +There is no public React callback for “this render attempt was abandoned.” Consequently, an object created only for a render attempt cannot receive deterministic abandonment notification. + +A correct architecture must therefore choose one of these models: + +- Do not acquire resources until commit. +- Store render-time resources in an external registry under an explicit, stable identity. +- Treat render-time resources as speculative cached entries and garbage-collect idle entries, while ensuring an expired entry can always be recreated safely. + +The first model is simplest. The second is the model used by atom/resource systems. The third is necessarily a cache/TTL design rather than exact component-lifecycle tracking. + +## The original `useScope` lifecycle + +The implementation in `Component.ts` performs approximately the following work: + +```ts +function useScope(dependencies) { + const { key, scope } = React.useMemo(() => { + const key = makeIdentity() + const scope = makeEffectScope() + scopeMap.set(key, { scope, closeFiber: none() }) + + return { key, scope } + }, dependencies) + + React.useEffect(() => { + cancelPreviouslyScheduledClose(key) + + return () => { + const closeFiber = sleep(debounce).andThen(close(scope)).fork() + scopeMap.set(key, { scope, closeFiber: some(closeFiber) }) + } + }, [key]) + + return scope +} +``` + +The intended committed lifecycle is: + +```text +render + create scope + insert scope into ScopeMap + +commit + run useEffect setup + cancel any pending close left by a rapid remount + +unmount or dependency change + run useEffect cleanup + wait for the debounce + close the scope + remove it from ScopeMap +``` + +For an ordinary committed component, this works. The debounce also bridges React Strict Mode’s development-only effect cycle: + +```text +effect setup +effect cleanup schedules close +effect setup again cancels close +``` + +The failing lifecycle is: + +```text +render + create scope + insert scope into ScopeMap + +React abandons render + useEffect setup never runs + useEffect cleanup therefore never exists + no close is scheduled + ScopeMap retains the scope forever +``` + +Suspense can trigger this by throwing a promise before the component commits. Concurrent rendering and failed/erroring renders can produce the same category of problem. + +## Why React cannot directly report abandonment + +Hooks such as `useEffect` and `useLayoutEffect` describe the lifetime of a committed component. They are deliberately not executed for render work that never commits. + +Render-time hook state does not solve this: + +- `useMemo` may be discarded with the render attempt. +- `useRef` belongs to the same provisional fiber state. +- `useState` belongs to the same provisional fiber state. +- Cleanup returned from `useEffect` only exists after effect setup has run. +- A component cannot read its React `key`; React consumes it before props reach the component. + +JavaScript garbage collection is also insufficient. `FinalizationRegistry` is nondeterministic and cannot be used to guarantee timely execution of Effect finalizers. + +This means there is no reliable per-render-attempt destructor available to application code. + +## Why Effect Atom can use an external lifecycle + +Effect Atom has something a component scope does not: an atom is an explicit object with stable identity outside React. + +The conceptual flow is: + +```text +React receives an Atom object + │ + ▼ +AtomRegistry.getOrCreate(atom) + │ + ├── returns an existing external node + └── or creates a new external node and schedules idle removal + +React commit subscribes to the node + │ + └── subscription prevents idle removal + +React unmount unsubscribes + │ + └── node becomes eligible for removal +``` + +If a render is abandoned, no subscription is established. The node is still owned by the external registry and can remove itself when idle. If React retries later, it asks the registry for the atom again. The registry either returns the still-live node or creates a replacement. + +`useSyncExternalStore` belongs naturally in this design because an atom node has a changing snapshot. React must both subscribe to changes and read a consistent value. + +A component scope does not naturally have either property: + +- It has no explicit identity external to React. +- Its scope object is not a changing UI snapshot. + +Therefore, copying the Atom mechanism without first solving identity produces abstractions that look like an external store but are actually render-attempt bookkeeping. + +## The experimental external-store implementation + +The first experiment introduced three concepts: + +- A runtime-owned registry. +- A render-owned store/handle created with `useMemo`. +- A registry entry containing the Effect scope and its cleanup state. + +It used `useSyncExternalStore` as follows: + +```text +getSnapshot during render + create a scope entry + register it externally + immediately schedule idle cleanup + +subscribe during commit + retain the entry + cancel idle cleanup + +unsubscribe during unmount + release the entry + schedule cleanup +``` + +This fixed the abandoned-render leak because an uncommitted entry had no subscriber and its initial cleanup remained scheduled. + +It also allowed a closed snapshot to be replaced: if cleanup won a race before subscription, a later `getSnapshot` could create another entry. + +However, it had several design problems: + +1. The “store” was created by `useMemo`, so it was not truly an externally identified store. +2. `useSyncExternalStore` was being used primarily as a commit/unmount detector rather than for observable state. +3. The names “store,” “entry,” and “snapshot” obscured the resource lifecycle. +4. It introduced listener notification machinery even though a scope has no meaningful changing value for the UI. +5. It gave the appearance of Atom’s semantics without possessing Atom’s stable external identity. + +It was functional as a self-healing speculative cache, but it was not a clean model for a component instance. + +## The experimental retain/release implementation + +The second experiment removed `useSyncExternalStore` and represented the lifecycle directly: + +```ts +const registration = React.useMemo( + () => scopeMap.register(context, options), + dependencies, +) + +React.useLayoutEffect(() => { + registration.retain() + return registration.release +}, [registration]) + +return registration.scope +``` + +Registration immediately scheduled its own close. A committed layout effect cancelled that close through `retain()`. Unmount called `release()` and scheduled it again. + +This was much easier to understand: + +```text +registration created → provisional +layout effect setup → retained +layout effect cleanup → released +idle timeout → closed +``` + +It still had a serious race: + +```text +render creates provisional registration +React delays commit longer than the cleanup debounce +registration closes +React eventually commits the same render +layout effect calls retain on an already-closed registration +component now holds a closed Effect scope +``` + +The external-store version could recover by returning a new snapshot. The direct retain/release version could not trigger a render-time replacement after the scope had closed. + +Increasing the timeout reduces the likelihood but does not make the system correct. A timeout cannot prove that React has abandoned work. + +## What the bookkeeping in the experiment was doing + +The experimental implementation contained more machinery than the conceptual model suggested. Each part existed for a specific race: + +### Runtime registry + +The registry retained every scope that might still need disposal. It also allowed `ReactRuntime` disposal to close every remaining scope. + +A `HashMap` and `Ref` were used, but neither is essential for a synchronous JavaScript registry. A `Set` would express the ownership more clearly unless atomic Effect composition is specifically required. + +### Unique registration key + +Each speculative render needed a separate map entry. Otherwise two simultaneous attempts could overwrite or close one another. + +### Cleanup fiber + +The fiber represented the debounce period followed by scope closure. Retaining the registration interrupted this fiber. + +### Cleanup generation + +Interrupting an Effect fiber is not equivalent to synchronously erasing every continuation it may execute. Consider: + +```text +cleanup A is running +retain interrupts cleanup A +release schedules cleanup B +cleanup A's ensuring handler finishes afterward +``` + +If cleanup A blindly clears the `closeFiber` field, it erases the reference to cleanup B. A monotonically increasing generation lets a finalizer clear the field only if it still represents the current scheduled close. + +### Retain count + +A count allows repeated retain/release pairs, including Strict Mode effect simulation, without closing while at least one committed lease remains. A boolean is sufficient only if the code can prove that setup and cleanup are perfectly paired and never nested. + +These details are legitimate in a speculative cache, but they should be encapsulated behind a much smaller domain model. + +## The identity problem + +An external registry needs a key that means “this logical resource.” Possible candidates all have limitations: + +### Component definition + +Using the `Component` object would make every mounted instance of the same component share one scope. That breaks per-instance mount state and cleanup. + +### Props or dependency values + +Two component instances can have equal props while requiring independent scopes. Object props may also be recreated on every render. + +### `useId` + +`useId` is intended for accessibility and hydration identifiers, not general cache identity. Concurrent versions of the same logical component can receive the same identifier, and uniqueness across multiple roots depends on root configuration. It should not silently become a resource-ownership contract. + +### React `key` + +This would be conceptually useful, but React does not expose it to the component. Requiring a separate explicit resource key would be an API change. + +### A value made by `useMemo`, `useRef`, or `useState` + +These values identify a React fiber lifetime only after React preserves that hook state. They do not survive an abandoned initial render and therefore cannot provide Atom-style external identity. + +The clean external design consequently requires an explicit identity supplied by the application or created outside the speculative render. + +## Recommended architecture + +The API should distinguish committed lifecycle work from render-time resources instead of trying to give them identical semantics. + +### 1. Commit-only component scopes + +Use this model for resources that do not need to affect the current render synchronously. + +```ts +function useCommittedScope(options): ScopeState { + const [scope, setScope] = React.useState() + + React.useLayoutEffect(() => { + const scope = makeScope(options) + setScope(scope) + + return () => runClose(scope) + }, dependencies) + + return scope +} +``` + +The exact API need not use state, but the invariant should be: + +> No resource is acquired until React commits the component. + +An abandoned render then has nothing to clean up. + +This may require changing APIs that currently expect acquisition results during the same render. Such APIs cannot be made commit-only without representing an uninitialized/loading state or causing a subsequent render. + +### 2. Explicit external resources for Suspense + +Use this model when rendering depends on asynchronous acquisition or a promise. + +```ts +interface ResourceKey { + readonly id: string +} + +interface ResourceNode { + readonly read: () => A + readonly subscribe: (listener: () => void) => () => void +} + +const node = resourceRegistry.getOrCreate(key, createResource) +const value = React.useSyncExternalStore(node.subscribe, node.read, node.read) +``` + +Here `useSyncExternalStore` is justified because the node is truly external, has a stable explicit key, and has a changing observable result. + +The node lifecycle should be: + +```text +absent + │ getOrCreate + ▼ +idle/pending ── subscribe ──► retained + ▲ │ + └──── unsubscribe ──────────┘ + │ + └── idle TTL expires ──► disposed and removed +``` + +If a node expires before a retry, `getOrCreate` constructs a new node. No React render can remain permanently bound to an expired object without revalidating it. + +### 3. Make `useOnMount` semantics explicit + +The name `useOnMount` suggests commit-time execution, but if its Effect is evaluated from `useMemo` during render, it is actually speculative render-time execution. + +The library should choose and document one of these contracts: + +- `useOnMount` runs only after commit and cannot synchronously return an acquisition result during the initial render. +- A separate render-safe primitive accepts only pure/synchronous computation. +- A resource primitive uses an explicit external resource key and supports Suspense. + +Allowing arbitrary scoped Effects to execute during render while promising exact component cleanup is the combination that creates the unsolvable abandonment problem. + +## Required invariants for an external resource registry + +If an Atom-style registry is implemented, it should satisfy all of the following: + +1. **Stable identity:** Every node is addressed by an explicit resource key independent of React hook state. +2. **Idempotent lookup:** Repeated reads of the same key return the same live node. +3. **Recoverable expiry:** A lookup after disposal returns a new live node, never the disposed node. +4. **Commit retention:** A committed subscriber prevents idle disposal. +5. **Abandoned-render collection:** A node read by an abandoned render has no subscriber and becomes eligible for disposal. +6. **Reference-counted ownership:** One unmount cannot dispose a node still used by another subscriber. +7. **Idempotent disposal:** Closing a node multiple times has the same result as closing it once. +8. **Registry disposal:** Disposing the runtime closes every node regardless of subscriber state. +9. **Generation safety:** Completion of an older cleanup task cannot overwrite or cancel newer lifecycle state. +10. **Consistent snapshot:** React must never receive a closed node as the current live snapshot. + +## Required test matrix + +A replacement should be tested against lifecycle sequences, not only final rendered output. + +### Normal lifecycle + +- Initial commit acquires exactly the intended resources. +- Rerender with equivalent dependencies does not reacquire. +- Dependency change releases the old resource and acquires the new one. +- Unmount runs every finalizer once. + +### Strict Mode + +- Development render duplication does not leak the discarded attempt. +- Effect setup/cleanup/setup simulation does not prematurely close the committed resource. +- Final unmount closes all remaining resources. + +### Suspense + +- A render that suspends forever does not retain resources indefinitely. +- A suspended render that retries can obtain a live resource after any idle cleanup. +- Resolving an obsolete promise cannot mutate or resurrect a newer node. +- Changing props while pending disposes or detaches the obsolete computation. + +### Concurrent replacement + +- The current committed tree remains usable while a replacement tree renders. +- Abandoning the replacement does not affect the current tree. +- Committing the replacement releases the previous tree only after the replacement commits. + +### Runtime disposal + +- Disposing `ReactRuntime` closes committed resources. +- It also closes idle, pending, and speculative registry nodes. +- Pending async fibers are interrupted without unhandled promise rejections. + +### Timing races + +- Retain racing with scheduled disposal has a deterministic winner. +- Disposal racing with retry either preserves the live node or forces recreation. +- An old cleanup task cannot clear the handle for a newer cleanup task. + +## Suggested minimal domain model + +For a real external resource cache, the implementation can remain small if the names match the responsibilities: + +```ts +interface ResourceRegistry { + getOrCreate(key: ResourceKey, create: () => ResourceNode): ResourceNode + dispose: Effect.Effect +} + +interface ResourceNode { + readonly key: ResourceKey + readonly read: () => A + readonly subscribe: (listener: () => void) => () => void + readonly dispose: Effect.Effect +} +``` + +Internally, a node can own: + +- Its Effect scope. +- Its current result or promise. +- Its subscribers. +- Its idle cleanup task. +- Its lifecycle generation. + +There should not be a separate render-owned object called a “store.” React should interact directly with the externally owned node. + +For commit-only scopes, the model is even smaller: + +```ts +interface ComponentScope { + readonly scope: Scope.Closeable + readonly close: Effect.Effect +} +``` + +Create it at commit and close it at effect cleanup. No registry, snapshot, subscription, speculative timer, or abandonment recovery is necessary unless runtime-wide disposal must independently own it. + +## Final recommendation for `effect-fc-next` + +Do not attempt to hide both committed component lifecycles and render-time Suspense resources behind one implicit `Scope` mechanism. + +The most defensible direction is: + +1. Make normal component acquisition commit-driven. +2. Prevent or clearly label arbitrary Effect acquisition during render. +3. Introduce a separate external resource abstraction for async/Suspense work. +4. Require that abstraction to have an explicit stable key. +5. Use `useSyncExternalStore` only for those externally owned nodes whose snapshots can change. +6. Treat idle timeout as cache eviction, not as proof that React abandoned a render. +7. Make every read capable of replacing an expired node. + +If backward compatibility requires speculative per-render scopes, document that the debounce is heuristic and retain the recovery behavior that can replace a scope which expires before commit. That model can prevent leaks, but it should not be presented as exact React component-instance lifecycle tracking. diff --git a/REACT_REFRESH_FEASIBILITY.md b/REACT_REFRESH_FEASIBILITY.md new file mode 100644 index 0000000..641e754 --- /dev/null +++ b/REACT_REFRESH_FEASIBILITY.md @@ -0,0 +1,335 @@ +# React Fast Refresh for Effect View components + +Date: 2026-07-22 + +## Executive summary + +Implementing Fast Refresh for Effect View components is feasible, but it is not a one-line change to React Refresh's component detection. + +The current API has two identities: + +1. `Component.make` / `Component.makeUntraced` creates an Effect View descriptor. +2. `.use` later synthesizes the React function component that is actually mounted. + +Vite's React Refresh transform sees the descriptor definition, while React reconciles the synthesized function. In addition, `.use` deliberately caches that function. A newly evaluated module therefore creates a new descriptor, but the mounted function continues to close over the old descriptor. + +The recommended implementation is a bundler-neutral development refresh protocol in Effect View plus a Vite compiler adapter. The plugin should assign stable source IDs and hook signatures to Effect View definitions. The main library's protocol should retain the current descriptor, notify mounted instances after an update, preserve state when the signature is compatible, and remount when it is not. The Vite adapter should retain those cells in `import.meta.hot.data` and manage accept/invalidate behavior. + +My feasibility assessment is: + +- **Safe refresh with remount on every edit:** high confidence, moderate effort. +- **State-preserving refresh with React-like hook signature handling:** high confidence, moderate-to-high effort. +- **A runtime-only or export-detection-only fix:** not sufficient. +- **Bundler-independent support in the first release:** not recommended; establish the protocol with Vite first. + +A production-quality Vite implementation is likely **10–18 engineer-days**, including the runtime bridge, transform, lifecycle tests, examples, and documentation. A remounting proof of concept should take **2–4 days**. + +## Scope examined + +The implementation target is `effect-fc-next` (Effect 4 beta), which is +expected to become `effect-view`. The legacy `effect-fc` package is not +supported by the Vite plugin. + +## How Effect View rendering works today + +`Component.make` creates a function-shaped descriptor with a `body` property and `ComponentPrototype`; it does not create the React component that will be mounted. See [`packages/effect-fc-next/src/Component.ts`](packages/effect-fc-next/src/Component.ts), around `make`, `makeUntraced`, and `ComponentImplPrototype`. + +The relevant path is: + +```text +source definition + -> Effect View descriptor (`body`, options, prototype traits) + -> `.use` + -> synthesized React function bound to an Effect runtime/context + -> optional `React.memo` / async transformation + -> mounted React fiber +``` + +In `effect-fc-next`, `asFunctionComponent` creates a closure over the descriptor +and Effect context. `.use` retains that synthesized function in `componentRef` +while the relevant Effect service identities remain unchanged, and +`withContext` renders the function returned by `.use`. + +This caching is useful during ordinary rendering: without it, React would see a new component type and remount on every parent render. It is also why a newly evaluated module cannot replace the mounted implementation by itself. + +## What the current Vite transform does + +I inspected Vite's development transform for representative files with the repository's actual configuration and dependency versions. + +For a class definition such as `TodosView`, the transform produced the equivalent of: + +```js +var _s = $RefreshSig$() +export class TodosView extends _s( + Component.make("TodosView")( + _s(function* () { + _s() + // component body + }, "", false, () => [ + Subscribable.useAll, + Component.useOnMount, + ]) + ), + "", + false, + () => [Subscribable.useAll, Component.useOnMount], +) {} +``` + +The transform recognizes hook-shaped calls and calculates a signature, but it emits no `$RefreshReg$` call and no refresh boundary for the Effect View. The same was true for `const` definitions created with `Component.make` and for route components ending in `.pipe(Component.withRuntime(...))`. + +This happens because `Component.make(...)` and Effect's `pipe(...)` are not React component patterns known to the transform. Class-style Effect Views also inherit from a non-React base, so React Refresh's runtime heuristic deliberately does not classify them as React classes. + +Even if export registration were forced, registering the descriptor would not be enough. The descriptor is not the type stored in the mounted React fiber; the lazily synthesized function is. + +Consequently, edits currently propagate through ordinary Vite HMR invalidation. Whether they eventually update through an importer or cause a page reload depends on the surrounding module graph and router integration, but React Refresh cannot directly reconcile the edited Effect View family. + +## Runtime experiment + +The initial feasibility study used the legacy implementation for a focused +jsdom/React identity experiment. Its descriptor-caching result also applies to +`effect-fc-next`, but the legacy package is not an implementation target: + +1. Render an Effect View containing `React.useState(0)`. +2. Increment it to `old:1`. +3. Create a replacement descriptor with a body rendering `new:`. +4. Rerender the existing entry component. +5. Copy the replacement `body` onto the descriptor retained by the mounted component and rerender again. + +Observed output: + +```text +after local state update: old:1 +new descriptor, old mounted entry: old:1 +mutated descriptor, stable entry: new:1 +``` + +This proves two things: + +- Module reevaluation alone cannot update a mounted Effect View because its synthesized function retained the old descriptor. +- Updating the retained implementation and scheduling a render can apply new code while preserving React state. + +The experiment was temporary and left no probe files in the repository. + +## Required semantics + +A complete implementation should provide the same safety contract developers expect from Fast Refresh: + +- Apply edits without reloading the page. +- Preserve React state when the hook signature is compatible. +- Remount when hooks are added, removed, reordered, or otherwise become incompatible. +- Recover after a syntax or render error. +- Support both `const` and class definition styles. +- Support local/non-exported child Views, not only module exports. +- Support `make`, `makeUntraced`, `withOptions`, `Memoized.memoized`, async traits, and `withRuntime` / `withContext` entrypoints. +- Work when one View is materialized under multiple Effect service contexts. +- Preserve Effect scopes on compatible edits and close them exactly once on a reset/remount. +- Offer an explicit reset escape hatch equivalent to a refresh-reset directive. + +## Recommended design + +### 1. Add an Effect View refresh transform + +Ship a Vite plugin, `@effect-view/vite-plugin`, placed before `react()`: + +```ts +plugins: [ + effectViewPlugin(), + react(), +] +``` + +It should recognize: + +- `Component.make(...)` +- `Component.makeUntraced(...)` +- class declarations extending either factory result +- definitions followed by Effect `pipe` transformations +- aliased imports from `effect-fc-next` + +For each definition it should inject development-only metadata containing: + +- A stable ID based on normalized module path plus local binding. +- A hook signature derived from the generator/body. +- The HMR context or a small generated accept handler. +- Optional reset metadata. + +Detection must be binding-aware rather than matching text. Otherwise unrelated `Component.make` functions, renamed imports, and namespace aliases will cause false positives or missed Views. + +The plugin must instrument local Views as well as exports. React Refresh works on component families, not only refresh-boundary exports, and most nested Views in this repository are consumed through `.use`. + +### 2. Add a development-only hot cell protocol to Effect View + +The main library should expose the bundler-neutral cell contract from its `Refreshable` module and the component shell should consume it directly: + +```ts +interface HotViewCell { + current: Component.Any + revision: number + resetRevision: number + signature: string + subscribe(listener: () => void): () => void +} +``` + +On module reevaluation, the new descriptor updates `cell.current`. If the signature is unchanged, `revision` changes. If the signature changes, `resetRevision` changes as well. + +Keeping the cell rather than only mutating the old descriptor is important for class inheritance and traits. Class-style Views inherit `body` and options through the generated base class, while memoized and async Views alter prototype behavior. A cell can point to the complete new descriptor without attempting to copy an unknown prototype graph onto the old one. + +Bundler integrations should depend on this public protocol rather than define a structurally duplicated symbol and cell. The Vite adapter owns only Vite-specific storage in `import.meta.hot.data`, registration IDs, and accept/invalidate decisions. + +### 3. Split the development component into a stable shell and keyed implementation + +In development, the function materialized by `.use` should become a stable shell: + +```text +stable shell + -> subscribes to HotViewCell + -> reads current descriptor and resetRevision + -> renders keyed implementation + -> runs useScope + -> runs the current Effect View body + -> owns the View's React hooks and Effect resources +``` + +On a compatible edit, the cell subscription rerenders the shell and the implementation keeps the same type/key, preserving state. On an incompatible edit, the key changes and React remounts the implementation safely. + +This extra fiber and subscription should exist only in development builds. The production path can remain unchanged. + +This design avoids depending on React Refresh's private family maps. It can coexist with the normal Vite React plugin, which remains responsible for standard React components and the error overlay. The Effect View plugin self-accepts only the modules it successfully instruments; unsupported patterns should fall back to normal HMR invalidation rather than accepting an update it cannot apply. + +### 4. Reuse or reproduce hook signatures carefully + +This is the hardest part of state-preserving support. + +The current Vite/OXC transform already sees calls such as `React.useState`, `Component.useOnMount`, and `Subscribable.useAll`, but its computed signature is attached to the descriptor expression rather than the lazily created React function. There is no public runtime API for reading that signature back. + +The robust choices are: + +1. Run a small binding-aware AST pass that computes Effect View hook signatures and feeds them to the hot cell. +2. Integrate with a public transform hook if Vite/React exposes one in a future version. + +Parsing generated OXC text to steal `_s(...)` arguments would be brittle and is not recommended. + +An MVP may conservatively remount on every edit. The next step can preserve state only when the plugin can prove that the ordered hook signature is unchanged. False negatives cost state; false positives can violate the Rules of Hooks, so the algorithm must favor remounting. + +The signature pass should cover: + +- Direct React hooks. +- Effect View hooks named `useX` even when used through `yield*`. +- Imported custom hooks and their identities where possible. +- Hooks introduced by traits such as async rendering. +- An explicit force-reset directive. + +### 5. Keep Effect lifecycle behavior explicit + +Compatible refresh should retain existing `useOnMount` values and open scopes, just as React Fast Refresh retains hook state. Editing the acquisition code inside `useOnMount` should not silently rerun it unless the View resets. + +On a reset, the existing `useScope` effect cleanup should close the old scope and its finalizers. Tests need to account for `finalizerExecutionDebounce` (100 ms by default), Strict Mode, and rapid consecutive edits. The implementation must not create a second close path in the HMR layer. + +## Why smaller fixes are insufficient + +| Option | Result | Assessment | +| --- | --- | --- | +| Teach Vite that `Component.make` is a component factory | Registers the descriptor, not the mounted synthesized function | Insufficient alone | +| Export every View or rename it to PascalCase | May improve boundary heuristics, but does not bridge the two identities | Insufficient | +| Wrap only route entrypoints with a normal React component | Can refresh the entry wrapper, but nested `.use` components still retain old implementations and state may remount | Partial workaround | +| Remove caching from `.use` | New type on every ordinary render; all child Views remount continuously | Incorrect | +| Mutate the old descriptor in a manual HMR handler | Demonstrably updates code and can preserve state, but lacks scheduling, hook safety, class/trait handling, and ergonomics | Useful prototype only | +| Register every synthesized function directly with React Refresh | Possible, but needs stable IDs per materialization, replacement creation for every Effect context, signature propagation, and private/runtime coupling | Viable but more coupled | +| Stable hot cell plus development shell | Explicitly bridges identities and controls preserve-versus-reset behavior | Recommended | +| Redesign Effect Views to be ordinary React component types | Makes React Refresh natural, but conflicts with context binding through `.use` and is a large API/architecture change | Not justified for this feature | + +## Proposed delivery plan + +### Phase 0: executable spike (2–4 days) + +- Instrument one `const` View and one class View in the example app. +- Retain a hot cell in `import.meta.hot.data`. +- Refresh with a guaranteed remount. +- Verify edits through a nested `.use` View and a `withRuntime` / `withContext` route. +- Verify a finalizer runs exactly once on reset. + +Exit criterion: editing render text updates without a page reload, and incompatible edits remount safely. + +### Phase 1: Vite MVP (4–7 additional days) + +- Implement binding-aware AST detection for all public construction styles. +- Add stable shell/keyed implementation support to the supported `effect-fc-next` Component implementation. +- Cover memoized and async traits. +- Add safe self-accept/fallback behavior. +- Add browser integration tests against the example app. + +Exit criterion: all supported Effect View forms refresh reliably, initially with conservative remounting where signature information is unavailable. + +### Phase 2: state preservation (4–7 additional days) + +- Compute ordered hook signatures. +- Preserve local state for compatible edits. +- Reset for hook-order changes and the force-reset directive. +- Test custom hooks, multiple service contexts, syntax-error recovery, and rapid edits. +- Document expected `useOnMount` and scope behavior. + +Exit criterion: the behavior matches React Fast Refresh closely enough that state preservation is predictable and hook-safe. + +### Later: other bundlers + +Because the main Effect View library owns the runtime metadata protocol, adapters for webpack/Rspack, Rolldown, or other environments can emit the same metadata without depending on Vite. Building those in parallel with the first Vite version would enlarge the test matrix before the semantics have settled. + +## Test matrix + +The feature should have real browser HMR tests; unit tests cannot fully validate React Refresh scheduling and module replacement. + +Minimum cases: + +- `const` and class View definitions. +- `make` and `makeUntraced`. +- Root entrypoint and nested `.use` child. +- A View imported through another module. +- Local, exported, default-exported, and renamed Views. +- Direct React state preserved after a render-only edit. +- State reset after adding/removing/reordering a hook. +- `useOnMount`, `useOnChange`, `useReactEffect`, and `useReactLayoutEffect` cleanup. +- Default and zero finalizer debounce. +- Memoized View with unchanged props. +- Async View and Suspense/error recovery. +- Two materializations of the same View under different Effect contexts. +- Reactive and `nonReactiveTags` service changes. +- TanStack Router code splitting used by the `example-next` application. +- Successive edits before the previous refresh finishes. +- Syntax error followed by recovery. +- Production build contains no HMR registry/subscription code. + +## Risks and open questions + +### Hook signature ownership + +The plugin must decide which `useX` calls represent React hook state. Effect View intentionally makes React hooks appear inside generator bodies, so relying only on standard React source patterns will remain incomplete. + +### Trait composition + +`Memoized.memoized`, async behavior, `withOptions`, and future traits can replace `transformFunctionComponent` or alter prototypes. The hot cell should point to the newest complete descriptor, and the development shell must define whether a trait change is compatible or forces reset. + +### Development tree shape + +A stable shell plus keyed implementation adds one fiber in development. This is a reasonable tradeoff, but React DevTools naming should make the extra layer understandable. + +### React/Vite version coupling + +The current plugin stack uses Vite's OXC refresh transform and a bundled/simplified React Refresh runtime. Depending on private runtime functions or generated transform text would make the feature sensitive to Vite upgrades. The main Effect View package should therefore own the standalone metadata protocol, while the Vite plugin depends on and adapts it. + +### Multiple materializations + +One View definition can produce more than one function identity because `.use` is evaluated under different Effect service sets and parent instances. A solution based on direct React Refresh registration must track every materialization. The hot-cell subscription model naturally fans one update out to all mounted materializations. + +### Resource expectations + +Preserving state also preserves acquired resources. Developers will need a reset directive or a documented way to force a remount when they edit acquisition logic and want it rerun immediately. + +## Recommendation + +Proceed with a Vite-first proof of concept using a stable hot cell and a development-only stable shell/keyed implementation. + +Do not begin by patching component-name heuristics or by registering the Effect View descriptor with React Refresh; those changes target the wrong identity. Also avoid coupling the initial implementation to private React Refresh family maps. + +The first milestone should always remount safely. Once browser tests prove update delivery and Effect scope cleanup, add signature-aware state preservation. This order isolates the HMR transport/identity problem from the hook-compatibility problem and gives the project a useful, releasable intermediate result. diff --git a/README.md b/README.md index 3d7e9bb..9d4f452 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,61 @@ -# Effect FC Monorepo +

+ + Effect View logo + +

-[Effect-TS](https://effect.website/) integration for React 19.2+ that allows you to write function components using Effect generators. +

Effect View Monorepo

-This monorepo contains: -- [The `effect-fc` library](packages/effect-fc) -- [An example project](packages/example) +

+ Write React components as typed Effect programs. +

+ +This repository contains Effect View, its documentation, development examples, +and supporting tooling. Effect View brings Effect's typed services, resource +safety, concurrency, and data modeling to React while keeping ordinary React +components, hooks, and JSX. + +## Packages + +| Package | Description | +| --- | --- | +| [`effect-view`](packages/effect-fc-next) | The Effect View library for Effect v4 and React 19. | +| [`@effect-view/vite-plugin`](packages/vite-plugin) | Vite Fast Refresh support for Effect View components. | +| [`docs`](packages/docs) | The [Effect View documentation](https://thila.dev/effect-view), built with Docusaurus. | +| [`example-next`](packages/example-next) | Example application using Effect View and Effect v4. | +| [`effect-fc`](packages/effect-fc) | Legacy Effect v3 package. | +| [`example`](packages/example) | Example application for the legacy package. | + +## Development + +The monorepo uses [Bun](https://bun.sh/) workspaces and +[Turborepo](https://turbo.build/). + +```bash +bun install +``` + +Run checks and builds from the repository root: + +```bash +bun run lint:tsc +bun run lint:biome +bun run test +bun run build +``` + +Start the Effect View example or documentation site: + +```bash +bun run --cwd packages/example-next dev +bun run --cwd packages/docs start +``` + +## Documentation + +Read the documentation at +[thila.dev/effect-view](https://thila.dev/effect-view). + +## License + +[MIT](LICENSE) diff --git a/bun.lock b/bun.lock index 2fb16f8..ee0d7d8 100644 --- a/bun.lock +++ b/bun.lock @@ -18,9 +18,9 @@ "name": "docs", "version": "0.0.0", "dependencies": { - "@docusaurus/core": "3.10.1", - "@docusaurus/faster": "^3.10.1", - "@docusaurus/preset-classic": "3.10.1", + "@docusaurus/core": "^3.10.2", + "@docusaurus/faster": "^3.10.2", + "@docusaurus/preset-classic": "^3.10.2", "@mdx-js/react": "^3.1.1", "clsx": "^2.1.1", "prism-react-renderer": "^2.4.1", @@ -28,20 +28,25 @@ "react-dom": "^19.2.5", }, "devDependencies": { - "@docusaurus/module-type-aliases": "3.10.1", - "@docusaurus/tsconfig": "3.10.1", - "@docusaurus/types": "3.10.1", + "@docusaurus/module-type-aliases": "^3.10.2", + "@docusaurus/tsconfig": "^3.10.2", + "@docusaurus/types": "^3.10.2", + "@types/react": "^19.2.15", + "@types/react-dom": "^19.2.3", "typescript": "~6.0.3", }, }, "packages/effect-fc": { "name": "effect-fc", - "version": "0.2.6", + "version": "0.3.0", "dependencies": { "effect-lens": "^0.2.0", }, "devDependencies": { "@effect/platform-browser": "^0.76.0", + "@testing-library/react": "^16.3.0", + "jsdom": "^26.1.0", + "vitest": "^3.2.4", }, "peerDependencies": { "@types/react": "^19.2.0", @@ -49,6 +54,26 @@ "react": "^19.2.0", }, }, + "packages/effect-fc-next": { + "name": "effect-fc-next", + "version": "0.1.0-beta.0", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "effect-lens": "^2.0.0-beta.1", + }, + "devDependencies": { + "@effect/platform-browser": "4.0.0-beta.98", + "@testing-library/react": "^16.3.0", + "effect": "4.0.0-beta.98", + "jsdom": "^26.1.0", + "vitest": "^3.2.4", + }, + "peerDependencies": { + "@types/react": "^19.2.0", + "effect": "4.0.0-beta.98", + "react": "^19.2.0", + }, + }, "packages/example": { "name": "@effect-fc/example", "version": "0.0.0", @@ -75,265 +100,311 @@ "vite": "^8.0.16", }, }, + "packages/example-next": { + "name": "@effect-fc/example-next", + "version": "0.0.0", + "dependencies": { + "@effect/platform-browser": "4.0.0-beta.98", + "@radix-ui/themes": "^3.3.0", + "effect": "4.0.0-beta.98", + "effect-fc-next": "workspace:*", + "react-icons": "^5.6.0", + }, + "devDependencies": { + "@effect-view/vite-plugin": "workspace:*", + "@tanstack/react-router": "^1.170.10", + "@tanstack/react-router-devtools": "^1.167.0", + "@tanstack/router-plugin": "^1.168.13", + "@types/react": "^19.2.15", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.2", + "globals": "^17.6.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "vite": "^8.0.16", + }, + }, + "packages/vite-plugin": { + "name": "@effect-view/vite-plugin", + "version": "0.0.1", + "dependencies": { + "typescript": "^6.0.3", + }, + "devDependencies": { + "effect-fc-next": "workspace:*", + "vite": "^8.0.16", + "vitest": "^3.2.4", + }, + "peerDependencies": { + "effect-fc-next": "0.1.0-beta.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + }, + }, }, "packages": { - "@algolia/abtesting": ["@algolia/abtesting@1.16.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-alHFZ68/i9qLC/muEB07VQ9r7cB8AvCcGX6dVQi2PNHhc/ZQRmmFAv8KK1ay4UiseGSFr7f0nXBKsZ/jRg7e4g=="], + "@11ty/gray-matter": ["@11ty/gray-matter@1.0.0", "", { "dependencies": { "js-yaml": "^4.1.0", "kind-of": "^6.0.3", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-7mJJl+wf1AByoT0PknQiQfOPnVNT4fevGrUBVWO4HXsnYn1aQPyRyrELYrNUFleUBM++KzMKN6QaxHPk0t/6/g=="], - "@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.19.2", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", "@algolia/autocomplete-shared": "1.19.2" } }, "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw=="], + "@algolia/abtesting": ["@algolia/abtesting@1.22.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-BFR6zNowNKcY7Ou7TaJc9QWexES4YKPbmf/OTFofpdsdhz4x6q0lbxp3duO0EHnyrN7rE4ba/TSXuY+BDGu4+g=="], - "@algolia/autocomplete-plugin-algolia-insights": ["@algolia/autocomplete-plugin-algolia-insights@1.19.2", "", { "dependencies": { "@algolia/autocomplete-shared": "1.19.2" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg=="], + "@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.19.9", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.19.9", "@algolia/autocomplete-shared": "1.19.9" } }, "sha512-4U2JKLMWlDu0CotYyUkWakDxr8AIav3QtIUXXRpfavYN29aVWfzlwJp9T0rPKEf/dO2QCPAUc0Kq1Tj1GJxo2A=="], - "@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.19.2", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w=="], + "@algolia/autocomplete-plugin-algolia-insights": ["@algolia/autocomplete-plugin-algolia-insights@1.19.9", "", { "dependencies": { "@algolia/autocomplete-shared": "1.19.9" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "sha512-6mExC6X7762s2SV3eJy3QOkB8bdMmnUhQ2agvGVDuzwoGyr3PquGSY/0vPQXCfiAiCaXUz1rXn+lwghgSi0l0w=="], - "@algolia/client-abtesting": ["@algolia/client-abtesting@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-mfgUdLQNxOAvCZUGzPQxjahEWEPuQkKlV0ZtGmePOa9ZxIQZlk31vRBNbM6ScU8jTH41SCYE77G/lCifDr1SVw=="], + "@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.19.9", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-YosP9Uoek6y/Ur1r1qeogk4biMe/hzkyNcgMCciw0//3XpCM7VlYLSHnyt/vOnEOGhCCc0+3v+unEiH6zz+Z1A=="], - "@algolia/client-analytics": ["@algolia/client-analytics@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-5mjokeKYyPaP3Q8IYJEnutI+O4dW/Ixxx5IgsSxT04pCfGqPXxTOH311hTQxyNpcGGEOGrMv8n8Z+UMTPamioQ=="], + "@algolia/client-abtesting": ["@algolia/client-abtesting@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-7r4Z3NC7yU1oAQVWJNA2HX7tX481F3pJvCGyLIXiTdBcthz4Q/o21jwcMYDFkuI92UWTNBQQmHYgwHo1zS5dzg=="], - "@algolia/client-common": ["@algolia/client-common@5.50.0", "", {}, "sha512-emtOvR6dl3rX3sBJXXbofMNHU1qMQqQSWu319RMrNL5BWoBqyiq7y0Zn6cjJm7aGHV/Qbf+KCCYeWNKEMPI3BQ=="], + "@algolia/client-analytics": ["@algolia/client-analytics@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-avmjXQSq+jadFO8Xl2em05/uQdQnEmHsJyOAdVbZkmVgpMfxL12aJwVVfGNwYr9nulcpuJN1X0lTaQ5wxuNGcA=="], - "@algolia/client-insights": ["@algolia/client-insights@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-IerGH2/hcj/6bwkpQg/HHRqmlGN1XwygQWythAk0gZFBrghs9danJaYuSS3ShzLSVoIVth4jY5GDPX9Lbw5cgg=="], + "@algolia/client-common": ["@algolia/client-common@5.56.0", "", {}, "sha512-v2TPStUhY//ripPjIVclZ8AWc7DEGooXULZGFlFu37zNatgHjw34oZZ+OSbbc/YHO+xZwPl62I1k8xH1m4S2eg=="], - "@algolia/client-personalization": ["@algolia/client-personalization@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-3idPJeXn5L0MmgP9jk9JJqblrQ/SguN93dNK9z9gfgyupBhHnJMOEjrRYcVgTIfvG13Y04wO+Q0FxE2Ut8PVbA=="], + "@algolia/client-insights": ["@algolia/client-insights@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-P0ehROpM4Sem3Sqo5x2cKPgj67D3G3jy0rh1Amwkcvsfr6tkvIcdCmerieanqTF7NxUMPNFLkpIFeMO8Rpa50w=="], - "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-q7qRoWrQK1a8m5EFQEmPlo7+pg9mVQ8X5jsChtChERre0uS2pdYEDixBBl0ydBSGkdGbLUDufcACIhH/077E4g=="], + "@algolia/client-personalization": ["@algolia/client-personalization@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-SXK3Vn3WVxyzbm31oePZBJkp1wpOyuWdd4B/Pv7n0aXDxmeSWhC1R1FC1517mMrFAIaPH4Rt0x6RUe7ZNjz8FA=="], - "@algolia/client-search": ["@algolia/client-search@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-Jc360x4yqb3eEg4OY4KEIdGePBxZogivKI+OGIU8aLXgAYPTECvzeOBc90312yHA1hr3AeRlAFl0rIc8lQaIrQ=="], + "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-5+ZdX8garFnmycnZgKhtXHePEaLj5zqDxI/0lkhhluzCcvTn0/PvvTirTg8hHYetQHvn7GDyeAiqTAieMvMW4A=="], + + "@algolia/client-search": ["@algolia/client-search@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-+mKUdYvqOi0BcvpAEyCEw49vSBptufIcfibtHz2bdr1pI789M46Yt0uQEk/sxtK3teh71OQvVFHaTDzShUWewQ=="], "@algolia/events": ["@algolia/events@4.0.1", "", {}, "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ=="], - "@algolia/ingestion": ["@algolia/ingestion@1.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-OS3/Viao+NPpyBbEY3tf6hLewppG+UclD+9i0ju56mq2DrdMJFCkEky6Sk9S5VPcbLzxzg3BqBX6u9Q35w19aQ=="], + "@algolia/ingestion": ["@algolia/ingestion@1.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-9g/zj+AZx5moFcdFIrYQoVrueXivjUcc3MQHtCYT8WhIuk1lUh1AyEhvJCS0XBZld09cLvd1AZ3BvDBpVpX2UA=="], - "@algolia/monitoring": ["@algolia/monitoring@1.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-/znwgSiGufpbJVIoDmeQaHtTq+OMdDawFRbMSJVv+12n79hW+qdQXS8/Uu3BD3yn0BzgVFJEvrsHrCsInZKdhw=="], + "@algolia/monitoring": ["@algolia/monitoring@1.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-Qf3Sr6f9A9uxCZUf3MXS0d2b877uYzEB5yxqpVGXAhcJnBCQjrRRon0KvefpGkxy+BshrIJs96OUoMtGqXTFDA=="], - "@algolia/recommend": ["@algolia/recommend@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-dHjUfu4jfjdQiKDpCpAnM7LP5yfG0oNShtfpF5rMCel6/4HIoqJ4DC4h5GKDzgrvJYtgAhblo0AYBmOM00T+lQ=="], + "@algolia/recommend": ["@algolia/recommend@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-GXWG1rWc5wu8hY4N33Y3b6ernY6sAdAvmKWN/zHAiACOx40WnpG0TVX5YazCAr/9gOYGInSiM2A0y2jy2xbiDA=="], - "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0" } }, "sha512-bffIbUljAWnh/Ctu5uScORajuUavqmZ0ACYd1fQQeSSYA9NNN83ynO26pSc2dZRXpSK0fkc1//qSSFXMKGu+aw=="], + "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0" } }, "sha512-7t24cBxaInS3mZb7ddEaZT/tp6q+/aR4YttsQVyP1/i+LmwPR34atO35KjaLFCcRVrlP7sYOAqkCfg6lIRB+ew=="], - "@algolia/requester-fetch": ["@algolia/requester-fetch@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0" } }, "sha512-y0EwNvPGvkM+yTAqqO6Gpt9wVGm3CLDtpLvNEiB3VGvN3WzfkjZGtLUsG/ru2kVJIIU7QcV0puuYgEpBeFxcJg=="], + "@algolia/requester-fetch": ["@algolia/requester-fetch@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0" } }, "sha512-R7ePHgVYmDFjZpvrsVAfbDz/d4RxKAYZ5/vgLfIsCVRZRryjWl/3INOxpOICzitehQ5FjNtNjcLQTrmHPTcHBQ=="], - "@algolia/requester-node-http": ["@algolia/requester-node-http@5.50.0", "", { "dependencies": { "@algolia/client-common": "5.50.0" } }, "sha512-xpwefe4fCOWnZgXCbkGpqQY6jgBSCf2hmgnySbyzZIccrv3SoashHKGPE4x6vVG+gdHrGciMTAcDo9HOZwH22Q=="], + "@algolia/requester-node-http": ["@algolia/requester-node-http@5.56.0", "", { "dependencies": { "@algolia/client-common": "5.56.0" } }, "sha512-PIOUXlSnrqM0S+WOgDRb4RzotydJH7ZoT6tOyL7tAO7qJOfvX5wsEW8Pe+PMKMwvuI4/gIyK9cg2H7lJXqnc4Q=="], - "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + "@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.2.0", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw=="], - "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], + "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], - "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@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-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="], - "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], + "@babel/core": ["@babel/core@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-module-transforms": "^7.29.7", "@babel/helpers": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", "@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-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA=="], - "@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/generator": ["@babel/generator@7.29.7", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ=="], - "@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.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" } }, "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw=="], - "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow=="], + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="], - "@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="], + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-member-expression-to-functions": "^7.29.7", "@babel/helper-optimise-call-expression": "^7.29.7", "@babel/helper-replace-supers": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/traverse": "^7.29.7", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg=="], + + "@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg=="], "@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.8", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "debug": "^4.4.3", "lodash.debounce": "^4.0.8", "resolve": "^1.22.11" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA=="], - "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + "@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="], - "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="], + "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg=="], - "@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-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="], - "@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-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="], - "@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-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" } }, "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong=="], - "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.29.7", "", {}, "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw=="], - "@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-wrap-function": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="], + "@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-wrap-function": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og=="], - "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.28.6", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg=="], + "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.29.7", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.29.7", "@babel/helper-optimise-call-expression": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ=="], - "@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-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ=="], - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], - "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="], - "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ=="], + "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw=="], - "@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="], + "@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="], - "@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="], + "@babel/parser": ["@babel/parser@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" }, "bin": "./bin/babel-parser.js" }, "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg=="], - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="], + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w=="], - "@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="], + "@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ=="], - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA=="], + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ=="], - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="], + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": ["@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA=="], - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g=="], + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/plugin-transform-optional-chaining": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw=="], + + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw=="], "@babel/plugin-proposal-private-property-in-object": ["@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w=="], "@babel/plugin-syntax-dynamic-import": ["@babel/plugin-syntax-dynamic-import@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ=="], - "@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw=="], + "@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw=="], - "@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw=="], + "@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg=="], - "@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.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A=="], - "@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.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA=="], "@babel/plugin-syntax-unicode-sets-regex": ["@babel/plugin-syntax-unicode-sets-regex@7.18.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg=="], - "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="], + "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ=="], - "@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.29.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1", "@babel/traverse": "^7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w=="], + "@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-remap-async-to-generator": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA=="], - "@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g=="], + "@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-remap-async-to-generator": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w=="], - "@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="], + "@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA=="], - "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw=="], + "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ=="], - "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.28.6", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw=="], + "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.29.7", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA=="], - "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.6", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ=="], + "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.29.7", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A=="], - "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-replace-supers": "^7.28.6", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q=="], + "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-globals": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-replace-supers": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g=="], - "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/template": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ=="], + "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/template": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA=="], - "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="], + "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg=="], - "@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.28.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg=="], + "@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.29.7", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ=="], - "@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q=="], + "@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ=="], - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw=="], + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA=="], - "@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A=="], + "@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg=="], - "@babel/plugin-transform-explicit-resource-management": ["@babel/plugin-transform-explicit-resource-management@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/plugin-transform-destructuring": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg=="], + "@babel/plugin-transform-explicit-resource-management": ["@babel/plugin-transform-explicit-resource-management@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/plugin-transform-destructuring": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw=="], - "@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw=="], + "@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ=="], - "@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="], + "@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA=="], - "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="], + "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ=="], - "@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="], + "@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.29.7", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg=="], - "@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw=="], + "@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg=="], - "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="], + "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw=="], - "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A=="], + "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q=="], - "@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="], + "@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg=="], - "@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@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-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA=="], + "@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.29.7", "", { "dependencies": { "@babel/helper-module-transforms": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew=="], - "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.28.6", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA=="], + "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.29.7", "", { "dependencies": { "@babel/helper-module-transforms": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ=="], - "@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.29.0", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ=="], + "@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.29.7", "", { "dependencies": { "@babel/helper-module-transforms": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ=="], - "@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@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-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="], + "@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.29.7", "", { "dependencies": { "@babel/helper-module-transforms": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA=="], - "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.29.0", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ=="], + "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.29.7", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ=="], - "@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ=="], + "@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A=="], - "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg=="], + "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg=="], - "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w=="], + "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw=="], - "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.6", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA=="], + "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.29.7", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/plugin-transform-destructuring": "^7.29.7", "@babel/plugin-transform-parameters": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A=="], - "@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="], + "@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-replace-supers": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA=="], - "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ=="], + "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng=="], - "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w=="], + "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ=="], - "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="], + "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g=="], - "@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.28.6", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg=="], + "@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.29.7", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug=="], - "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA=="], + "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA=="], - "@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="], + "@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA=="], - "@babel/plugin-transform-react-constant-elements": ["@babel/plugin-transform-react-constant-elements@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug=="], + "@babel/plugin-transform-react-constant-elements": ["@babel/plugin-transform-react-constant-elements@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-J0wGhKan+rIiE2OhfhRptySLrJ6SjQYM6b6N1FMlhyhCcw1Mig8vQjWchyB+bgHGDvaWo6Diu6CLRMra2uMtmg=="], - "@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="], + "@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q=="], - "@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-module-imports": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/plugin-syntax-jsx": "^7.28.6", "@babel/types": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow=="], + "@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-module-imports": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/plugin-syntax-jsx": "^7.29.7", "@babel/types": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A=="], - "@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="], + "@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.29.7", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g=="], - "@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="], + "@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA=="], - "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.29.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog=="], + "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw=="], - "@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.28.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg=="], + "@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.29.7", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ=="], - "@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="], + "@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA=="], - "@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.29.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w=="], + "@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xmAscdE/AsqRW7vutbPNoUmu/nF5SrLKPs7aoJgEjo35lLKA/Bc0i2rMv/hr1+Y0o1bQCiVtith3u2vdgRL39Q=="], - "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="], + "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg=="], - "@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA=="], + "@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ=="], - "@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="], + "@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA=="], - "@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="], + "@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA=="], - "@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="], + "@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A=="], - "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw=="], + "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/plugin-syntax-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw=="], - "@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="], + "@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA=="], - "@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.28.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A=="], + "@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.29.7", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw=="], - "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="], + "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.29.7", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA=="], - "@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.28.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q=="], + "@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.29.7", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg=="], - "@babel/preset-env": ["@babel/preset-env@7.29.2", "", { "dependencies": { "@babel/compat-data": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.28.6", "@babel/plugin-syntax-import-attributes": "^7.28.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.29.0", "@babel/plugin-transform-async-to-generator": "^7.28.6", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.6", "@babel/plugin-transform-class-properties": "^7.28.6", "@babel/plugin-transform-class-static-block": "^7.28.6", "@babel/plugin-transform-classes": "^7.28.6", "@babel/plugin-transform-computed-properties": "^7.28.6", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.28.6", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.6", "@babel/plugin-transform-exponentiation-operator": "^7.28.6", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.28.6", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.28.6", "@babel/plugin-transform-modules-systemjs": "^7.29.0", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", "@babel/plugin-transform-numeric-separator": "^7.28.6", "@babel/plugin-transform-object-rest-spread": "^7.28.6", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.28.6", "@babel/plugin-transform-optional-chaining": "^7.28.6", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.28.6", "@babel/plugin-transform-private-property-in-object": "^7.28.6", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.29.0", "@babel/plugin-transform-regexp-modifiers": "^7.28.6", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.28.6", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.28.6", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.15", "babel-plugin-polyfill-corejs3": "^0.14.0", "babel-plugin-polyfill-regenerator": "^0.6.6", "core-js-compat": "^3.48.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw=="], + "@babel/preset-env": ["@babel/preset-env@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.29.7", "@babel/plugin-syntax-import-attributes": "^7.29.7", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.29.7", "@babel/plugin-transform-async-generator-functions": "^7.29.7", "@babel/plugin-transform-async-to-generator": "^7.29.7", "@babel/plugin-transform-block-scoped-functions": "^7.29.7", "@babel/plugin-transform-block-scoping": "^7.29.7", "@babel/plugin-transform-class-properties": "^7.29.7", "@babel/plugin-transform-class-static-block": "^7.29.7", "@babel/plugin-transform-classes": "^7.29.7", "@babel/plugin-transform-computed-properties": "^7.29.7", "@babel/plugin-transform-destructuring": "^7.29.7", "@babel/plugin-transform-dotall-regex": "^7.29.7", "@babel/plugin-transform-duplicate-keys": "^7.29.7", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", "@babel/plugin-transform-dynamic-import": "^7.29.7", "@babel/plugin-transform-explicit-resource-management": "^7.29.7", "@babel/plugin-transform-exponentiation-operator": "^7.29.7", "@babel/plugin-transform-export-namespace-from": "^7.29.7", "@babel/plugin-transform-for-of": "^7.29.7", "@babel/plugin-transform-function-name": "^7.29.7", "@babel/plugin-transform-json-strings": "^7.29.7", "@babel/plugin-transform-literals": "^7.29.7", "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", "@babel/plugin-transform-member-expression-literals": "^7.29.7", "@babel/plugin-transform-modules-amd": "^7.29.7", "@babel/plugin-transform-modules-commonjs": "^7.29.7", "@babel/plugin-transform-modules-systemjs": "^7.29.7", "@babel/plugin-transform-modules-umd": "^7.29.7", "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", "@babel/plugin-transform-new-target": "^7.29.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", "@babel/plugin-transform-numeric-separator": "^7.29.7", "@babel/plugin-transform-object-rest-spread": "^7.29.7", "@babel/plugin-transform-object-super": "^7.29.7", "@babel/plugin-transform-optional-catch-binding": "^7.29.7", "@babel/plugin-transform-optional-chaining": "^7.29.7", "@babel/plugin-transform-parameters": "^7.29.7", "@babel/plugin-transform-private-methods": "^7.29.7", "@babel/plugin-transform-private-property-in-object": "^7.29.7", "@babel/plugin-transform-property-literals": "^7.29.7", "@babel/plugin-transform-regenerator": "^7.29.7", "@babel/plugin-transform-regexp-modifiers": "^7.29.7", "@babel/plugin-transform-reserved-words": "^7.29.7", "@babel/plugin-transform-shorthand-properties": "^7.29.7", "@babel/plugin-transform-spread": "^7.29.7", "@babel/plugin-transform-sticky-regex": "^7.29.7", "@babel/plugin-transform-template-literals": "^7.29.7", "@babel/plugin-transform-typeof-symbol": "^7.29.7", "@babel/plugin-transform-unicode-escapes": "^7.29.7", "@babel/plugin-transform-unicode-property-regex": "^7.29.7", "@babel/plugin-transform-unicode-regex": "^7.29.7", "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.15", "babel-plugin-polyfill-corejs3": "^0.14.0", "babel-plugin-polyfill-regenerator": "^0.6.6", "core-js-compat": "^3.48.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA=="], "@babel/preset-modules": ["@babel/preset-modules@0.1.6-no-external-plugins", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA=="], - "@babel/preset-react": ["@babel/preset-react@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ=="], + "@babel/preset-react": ["@babel/preset-react@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "@babel/plugin-transform-react-display-name": "^7.29.7", "@babel/plugin-transform-react-jsx": "^7.29.7", "@babel/plugin-transform-react-jsx-development": "^7.29.7", "@babel/plugin-transform-react-pure-annotations": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-C+PV1TFUPTmBQGoPBL8j2QmLpZ117YTCwxIZeJOM96GbYMFSc7/pOXU5lVykwnZxyTqQxRsvoRk6f2FktZgGHA=="], - "@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "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.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="], + "@babel/preset-typescript": ["@babel/preset-typescript@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "@babel/plugin-syntax-jsx": "^7.29.7", "@babel/plugin-transform-modules-commonjs": "^7.29.7", "@babel/plugin-transform-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ=="], - "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], + "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="], - "@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/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="], - "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], + "@babel/traverse": ["@babel/traverse@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/types": "^7.29.7", "debug": "^4.3.1" } }, "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw=="], - "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + "@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], - "@biomejs/biome": ["@biomejs/biome@2.4.16", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.16", "@biomejs/cli-darwin-x64": "2.4.16", "@biomejs/cli-linux-arm64": "2.4.16", "@biomejs/cli-linux-arm64-musl": "2.4.16", "@biomejs/cli-linux-x64": "2.4.16", "@biomejs/cli-linux-x64-musl": "2.4.16", "@biomejs/cli-win32-arm64": "2.4.16", "@biomejs/cli-win32-x64": "2.4.16" }, "bin": { "biome": "bin/biome" } }, "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA=="], + "@biomejs/biome": ["@biomejs/biome@2.5.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.5.4", "@biomejs/cli-darwin-x64": "2.5.4", "@biomejs/cli-linux-arm64": "2.5.4", "@biomejs/cli-linux-arm64-musl": "2.5.4", "@biomejs/cli-linux-x64": "2.5.4", "@biomejs/cli-linux-x64-musl": "2.5.4", "@biomejs/cli-win32-arm64": "2.5.4", "@biomejs/cli-win32-x64": "2.5.4" }, "bin": { "biome": "bin/biome" } }, "sha512-xy5FNE5kQJKyK5MR1gJy6ztXYx4WBAbYGlK04lMEgmyPRWKybY9NFwiG9yo0XdzOU8Xvhj41u034J1ywfoWfMw=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.5.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4o3NFRobXHynkgcFVrlZsoDAFtF2ldlEGN8sORSws5ZQqyY4PXnPUIylu4ksfyHuwkfvDREuWh3JK+niRwGq3w=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.5.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-D32P5HkU2Y6PySuC/WsVDTOgsDwVFmujzhhhOQjajtATpVWFDXuVd3oRbsWNSEA+aaFzyzZm22szsyydBYlSyQ=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.5.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-pSEfW7B8kTsXUjUxC1xVVK+y85Ht3C5XxZ9gclmC7/3Ku9Vqz8jmI7k0p/BNIjQ6t4sFERI2sFeH73ybiZl6YQ=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.5.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-Rpm5/AT1m+DlJmUoYvS4/vXc+0tXJPJ2NQz25TGPyHVF5JrWy75PE0GH6kVxsKtQDuCH4OgzquZq0R4kj/wCVg=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.5.4", "", { "os": "linux", "cpu": "x64" }, "sha512-FNxojWJkL7EajAuzBgoLe0T2G0y112M4lBrDIFl/DomFTx8yqenYOIdsRLNXvOvBBofE8hJi85LjzLmBDpY7/Q=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.5.4", "", { "os": "linux", "cpu": "x64" }, "sha512-aby/PohmmgbShcHqFsZVzG8H6D98+P+A6xRWRrQcLW1pCjabcov5UUlke4UqNQBYTkDQav+jB4zyyDDeKB2GaA=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.5.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-emoXexPZIPAZkz2RKmA95WJUqK3I5MJNYtwEbL5ESciRzhmFMMyekDhNG8hpeOaK+ZGRDxAU4wvGuA5IHQ0h0w=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.16", "", { "os": "win32", "cpu": "x64" }, "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.5.4", "", { "os": "win32", "cpu": "x64" }, "sha512-U1jaluLw1qQc2Tx7/CeSoL9N5XcqIH+GWjpUAy1ouB5nVjSCMNO+NNHdY3RAs8zxNurLWAdj6pehQdCA2zyU+Q=="], "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], @@ -439,89 +510,145 @@ "@discoveryjs/json-ext": ["@discoveryjs/json-ext@0.5.7", "", {}, "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw=="], - "@docsearch/core": ["@docsearch/core@4.6.2", "", { "peerDependencies": { "@types/react": ">= 16.8.0 < 20.0.0", "react": ">= 16.8.0 < 20.0.0", "react-dom": ">= 16.8.0 < 20.0.0" }, "optionalPeers": ["@types/react", "react", "react-dom"] }, "sha512-/S0e6Dj7Zcm8m9Rru49YEX49dhU11be68c+S/BCyN8zQsTTgkKzXlhRbVL5mV6lOLC2+ZRRryaTdcm070Ug2oA=="], + "@docsearch/core": ["@docsearch/core@4.6.3", "", { "peerDependencies": { "@types/react": ">= 16.8.0 < 20.0.0", "react": ">= 16.8.0 < 20.0.0", "react-dom": ">= 16.8.0 < 20.0.0" }, "optionalPeers": ["@types/react", "react", "react-dom"] }, "sha512-rUOujwIpxJRgD7+kicVsI3D5sqBvdiRTquzWBpTEXZs8ZXfGbfzpus5HqumaNYTppN2HvH8E2yNuRwYdHJeOlA=="], - "@docsearch/css": ["@docsearch/css@4.6.2", "", {}, "sha512-fH/cn8BjEEdM2nJdjNMHIvOVYupG6AIDtFVDgIZrNzdCSj4KXr9kd+hsehqsNGYjpUjObeKYKvgy/IwCb1jZYQ=="], + "@docsearch/css": ["@docsearch/css@4.6.3", "", {}, "sha512-nlOwcXcsNAptQl4vlL4MA78qNJKO0Qlds5GuBjCoePgkebTXLSf8Qt1oyZ3YBshYupKXG9VRGEsk1zr23d+bzQ=="], - "@docsearch/react": ["@docsearch/react@4.6.2", "", { "dependencies": { "@algolia/autocomplete-core": "1.19.2", "@docsearch/core": "4.6.2", "@docsearch/css": "4.6.2" }, "peerDependencies": { "@types/react": ">= 16.8.0 < 20.0.0", "react": ">= 16.8.0 < 20.0.0", "react-dom": ">= 16.8.0 < 20.0.0", "search-insights": ">= 1 < 3" }, "optionalPeers": ["@types/react", "react", "react-dom", "search-insights"] }, "sha512-/BbtGFtqVOGwZx0dw/UfhN/0/DmMQYnulY4iv0tPRhC2JCXv0ka/+izwt3Jzo1ZxXS/2eMvv9zHsBJOK1I9f/w=="], + "@docsearch/react": ["@docsearch/react@4.6.3", "", { "dependencies": { "@algolia/autocomplete-core": "1.19.2", "@docsearch/core": "4.6.3", "@docsearch/css": "4.6.3" }, "peerDependencies": { "@types/react": ">= 16.8.0 < 20.0.0", "react": ">= 16.8.0 < 20.0.0", "react-dom": ">= 16.8.0 < 20.0.0", "search-insights": ">= 1 < 3" }, "optionalPeers": ["@types/react", "react", "react-dom", "search-insights"] }, "sha512-Bg2wdDsoQVlNCcEKuEJAU04tvHCqgx8rIu+uIoM4pRtcx3TBKJuXutJik3LTA8LRc9YEyHkrYUrmcC0D7BYf+g=="], - "@docusaurus/babel": ["@docusaurus/babel@3.10.1", "", { "dependencies": { "@babel/core": "^7.25.9", "@babel/generator": "^7.25.9", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.25.9", "@babel/preset-react": "^7.25.9", "@babel/preset-typescript": "^7.25.9", "@babel/runtime": "^7.25.9", "@babel/traverse": "^7.25.9", "@docusaurus/logger": "3.10.1", "@docusaurus/utils": "3.10.1", "babel-plugin-dynamic-import-node": "^2.3.3", "fs-extra": "^11.1.1", "tslib": "^2.6.0" } }, "sha512-DZzFO1K3v/GoEt1fx1DiYHF4en+PuhtQf1AkQJa5zu3CoeKSpr5cpQRUlz3jr0m44wyzmSXu9bVpfir+N4+8bg=="], + "@docusaurus/babel": ["@docusaurus/babel@3.10.2", "", { "dependencies": { "@babel/core": "^7.25.9", "@babel/generator": "^7.25.9", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.25.9", "@babel/preset-react": "^7.25.9", "@babel/preset-typescript": "^7.25.9", "@babel/runtime": "^7.25.9", "@babel/traverse": "^7.25.9", "@docusaurus/logger": "3.10.2", "@docusaurus/utils": "3.10.2", "babel-plugin-dynamic-import-node": "^2.3.3", "fs-extra": "^11.1.1", "tslib": "^2.6.0" } }, "sha512-aJ1hpGyvfkte3dDAfNbWM4biW4yWZBVz7TIGLZP+v+tWOBgxX3e0N5ZIXHIvmfNNXTI77pcHUx3KmtOk05Ze3Q=="], - "@docusaurus/bundler": ["@docusaurus/bundler@3.10.1", "", { "dependencies": { "@babel/core": "^7.25.9", "@docusaurus/babel": "3.10.1", "@docusaurus/cssnano-preset": "3.10.1", "@docusaurus/logger": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "babel-loader": "^9.2.1", "clean-css": "^5.3.3", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.11.0", "css-minimizer-webpack-plugin": "^5.0.1", "cssnano": "^6.1.2", "file-loader": "^6.2.0", "html-minifier-terser": "^7.2.0", "mini-css-extract-plugin": "^2.9.2", "null-loader": "^4.0.1", "postcss": "^8.5.4", "postcss-loader": "^7.3.4", "postcss-preset-env": "^10.2.1", "terser-webpack-plugin": "^5.3.9", "tslib": "^2.6.0", "url-loader": "^4.1.1", "webpack": "^5.95.0", "webpackbar": "^7.0.0" }, "peerDependencies": { "@docusaurus/faster": "*" }, "optionalPeers": ["@docusaurus/faster"] }, "sha512-HIqQPvbqnnQRe4NsBd1774KRarjXqS6wHsWELtyuSs1gCfvixJO2jUGH/OEBtr1Gvzpw+ze5CjGMvSJ8UE1KUw=="], + "@docusaurus/bundler": ["@docusaurus/bundler@3.10.2", "", { "dependencies": { "@babel/core": "^7.25.9", "@docusaurus/babel": "3.10.2", "@docusaurus/cssnano-preset": "3.10.2", "@docusaurus/logger": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils": "3.10.2", "babel-loader": "^9.2.1", "clean-css": "^5.3.3", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.11.0", "css-minimizer-webpack-plugin": "^5.0.1", "cssnano": "^6.1.2", "file-loader": "^6.2.0", "html-minifier-terser": "^7.2.0", "mini-css-extract-plugin": "^2.9.2", "null-loader": "^4.0.1", "postcss": "^8.5.4", "postcss-loader": "^7.3.4", "postcss-preset-env": "^10.2.1", "terser-webpack-plugin": "^5.3.9", "tslib": "^2.6.0", "url-loader": "^4.1.1", "webpack": "^5.95.0", "webpackbar": "^7.0.0" }, "peerDependencies": { "@docusaurus/faster": "*" }, "optionalPeers": ["@docusaurus/faster"] }, "sha512-i0ZNcy0f0WhaOlYVgzLsWhIoEXO9kS3HRoKPtgE6vQtZUq7arKZaYdNBudr3mqCmd+TyOkwtwfHgs1ENj07r5g=="], - "@docusaurus/core": ["@docusaurus/core@3.10.1", "", { "dependencies": { "@docusaurus/babel": "3.10.1", "@docusaurus/bundler": "3.10.1", "@docusaurus/logger": "3.10.1", "@docusaurus/mdx-loader": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "boxen": "^6.2.1", "chalk": "^4.1.2", "chokidar": "^3.5.3", "cli-table3": "^0.6.3", "combine-promises": "^1.1.0", "commander": "^5.1.0", "core-js": "^3.31.1", "detect-port": "^1.5.1", "escape-html": "^1.0.3", "eta": "^2.2.0", "eval": "^0.1.8", "execa": "^5.1.1", "fs-extra": "^11.1.1", "html-tags": "^3.3.1", "html-webpack-plugin": "^5.6.0", "leven": "^3.1.0", "lodash": "^4.17.21", "open": "^8.4.0", "p-map": "^4.0.0", "prompts": "^2.4.2", "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", "react-loadable-ssr-addon-v5-slorber": "^1.0.3", "react-router": "^5.3.4", "react-router-config": "^5.1.1", "react-router-dom": "^5.3.4", "semver": "^7.5.4", "serve-handler": "^6.1.7", "tinypool": "^1.0.2", "tslib": "^2.6.0", "update-notifier": "^6.0.2", "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.10.2", "webpack-dev-server": "^5.2.2", "webpack-merge": "^6.0.1" }, "peerDependencies": { "@docusaurus/faster": "*", "@mdx-js/react": "^3.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@docusaurus/faster"], "bin": { "docusaurus": "bin/docusaurus.mjs" } }, "sha512-3pf2fXXw0eVk8WnC3T4LIigRDupcpvngpKo9Vy7mYyBhuddc0klDUuZAIfzMoK6z05pdlk6EFC/vBSX43+1O5w=="], + "@docusaurus/core": ["@docusaurus/core@3.10.2", "", { "dependencies": { "@docusaurus/babel": "3.10.2", "@docusaurus/bundler": "3.10.2", "@docusaurus/logger": "3.10.2", "@docusaurus/mdx-loader": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-common": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "boxen": "^6.2.1", "chalk": "^4.1.2", "chokidar": "^3.5.3", "cli-table3": "^0.6.3", "combine-promises": "^1.1.0", "commander": "^5.1.0", "core-js": "^3.31.1", "detect-port": "^2.1.0", "escape-html": "^1.0.3", "eta": "^2.2.0", "eval": "^0.1.8", "execa": "^5.1.1", "fs-extra": "^11.1.1", "html-tags": "^3.3.1", "html-webpack-plugin": "^5.6.0", "leven": "^3.1.0", "lodash": "^4.17.21", "open": "^8.4.0", "p-map": "^4.0.0", "prompts": "^2.4.2", "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", "react-loadable-ssr-addon-v5-slorber": "^1.0.3", "react-router": "^5.3.4", "react-router-config": "^5.1.1", "react-router-dom": "^5.3.4", "semver": "^7.5.4", "serve-handler": "^6.1.7", "tinypool": "^1.0.2", "tslib": "^2.6.0", "update-notifier": "^6.0.2", "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.10.2", "webpack-dev-server": "^5.2.2", "webpack-merge": "^6.0.1" }, "peerDependencies": { "@docusaurus/faster": "*", "@mdx-js/react": "^3.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@docusaurus/faster"], "bin": { "docusaurus": "bin/docusaurus.mjs" } }, "sha512-EYByj6nk+aD9KeVxV6Hmo2/nAAT79P21Y82ycTBOBtrmqilloIbIEhgL2/8Xpt2Jz/pgNqHAwyusOGwmbKeJmA=="], - "@docusaurus/cssnano-preset": ["@docusaurus/cssnano-preset@3.10.1", "", { "dependencies": { "cssnano-preset-advanced": "^6.1.2", "postcss": "^8.5.4", "postcss-sort-media-queries": "^5.2.0", "tslib": "^2.6.0" } }, "sha512-eNfHGcTKCSq6xmcavAkX3RRclHaE2xRCMParlDXLdXVP01/a2e/jKXMj/0ULnLFQSNwwuI62L0Ge8J+nZsR7UQ=="], + "@docusaurus/cssnano-preset": ["@docusaurus/cssnano-preset@3.10.2", "", { "dependencies": { "cssnano-preset-advanced": "^6.1.2", "postcss": "^8.5.4", "postcss-sort-media-queries": "^5.2.0", "tslib": "^2.6.0" } }, "sha512-4gCnHRbJLTloiwfvFAa92tgb2gI4KYhvjfQVYnEaiMO/EgvWfCo1LwytHXen+1oZAN0VAlS0JAPxp3MsvKDa3A=="], - "@docusaurus/faster": ["@docusaurus/faster@3.10.1", "", { "dependencies": { "@docusaurus/types": "3.10.1", "@rspack/core": "^1.7.10", "@swc/core": "^1.7.39", "@swc/html": "^1.13.5", "browserslist": "^4.24.2", "lightningcss": "^1.27.0", "semver": "^7.5.4", "swc-loader": "^0.2.6", "tslib": "^2.6.0", "webpack": "^5.95.0" } }, "sha512-XTZhE5C1gZ/DaYYMlSk02dwP5vhpQON5QHVz1s3892mSESAywgWanURpXEDAvt4GvGuq7s+XP8rTWHZvfaJmdQ=="], + "@docusaurus/faster": ["@docusaurus/faster@3.10.2", "", { "dependencies": { "@docusaurus/types": "3.10.2", "@rspack/core": "^1.7.10", "@swc/core": "^1.15.40", "@swc/html": "^1.15.40", "browserslist": "^4.24.2", "lightningcss": "^1.27.0", "semver": "^7.5.4", "swc-loader": "^0.2.6", "tslib": "^2.6.0", "webpack": "^5.95.0" } }, "sha512-p/5E5/RyHv+QWusJMPN5i3OMJTqTgkhuwzVbB1AReDWTUHXQCmf5mlTFzGiDrWeQWIDOKsuOPn1jJh0s9LUOHA=="], - "@docusaurus/logger": ["@docusaurus/logger@3.10.1", "", { "dependencies": { "chalk": "^4.1.2", "tslib": "^2.6.0" } }, "sha512-oPjNFnfJsRCkePVjkGrxWGq4MvJKRQT0r9jOP0eRBTZ7Wr9FAbzdP/Gjs0I2Ss6YRkPoEgygKG112OkE6skvJw=="], + "@docusaurus/logger": ["@docusaurus/logger@3.10.2", "", { "dependencies": { "chalk": "^4.1.2", "tslib": "^2.6.0" } }, "sha512-gSEwqtPfCAnC3ZSJY6xL7tcIfgg0vFD39jbv93eakuweyvO2864xR0K+kmKwBhkTCtWRNjuGGnb5rdmkD/ndqw=="], - "@docusaurus/mdx-loader": ["@docusaurus/mdx-loader@3.10.1", "", { "dependencies": { "@docusaurus/logger": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "@mdx-js/mdx": "^3.0.0", "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", "estree-util-value-to-estree": "^3.0.1", "file-loader": "^6.2.0", "fs-extra": "^11.1.1", "image-size": "^2.0.2", "mdast-util-mdx": "^3.0.0", "mdast-util-to-string": "^4.0.0", "rehype-raw": "^7.0.0", "remark-directive": "^3.0.0", "remark-emoji": "^4.0.0", "remark-frontmatter": "^5.0.0", "remark-gfm": "^4.0.0", "stringify-object": "^3.3.0", "tslib": "^2.6.0", "unified": "^11.0.3", "unist-util-visit": "^5.0.0", "url-loader": "^4.1.1", "vfile": "^6.0.1", "webpack": "^5.88.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-GRmeb/wQ+iXRrFwcHBfgQhrJxGElgCsoTWZYDhccjsZVne1p8MK/EpQVIloXttz76TCe78kKD5AEG9n1xc1oxQ=="], + "@docusaurus/mdx-loader": ["@docusaurus/mdx-loader@3.10.2", "", { "dependencies": { "@docusaurus/logger": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "@mdx-js/mdx": "^3.0.0", "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", "estree-util-value-to-estree": "^3.0.1", "file-loader": "^6.2.0", "fs-extra": "^11.1.1", "image-size": "^2.0.2", "mdast-util-mdx": "^3.0.0", "mdast-util-to-string": "^4.0.0", "rehype-raw": "^7.0.0", "remark-directive": "^3.0.0", "remark-emoji": "^4.0.0", "remark-frontmatter": "^5.0.0", "remark-gfm": "^4.0.0", "stringify-object": "^3.3.0", "tslib": "^2.6.0", "unified": "^11.0.3", "unist-util-visit": "^5.0.0", "url-loader": "^4.1.1", "vfile": "^6.0.1", "webpack": "^5.88.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-9Fd4V/SFjfrVQ0JH5EN0+iPWyFunvTeQE3gfyFeetqPaXMP0OylIjOw16dCuXG4NZJrYdBqwzjh18/h3gRi47w=="], - "@docusaurus/module-type-aliases": ["@docusaurus/module-type-aliases@3.10.1", "", { "dependencies": { "@docusaurus/types": "3.10.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", "@types/react-router-dom": "*", "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-YoOZKUdGlp8xSYhuAkGdSo5Ydkbq4V4eK3sD8v0a2hloxCWdQbNBhkc+Ko9QyjpESc0BYcIGM5iHVAy5hdFV6w=="], + "@docusaurus/module-type-aliases": ["@docusaurus/module-type-aliases@3.10.2", "", { "dependencies": { "@docusaurus/types": "3.10.2", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", "@types/react-router-dom": "*", "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-h/I5e4jaAhDHW4vaLENi1i2hnOEnXY1t9R+nnRTbgUl7ymVRzN/HF7dDfj8rKYGj8gfIge+Ef+iYRAMtbGvsrQ=="], - "@docusaurus/plugin-content-blog": ["@docusaurus/plugin-content-blog@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", "@docusaurus/mdx-loader": "3.10.1", "@docusaurus/theme-common": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "cheerio": "1.0.0-rc.12", "combine-promises": "^1.1.0", "feed": "^4.2.2", "fs-extra": "^11.1.1", "lodash": "^4.17.21", "schema-dts": "^1.1.2", "srcset": "^4.0.0", "tslib": "^2.6.0", "unist-util-visit": "^5.0.0", "utility-types": "^3.10.0", "webpack": "^5.88.1" }, "peerDependencies": { "@docusaurus/plugin-content-docs": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-mmkgE6Q2+K74tnkou7tXlpDLvoCU/qkSa2GSQ3XUiHWvcebCoDQzS670RR3tO8PmaWlIyWWISYWzZLuMfxunRA=="], + "@docusaurus/plugin-content-blog": ["@docusaurus/plugin-content-blog@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/logger": "3.10.2", "@docusaurus/mdx-loader": "3.10.2", "@docusaurus/theme-common": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-common": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "cheerio": "1.0.0-rc.12", "combine-promises": "^1.1.0", "feed": "^4.2.2", "fs-extra": "^11.1.1", "lodash": "^4.17.21", "schema-dts": "^1.1.2", "srcset": "^4.0.0", "tslib": "^2.6.0", "unist-util-visit": "^5.0.0", "utility-types": "^3.10.0", "webpack": "^5.88.1" }, "peerDependencies": { "@docusaurus/plugin-content-docs": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-0cbEnNKf0InmLkhj/+nVRmqEnWEoOE8Mh+2x1qOXI0qYpCnphq4RXknVJ8BvybKRXqYVvbmdMfiJSup+k4tm5w=="], - "@docusaurus/plugin-content-docs": ["@docusaurus/plugin-content-docs@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", "@docusaurus/mdx-loader": "3.10.1", "@docusaurus/module-type-aliases": "3.10.1", "@docusaurus/theme-common": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "schema-dts": "^1.1.2", "tslib": "^2.6.0", "utility-types": "^3.10.0", "webpack": "^5.88.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-2jRVrtzjf8LClGTHQlwlwuD3wQXRx3WEoF7XUarJ8Ou+0onV+SLtejsyfY9JLpfUh9hPhXM4pbBGkyAY4Bi3HQ=="], + "@docusaurus/plugin-content-docs": ["@docusaurus/plugin-content-docs@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/logger": "3.10.2", "@docusaurus/mdx-loader": "3.10.2", "@docusaurus/module-type-aliases": "3.10.2", "@docusaurus/theme-common": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-common": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "schema-dts": "^1.1.2", "tslib": "^2.6.0", "utility-types": "^3.10.0", "webpack": "^5.88.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-Sqwl4FPoZBDrlY8I2VU2H8O0M91CHp9T8ToMSkTZmjvHCif+1laqfXi6sTk8IfyVS/trN5yNjcWd1bFsGB6W5Q=="], - "@docusaurus/plugin-content-pages": ["@docusaurus/plugin-content-pages@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/mdx-loader": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "fs-extra": "^11.1.1", "tslib": "^2.6.0", "webpack": "^5.88.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-huJpaRPMl42nsFwuCXvV8bVDj2MazuwRJIUylI/RSlmZeJssVoZXeCjVf1y+1Drtpa9SKcdGn8yoJ76IRJijtw=="], + "@docusaurus/plugin-content-pages": ["@docusaurus/plugin-content-pages@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/mdx-loader": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "fs-extra": "^11.1.1", "tslib": "^2.6.0", "webpack": "^5.88.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-h5R12sZ/vV9EPiVjvIl9YFCOwkpwXes7dQMYt3EvP6Pphu4amHxxTqWxf08Fl5DR8h+oZMbWpFTNw5vKEYfvzQ=="], - "@docusaurus/plugin-css-cascade-layers": ["@docusaurus/plugin-css-cascade-layers@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "tslib": "^2.6.0" } }, "sha512-r//fn+MNHkE1wCof8T29VAQezt1enGCpsFxoziBbvLgBM4JfXN2P3rxrBaavHmvLvm7lYkpJeitcDthwnmWCTw=="], + "@docusaurus/plugin-css-cascade-layers": ["@docusaurus/plugin-css-cascade-layers@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "tslib": "^2.6.0" } }, "sha512-UkdvQby5OQUKWrw3lLnSTJXQ6VETaUVTuPQX9AABtmFm5h+ifEBx1OQ+LN726Q4byuwBf2ElHkf4qU4hTxdvRg=="], - "@docusaurus/plugin-debug": ["@docusaurus/plugin-debug@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "fs-extra": "^11.1.1", "react-json-view-lite": "^2.3.0", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-9KqOpKNfAyqGZykRb9LhIT/vyRF6sm/ykhjj/39JvaJahDS+jZJE0Z1Wfz9q3DUNDTMNN0Q7u/kk4rKKU+IJuA=="], + "@docusaurus/plugin-debug": ["@docusaurus/plugin-debug@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils": "3.10.2", "fs-extra": "^11.1.1", "react-json-view-lite": "^2.3.0", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-8vbZNOSCpnsT57EY6CgN7sgRVmx3KTYwO8Uvo2pbxOyb8tbqAwtT9SslqaQ41HbA1v1hpn5RP7u5s2KvRwAFpQ=="], - "@docusaurus/plugin-google-analytics": ["@docusaurus/plugin-google-analytics@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-8o0P1KtmgdYQHH+oInitPpRWI0Of5XednAX4+DMhQNSmGSRNrsEEHg1ebv35m9AgRClfAytCJ5jA9KvcASTyuA=="], + "@docusaurus/plugin-google-analytics": ["@docusaurus/plugin-google-analytics@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-kMHMBK9j4VAtgd5owwrRLRIi0EjkrpXlX7ePj1+y68XfVZV9I1T4S+koPDm+Hfw2TtnyHvh0uNrDvjz+DjQGVA=="], - "@docusaurus/plugin-google-gtag": ["@docusaurus/plugin-google-gtag@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "@types/gtag.js": "^0.0.20", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-pu3xIUo5o/zCMLfUY9BO5KOwSH0zIsAGyFRPvXHayFSA5XIhCU/SFuB0g0ZNjFn9niZLCaNvoeAuOGFJZq0fdw=="], + "@docusaurus/plugin-google-gtag": ["@docusaurus/plugin-google-gtag@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-Vt90nNFhtAChRe9+it1hcHFgFvETdSnOkL5Bma+p6E/yU2tAYrvvyk+gv+LJGM2ZUkyKuKXLRsZ2Lb0bO7+Vog=="], - "@docusaurus/plugin-google-tag-manager": ["@docusaurus/plugin-google-tag-manager@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-f6fyGHiCm7kJHBtAisGQS5oNBnpnMTYQZxDXeVrnw/3zWU+LMA22pr6UHGYkBKDbN+qPC5QHG3NuOfzQLq3+Lw=="], + "@docusaurus/plugin-google-tag-manager": ["@docusaurus/plugin-google-tag-manager@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-MLCffCldysi/R0nzJQP7ZWd0xAoGNnSTiVOo6TTR6mKVGFhE+/XArGe67ZcaZv1uytgQXoXs92VJrgVDrz80rQ=="], - "@docusaurus/plugin-sitemap": ["@docusaurus/plugin-sitemap@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "fs-extra": "^11.1.1", "sitemap": "^7.1.1", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-C26MbmmqgdjkDq1htaZ3aD7LzEDKFWXfpyQpt0EOUThuq5nV77zDaedV20yHcVo9p+3ey9aZ4pbHA0D3QcZTzg=="], + "@docusaurus/plugin-sitemap": ["@docusaurus/plugin-sitemap@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/logger": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-common": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "fs-extra": "^11.1.1", "sitemap": "^7.1.1", "tslib": "^2.6.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-PODkwg5XetLML3hU/3xpCKJUZ9cqExLaBnD/Fzzwj2VHogLeqnDisLIujae87zuze7T4mCm2A6KEqZkyiz07EQ=="], - "@docusaurus/plugin-svgr": ["@docusaurus/plugin-svgr@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "@svgr/core": "8.1.0", "@svgr/webpack": "^8.1.0", "tslib": "^2.6.0", "webpack": "^5.88.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-6SFxsmjWFkVLDmBUvFK6i72QjUwqyQFe4Ovz+SUJophJjOyVG3ZZG5IQpBC/kX/Gfv1yWeU9nWauH6F6Q7QX/Q=="], + "@docusaurus/plugin-svgr": ["@docusaurus/plugin-svgr@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "@svgr/core": "8.1.0", "@svgr/webpack": "^8.1.0", "tslib": "^2.6.0", "webpack": "^5.88.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-JgfT3jWM0TJ8Uw0cEcqxHpybngQY1vlBYpuuNO+gEh5iPh5Ar+vxq/u9CFrYsWeXy48BN7Db76Pzp2edNXUQ8A=="], - "@docusaurus/preset-classic": ["@docusaurus/preset-classic@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/plugin-content-blog": "3.10.1", "@docusaurus/plugin-content-docs": "3.10.1", "@docusaurus/plugin-content-pages": "3.10.1", "@docusaurus/plugin-css-cascade-layers": "3.10.1", "@docusaurus/plugin-debug": "3.10.1", "@docusaurus/plugin-google-analytics": "3.10.1", "@docusaurus/plugin-google-gtag": "3.10.1", "@docusaurus/plugin-google-tag-manager": "3.10.1", "@docusaurus/plugin-sitemap": "3.10.1", "@docusaurus/plugin-svgr": "3.10.1", "@docusaurus/theme-classic": "3.10.1", "@docusaurus/theme-common": "3.10.1", "@docusaurus/theme-search-algolia": "3.10.1", "@docusaurus/types": "3.10.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-YO/FL8v1zmbxoTso6mjMz/RDjhaTJxb1UpFFTDdY5847LLDCeyYiYlrhyTbgN1RIN3xnkLKZ9Lj1x8hUzI4JOg=="], + "@docusaurus/preset-classic": ["@docusaurus/preset-classic@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/plugin-content-blog": "3.10.2", "@docusaurus/plugin-content-docs": "3.10.2", "@docusaurus/plugin-content-pages": "3.10.2", "@docusaurus/plugin-css-cascade-layers": "3.10.2", "@docusaurus/plugin-debug": "3.10.2", "@docusaurus/plugin-google-analytics": "3.10.2", "@docusaurus/plugin-google-gtag": "3.10.2", "@docusaurus/plugin-google-tag-manager": "3.10.2", "@docusaurus/plugin-sitemap": "3.10.2", "@docusaurus/plugin-svgr": "3.10.2", "@docusaurus/theme-classic": "3.10.2", "@docusaurus/theme-common": "3.10.2", "@docusaurus/theme-search-algolia": "3.10.2", "@docusaurus/types": "3.10.2" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-a4B3VczmDl99zK0EufDQYomdJ186WDingjmDXxhN2PNPS9Ty/Y2M5CLFX1KQMRKqRTLiRDKfutzG5IY1FC/ceg=="], - "@docusaurus/theme-classic": ["@docusaurus/theme-classic@3.10.1", "", { "dependencies": { "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", "@docusaurus/mdx-loader": "3.10.1", "@docusaurus/module-type-aliases": "3.10.1", "@docusaurus/plugin-content-blog": "3.10.1", "@docusaurus/plugin-content-docs": "3.10.1", "@docusaurus/plugin-content-pages": "3.10.1", "@docusaurus/theme-common": "3.10.1", "@docusaurus/theme-translations": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", "copy-text-to-clipboard": "^3.2.0", "infima": "0.2.0-alpha.45", "lodash": "^4.17.21", "nprogress": "^0.2.0", "postcss": "^8.5.4", "prism-react-renderer": "^2.3.0", "prismjs": "^1.29.0", "react-router-dom": "^5.3.4", "rtlcss": "^4.1.0", "tslib": "^2.6.0", "utility-types": "^3.10.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-VU1RK0qb2pab0si4r7HFK37cYco8VzqLj3u1PspVipSr/z/GPVKHO4/HXbnePqHoWDk8urjyGSeatH0NIMBM1A=="], + "@docusaurus/theme-classic": ["@docusaurus/theme-classic@3.10.2", "", { "dependencies": { "@docusaurus/core": "3.10.2", "@docusaurus/logger": "3.10.2", "@docusaurus/mdx-loader": "3.10.2", "@docusaurus/module-type-aliases": "3.10.2", "@docusaurus/plugin-content-blog": "3.10.2", "@docusaurus/plugin-content-docs": "3.10.2", "@docusaurus/plugin-content-pages": "3.10.2", "@docusaurus/theme-common": "3.10.2", "@docusaurus/theme-translations": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-common": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", "copy-text-to-clipboard": "^3.2.0", "infima": "0.2.0-alpha.45", "lodash": "^4.17.21", "nprogress": "^0.2.0", "postcss": "^8.5.4", "prism-react-renderer": "^2.3.0", "prismjs": "^1.29.0", "react-router-dom": "^5.3.4", "rtlcss": "^4.1.0", "tslib": "^2.6.0", "utility-types": "^3.10.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-JqTSLQmqmA9uKWZsD5iwBGJ4JyKB4/yTw6PsSXVPRJG/6GAm/u+add9Iip+hvwP12/AnPNztrdxsI14NJW4KeA=="], - "@docusaurus/theme-common": ["@docusaurus/theme-common@3.10.1", "", { "dependencies": { "@docusaurus/mdx-loader": "3.10.1", "@docusaurus/module-type-aliases": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", "clsx": "^2.0.0", "parse-numeric-range": "^1.3.0", "prism-react-renderer": "^2.3.0", "tslib": "^2.6.0", "utility-types": "^3.10.0" }, "peerDependencies": { "@docusaurus/plugin-content-docs": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-0YtmIeoNo1fIw65LO8+/1dPgmDV86UmhMkow37gzjytuiCSQm9xob6PJy0L4kuQEMTLfUOGvkXvZr7GPrHquMA=="], + "@docusaurus/theme-common": ["@docusaurus/theme-common@3.10.2", "", { "dependencies": { "@docusaurus/mdx-loader": "3.10.2", "@docusaurus/module-type-aliases": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-common": "3.10.2", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", "clsx": "^2.0.0", "parse-numeric-range": "^1.3.0", "prism-react-renderer": "^2.3.0", "tslib": "^2.6.0", "utility-types": "^3.10.0" }, "peerDependencies": { "@docusaurus/plugin-content-docs": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-R9b/vMpK1yye6hNZTA6x/ivRv+at6GhxnXcxkpzCGzO1R1RwiquqiFg2wMFh6aqlJTpWRFKpFD2TzCDQcyOU0A=="], - "@docusaurus/theme-search-algolia": ["@docusaurus/theme-search-algolia@3.10.1", "", { "dependencies": { "@algolia/autocomplete-core": "^1.19.2", "@docsearch/react": "^3.9.0 || ^4.3.2", "@docusaurus/core": "3.10.1", "@docusaurus/logger": "3.10.1", "@docusaurus/plugin-content-docs": "3.10.1", "@docusaurus/theme-common": "3.10.1", "@docusaurus/theme-translations": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-validation": "3.10.1", "algoliasearch": "^5.37.0", "algoliasearch-helper": "^3.26.0", "clsx": "^2.0.0", "eta": "^2.2.0", "fs-extra": "^11.1.1", "lodash": "^4.17.21", "tslib": "^2.6.0", "utility-types": "^3.10.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-OTaARARVZj2GvkJQjB+1jOIxntRaXea+G+fMsNqrZBAU1O1vJKDW22R7kECOHW27oJCLFN9HKaZeRrfAUyviug=="], + "@docusaurus/theme-search-algolia": ["@docusaurus/theme-search-algolia@3.10.2", "", { "dependencies": { "@algolia/autocomplete-core": "^1.19.2", "@docsearch/react": "^3.9.0 || ^4.3.2", "@docusaurus/core": "3.10.2", "@docusaurus/logger": "3.10.2", "@docusaurus/plugin-content-docs": "3.10.2", "@docusaurus/theme-common": "3.10.2", "@docusaurus/theme-translations": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-validation": "3.10.2", "algoliasearch": "^5.37.0", "algoliasearch-helper": "^3.26.0", "clsx": "^2.0.0", "eta": "^2.2.0", "fs-extra": "^11.1.1", "lodash": "^4.17.21", "tslib": "^2.6.0", "utility-types": "^3.10.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-1msxllyhi/5m77JukXtp5UFnUAriwZIC1oJ7MTnpQpCwLTbclJi5BK5n28CTZuSXpQN2ewbbnqRgAhMM6c6ihg=="], - "@docusaurus/theme-translations": ["@docusaurus/theme-translations@3.10.1", "", { "dependencies": { "fs-extra": "^11.1.1", "tslib": "^2.6.0" } }, "sha512-cLMyaKivjBVWKMJuWqyFVVgtqe8DPJNPkog0bn8W1MDVAKcPdxRFycBfC1We1RaNp7Rdk513bmtW78RR6OBxBw=="], + "@docusaurus/theme-translations": ["@docusaurus/theme-translations@3.10.2", "", { "dependencies": { "fs-extra": "^11.1.1", "tslib": "^2.6.0" } }, "sha512-iv20wrxnyXkY89LM3TzRlzGlt5fIGO5UnaR6UL1ZVfB9RRFjxQFQ6awDrwAc6Km8Y5gD8pInuwYPF+6/TiCxXA=="], - "@docusaurus/tsconfig": ["@docusaurus/tsconfig@3.10.1", "", {}, "sha512-rYvB7yqkdqWIpAbDzQljGfM4cDBkLTbhmagZBEcsyj6oPUsz47lmW2pYdN1j+7sGFgltbAmQH62xfbrij4Eh6Q=="], + "@docusaurus/tsconfig": ["@docusaurus/tsconfig@3.10.2", "", {}, "sha512-5GiB7h/nFsMFPO9mCqcRNE1yA5TSXXNCshNIgHPL6fCPOjcTDixs6qjQBu8ddkgPcicwCvOA7n3jeK2rGdJk6g=="], - "@docusaurus/types": ["@docusaurus/types@3.10.1", "", { "dependencies": { "@mdx-js/mdx": "^3.0.0", "@types/history": "^4.7.11", "@types/mdast": "^4.0.2", "@types/react": "*", "commander": "^5.1.0", "joi": "^17.9.2", "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "utility-types": "^3.10.0", "webpack": "^5.95.0", "webpack-merge": "^5.9.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-XYMK8k1szDCFMw2V+Xyen0g7Kee1sP3dtFnl7vkGkZOkeAJ/oPDQPL8iz4HBKOo/cwU8QeV6onVjMqtP+tFzsw=="], + "@docusaurus/types": ["@docusaurus/types@3.10.2", "", { "dependencies": { "@mdx-js/mdx": "^3.0.0", "@types/history": "^4.7.11", "@types/mdast": "^4.0.2", "@types/react": "*", "commander": "^5.1.0", "joi": "^17.9.2", "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "utility-types": "^3.10.0", "webpack": "^5.95.0", "webpack-merge": "^5.9.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-B6rvfwIFSapUqUJjMriZswX13K8l5Z7AcmVE6uTEJpYddQieSTR12DsGaFtcZAIDsQd4p+0WTl0Vc6jmZK0Trw=="], - "@docusaurus/utils": ["@docusaurus/utils@3.10.1", "", { "dependencies": { "@docusaurus/logger": "3.10.1", "@docusaurus/types": "3.10.1", "@docusaurus/utils-common": "3.10.1", "escape-string-regexp": "^4.0.0", "execa": "^5.1.1", "file-loader": "^6.2.0", "fs-extra": "^11.1.1", "github-slugger": "^1.5.0", "globby": "^11.1.0", "gray-matter": "^4.0.3", "jiti": "^1.20.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "micromatch": "^4.0.5", "p-queue": "^6.6.2", "prompts": "^2.4.2", "resolve-pathname": "^3.0.0", "tslib": "^2.6.0", "url-loader": "^4.1.1", "utility-types": "^3.10.0", "webpack": "^5.88.1" } }, "sha512-3ojeJry9xBYdJO6qoyyzqeJFSJBVx2mXhyDzSdjwL2+URFQMf+h25gG38iswGImicK0ELjTd1EL2xzk8hf3QPw=="], + "@docusaurus/utils": ["@docusaurus/utils@3.10.2", "", { "dependencies": { "@11ty/gray-matter": "^1.0.0", "@docusaurus/logger": "3.10.2", "@docusaurus/types": "3.10.2", "@docusaurus/utils-common": "3.10.2", "escape-string-regexp": "^4.0.0", "execa": "^5.1.1", "file-loader": "^6.2.0", "fs-extra": "^11.1.1", "github-slugger": "^1.5.0", "globby": "^11.1.0", "jiti": "^1.20.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "micromatch": "^4.0.5", "p-queue": "^6.6.2", "prompts": "^2.4.2", "resolve-pathname": "^3.0.0", "tslib": "^2.6.0", "url-loader": "^4.1.1", "utility-types": "^3.10.0", "webpack": "^5.88.1" } }, "sha512-xx0W3eav2uW1NRIpuHJWNwLTC15xPNjU4Uxi9NSnd3swYC96BE3vFiT93SD8s24kmAAWNwgZwfZ2fghGZ01Lcw=="], - "@docusaurus/utils-common": ["@docusaurus/utils-common@3.10.1", "", { "dependencies": { "@docusaurus/types": "3.10.1", "tslib": "^2.6.0" } }, "sha512-5mFSgEADtnFxFH7RLw02QA5MpU5JVUCj0MPeIvi/aF4Fi45tQRIuTwXoXDqJ+1VfQJuYJGz3SI63wmGz4HvXzA=="], + "@docusaurus/utils-common": ["@docusaurus/utils-common@3.10.2", "", { "dependencies": { "@docusaurus/types": "3.10.2", "tslib": "^2.6.0" } }, "sha512-x3Dz6jv6iQKBNjBmVTu8p57abMp/VNTUgKBMgRVXJc5444orBTsArv0+cdfrXTiz/VMmHfDRVkPbL7GH2B7T7w=="], - "@docusaurus/utils-validation": ["@docusaurus/utils-validation@3.10.1", "", { "dependencies": { "@docusaurus/logger": "3.10.1", "@docusaurus/utils": "3.10.1", "@docusaurus/utils-common": "3.10.1", "fs-extra": "^11.2.0", "joi": "^17.9.2", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "tslib": "^2.6.0" } }, "sha512-cRv1X69jwaWv47waglllgZVWzeBFLhl53XT/XED/83BerVBTC5FTP8WTcVl8Z6sZOegDSwitu/wpCSPCDOT6lg=="], + "@docusaurus/utils-validation": ["@docusaurus/utils-validation@3.10.2", "", { "dependencies": { "@docusaurus/logger": "3.10.2", "@docusaurus/utils": "3.10.2", "@docusaurus/utils-common": "3.10.2", "fs-extra": "^11.2.0", "joi": "^17.9.2", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "tslib": "^2.6.0" } }, "sha512-sn8unbDfUL585NtR3cwHefPicOyaHvPaX7VD0aOg/siIxUBoKyKKaGEqzJZDS64mM43TnxurkYDtmB1wsJlZsw=="], "@effect-fc/example": ["@effect-fc/example@workspace:packages/example"], - "@effect/language-service": ["@effect/language-service@0.86.2", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-SaPln+8srOqDJDUwNTDmP5e+IYpEDr9+1epGznnsLqu8xvo6VnxyWARdeLpqvZJlb0Pgy9ca7ppqvvdWbHPXAg=="], + "@effect-fc/example-next": ["@effect-fc/example-next@workspace:packages/example-next"], - "@effect/platform": ["@effect/platform@0.96.1", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.10", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.21.2" } }, "sha512-cjB1QZZYEP8JXCFNGvBLVi0T6YUBQTmOVEUA3SDbiQ6RUO+p6CE3eyD2vMWmrz5nE8yY5QSAuOV9v0boEcUv+A=="], + "@effect-view/vite-plugin": ["@effect-view/vite-plugin@workspace:packages/vite-plugin"], + + "@effect/language-service": ["@effect/language-service@0.86.6", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-uwXbp+lWzt60bZnm6lG6S5DWy0m6TthUzV2hcQoiS6NzieEDm07tuBakscxOXoO+AU9+yTH+0TSIa9mEDt9dFA=="], + + "@effect/platform": ["@effect/platform@0.96.3", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.10", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.21.5" } }, "sha512-LzvIj4HYE++TcTv/cVTCI/GRvQTV0ymwRmgjZMzNB5dU4OS05pTN36RKN0npiOm5orLJgw4yjIv1dNZoYGh/vg=="], "@effect/platform-browser": ["@effect/platform-browser@0.76.0", "", { "dependencies": { "multipasta": "^0.2.7" }, "peerDependencies": { "@effect/platform": "^0.96.0", "effect": "^3.21.0" } }, "sha512-cUyBpcLstrP/HiNsIePMBAI6R1+u6aRFlAUZb4wf08y1d1Vqf/Dmxsq14ZjBfnSYiqBPrCeYf1ZI+qMGQQL0RA=="], - "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + "@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="], - "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + "@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="], - "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], - "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="], - "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.28.1", "", { "os": "android", "cpu": "arm" }, "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ=="], - "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.8", "", { "dependencies": { "@floating-ui/dom": "^1.7.6" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.1", "", { "os": "android", "cpu": "arm64" }, "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg=="], - "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.28.1", "", { "os": "android", "cpu": "x64" }, "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.1", "", { "os": "linux", "cpu": "arm" }, "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.1", "", { "os": "linux", "cpu": "x64" }, "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.1", "", { "os": "none", "cpu": "x64" }, "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.1", "", { "os": "win32", "cpu": "x64" }, "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A=="], + + "@floating-ui/core": ["@floating-ui/core@1.8.0", "", { "dependencies": { "@floating-ui/utils": "^0.2.12" } }, "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.8.0", "", { "dependencies": { "@floating-ui/core": "^1.8.0", "@floating-ui/utils": "^0.2.12" } }, "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg=="], + + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.9", "", { "dependencies": { "@floating-ui/dom": "^1.8.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.12", "", {}, "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww=="], "@hapi/hoek": ["@hapi/hoek@9.3.0", "", {}, "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ=="], @@ -549,21 +676,21 @@ "@jsonjoy.com/codegen": ["@jsonjoy.com/codegen@1.0.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g=="], - "@jsonjoy.com/fs-core": ["@jsonjoy.com/fs-core@4.57.1", "", { "dependencies": { "@jsonjoy.com/fs-node-builtins": "4.57.1", "@jsonjoy.com/fs-node-utils": "4.57.1", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-YrEi/ZPmgc+GfdO0esBF04qv8boK9Dg9WpRQw/+vM8Qt3nnVIJWIa8HwZ/LXVZ0DB11XUROM8El/7yYTJX+WtA=="], + "@jsonjoy.com/fs-core": ["@jsonjoy.com/fs-core@4.64.0", "", { "dependencies": { "@jsonjoy.com/fs-node-builtins": "4.64.0", "@jsonjoy.com/fs-node-utils": "4.64.0", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-zs2TAq7Six5jgMuoMNjpspAvOP3mhtgq/k1UyQodEzCtQi/N83y2/y+zcvnZSGp/Rxq96DBN+bValOBQAyn/ew=="], - "@jsonjoy.com/fs-fsa": ["@jsonjoy.com/fs-fsa@4.57.1", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.57.1", "@jsonjoy.com/fs-node-builtins": "4.57.1", "@jsonjoy.com/fs-node-utils": "4.57.1", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-ooEPvSW/HQDivPDPZMibHGKZf/QS4WRir1czGZmXmp3MsQqLECZEpN0JobrD8iV9BzsuwdIv+PxtWX9WpPLsIA=="], + "@jsonjoy.com/fs-fsa": ["@jsonjoy.com/fs-fsa@4.64.0", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.64.0", "@jsonjoy.com/fs-node-builtins": "4.64.0", "@jsonjoy.com/fs-node-utils": "4.64.0", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-nMWOVbkLFyEgmXZih3wyvxA9XpgyyqyfrINMHvEFqhi7uqfRl7c9ERJt6yX7vgMPrB9Uo+OJO+Spa0cFzPD01w=="], - "@jsonjoy.com/fs-node": ["@jsonjoy.com/fs-node@4.57.1", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.57.1", "@jsonjoy.com/fs-node-builtins": "4.57.1", "@jsonjoy.com/fs-node-utils": "4.57.1", "@jsonjoy.com/fs-print": "4.57.1", "@jsonjoy.com/fs-snapshot": "4.57.1", "glob-to-regex.js": "^1.0.0", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-3YaKhP8gXEKN+2O49GLNfNb5l2gbnCFHyAaybbA2JkkbQP3dpdef7WcUaHAulg/c5Dg4VncHsA3NWAUSZMR5KQ=="], + "@jsonjoy.com/fs-node": ["@jsonjoy.com/fs-node@4.64.0", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.64.0", "@jsonjoy.com/fs-node-builtins": "4.64.0", "@jsonjoy.com/fs-node-utils": "4.64.0", "@jsonjoy.com/fs-print": "4.64.0", "@jsonjoy.com/fs-snapshot": "4.64.0", "glob-to-regex.js": "^1.0.0", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-dO+NNkODbUli4uV42bcNrrLvq5rE7SNpdZ5TNd0dtbLsAaNK3MDiIC9lUi+brboGoIjW6vd2fB1qao60nrk5xA=="], - "@jsonjoy.com/fs-node-builtins": ["@jsonjoy.com/fs-node-builtins@4.57.1", "", { "peerDependencies": { "tslib": "2" } }, "sha512-XHkFKQ5GSH3uxm8c3ZYXVrexGdscpWKIcMWKFQpMpMJc8gA3AwOMBJXJlgpdJqmrhPyQXxaY9nbkNeYpacC0Og=="], + "@jsonjoy.com/fs-node-builtins": ["@jsonjoy.com/fs-node-builtins@4.64.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-/o7WRFhUWaM/fOrslwLZGnzn4RmRILykn+lAL+mNObqqRNw+CQSiij6hpCeZ+C7buhdoVo7go/OYqzaSUfDYmA=="], - "@jsonjoy.com/fs-node-to-fsa": ["@jsonjoy.com/fs-node-to-fsa@4.57.1", "", { "dependencies": { "@jsonjoy.com/fs-fsa": "4.57.1", "@jsonjoy.com/fs-node-builtins": "4.57.1", "@jsonjoy.com/fs-node-utils": "4.57.1" }, "peerDependencies": { "tslib": "2" } }, "sha512-pqGHyWWzNck4jRfaGV39hkqpY5QjRUQ/nRbNT7FYbBa0xf4bDG+TE1Gt2KWZrSkrkZZDE3qZUjYMbjwSliX6pg=="], + "@jsonjoy.com/fs-node-to-fsa": ["@jsonjoy.com/fs-node-to-fsa@4.64.0", "", { "dependencies": { "@jsonjoy.com/fs-fsa": "4.64.0", "@jsonjoy.com/fs-node-builtins": "4.64.0", "@jsonjoy.com/fs-node-utils": "4.64.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-WDD9WVs0hb7UAEKTgZW2f66WDrbj7gIIWwpP3spbLyXa0rghtUaFTB8L4gdR3ZCWwiKIsj38/CNijpVmpnuPUw=="], - "@jsonjoy.com/fs-node-utils": ["@jsonjoy.com/fs-node-utils@4.57.1", "", { "dependencies": { "@jsonjoy.com/fs-node-builtins": "4.57.1" }, "peerDependencies": { "tslib": "2" } }, "sha512-vp+7ZzIB8v43G+GLXTS4oDUSQmhAsRz532QmmWBbdYA20s465JvwhkSFvX9cVTqRRAQg+vZ7zWDaIEh0lFe2gw=="], + "@jsonjoy.com/fs-node-utils": ["@jsonjoy.com/fs-node-utils@4.64.0", "", { "dependencies": { "@jsonjoy.com/fs-node-builtins": "4.64.0", "glob-to-regex.js": "^1.0.1" }, "peerDependencies": { "tslib": "2" } }, "sha512-k5Indsx9hWW9xSF7Y6oSKKwtCUNhzZxadub3owhIlitc+iMRVlPPdX2duTKQWBL3qNWpXya8jykgaaWpheeS4w=="], - "@jsonjoy.com/fs-print": ["@jsonjoy.com/fs-print@4.57.1", "", { "dependencies": { "@jsonjoy.com/fs-node-utils": "4.57.1", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-Ynct7ZJmfk6qoXDOKfpovNA36ITUx8rChLmRQtW08J73VOiuNsU8PB6d/Xs7fxJC2ohWR3a5AqyjmLojfrw5yw=="], + "@jsonjoy.com/fs-print": ["@jsonjoy.com/fs-print@4.64.0", "", { "dependencies": { "@jsonjoy.com/fs-node-utils": "4.64.0", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-PHZFccchvkhWrwPWHjmVAhbC3vSHCtyZvlZfJJ3ho2bnzl450hXri6/8e6pbkWdH+SkmLXNml0sV8e5HDAfxKw=="], - "@jsonjoy.com/fs-snapshot": ["@jsonjoy.com/fs-snapshot@4.57.1", "", { "dependencies": { "@jsonjoy.com/buffers": "^17.65.0", "@jsonjoy.com/fs-node-utils": "4.57.1", "@jsonjoy.com/json-pack": "^17.65.0", "@jsonjoy.com/util": "^17.65.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-/oG8xBNFMbDXTq9J7vepSA1kerS5vpgd3p5QZSPd+nX59uwodGJftI51gDYyHRpP57P3WCQf7LHtBYPqwUg2Bg=="], + "@jsonjoy.com/fs-snapshot": ["@jsonjoy.com/fs-snapshot@4.64.0", "", { "dependencies": { "@jsonjoy.com/buffers": "^17.65.0", "@jsonjoy.com/fs-node-utils": "4.64.0", "@jsonjoy.com/json-pack": "^17.65.0", "@jsonjoy.com/util": "^17.65.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-oM7UDeL83q6NBzzsfKAsYKXKVXlykKFqqOLh4xZZKAzzROTlInkPbc6LTDGThEOnPiFiUzA7tYziHG9xavd76Q=="], "@jsonjoy.com/json-pack": ["@jsonjoy.com/json-pack@1.21.0", "", { "dependencies": { "@jsonjoy.com/base64": "^1.1.2", "@jsonjoy.com/buffers": "^1.2.0", "@jsonjoy.com/codegen": "^1.0.0", "@jsonjoy.com/json-pointer": "^1.0.2", "@jsonjoy.com/util": "^1.9.0", "hyperdyperid": "^1.2.0", "thingies": "^2.5.0", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg=="], @@ -589,19 +716,19 @@ "@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.22.0", "", { "dependencies": { "@module-federation/runtime": "0.22.0", "@module-federation/sdk": "0.22.0" } }, "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA=="], - "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="], + "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="], - "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="], + "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="], - "@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3", "", { "os": "linux", "cpu": "arm" }, "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw=="], + "@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4", "", { "os": "linux", "cpu": "arm" }, "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw=="], - "@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg=="], + "@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw=="], - "@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg=="], + "@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ=="], - "@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.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg=="], "@noble/hashes": ["@noble/hashes@1.4.0", "", {}, "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg=="], @@ -611,27 +738,29 @@ "@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=="], - "@oxc-project/types": ["@oxc-project/types@0.133.0", "", {}, "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA=="], + "@oxc-project/types": ["@oxc-project/types@0.139.0", "", {}, "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw=="], - "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "@peculiar/asn1-x509-attr": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw=="], + "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "@peculiar/asn1-x509-attr": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-NgekZOrSJFSBFLFoLfwePguAWAx7z1+f2TEsWFUMyiqqfntZ4+S/S5hzqME3q4pCA0iOsFKdwiQ35dwY24eVqA=="], - "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w=="], + "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-akbF8+uvleHs8sejNPQxwmVFuInAg6FMNHOwMILXfP518YfFJwdR3jr6oNUPOaEJfuEhn/vkNOCIT6ASUd4mbg=="], - "@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g=="], + "@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-ohwlk+u9Rv2NOAY1c6MfHj45ATVF8R1DUN/WCgABiRtLi2ZftlZWZX7KvpAbU8v9xPcmoILfELeEABj/rn18AQ=="], - "@peculiar/asn1-pfx": ["@peculiar/asn1-pfx@2.6.1", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.1", "@peculiar/asn1-pkcs8": "^2.6.1", "@peculiar/asn1-rsa": "^2.6.1", "@peculiar/asn1-schema": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw=="], + "@peculiar/asn1-pfx": ["@peculiar/asn1-pfx@2.8.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.8.0", "@peculiar/asn1-pkcs8": "^2.8.0", "@peculiar/asn1-rsa": "^2.8.0", "@peculiar/asn1-schema": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-5yof1ytoB++RQtaFbqSUJ8pxDJtZT6vbVqZ8XoJ61ph7UjNVvfFwAilnCodqkNsAodpy13gDhoxZXw00pghnyg=="], - "@peculiar/asn1-pkcs8": ["@peculiar/asn1-pkcs8@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw=="], + "@peculiar/asn1-pkcs8": ["@peculiar/asn1-pkcs8@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-qAKXtLpBEw9LqhKpjw3ajZSXlBur+ipW+y2ivVBQAG6F6qRx94yO+1ZR4mvw+YaCfKSaOzLeYEzsPaBp4SJELA=="], - "@peculiar/asn1-pkcs9": ["@peculiar/asn1-pkcs9@2.6.1", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.1", "@peculiar/asn1-pfx": "^2.6.1", "@peculiar/asn1-pkcs8": "^2.6.1", "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "@peculiar/asn1-x509-attr": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw=="], + "@peculiar/asn1-pkcs9": ["@peculiar/asn1-pkcs9@2.8.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.8.0", "@peculiar/asn1-pfx": "^2.8.0", "@peculiar/asn1-pkcs8": "^2.8.0", "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "@peculiar/asn1-x509-attr": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-b5nDWCnkV60+cQ141D6sVVwK9nz64R5n3zSVnklGd+ECdkW2Ol3U1a6yYFlalpSOaD557yuJB64A+q42jG7lUQ=="], - "@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA=="], + "@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-zHEUlCqB2mk7x2lxDwHHJy7hWZOPdGHVlsmITWKB5/PbQo61atbu9PJ/0r9dQNMwFzbKPXZ8uK8/91eUhRznSg=="], - "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.6.0", "", { "dependencies": { "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg=="], + "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.8.0", "", { "dependencies": { "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q=="], - "@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA=="], + "@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-N0CMuhWUzsWEVq6F1q9X6+VKUnWzSW+cSVg+aPaGGwDdbFoFWTYgin5MHwXgpWd6y9COMBxnfy/Qc+Xc7F0Zwg=="], - "@peculiar/asn1-x509-attr": ["@peculiar/asn1-x509-attr@2.6.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ=="], + "@peculiar/asn1-x509-attr": ["@peculiar/asn1-x509-attr@2.8.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.8.0", "@peculiar/asn1-x509": "^2.8.0", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-tHjkfS/qhMnmrlB2J9NhflQlQ7In3khO3CfmVrriOlpTeErY9ZIKOso1hQ5JQiyrJ7ShvqVPk7E5fQmbclkSKA=="], + + "@peculiar/utils": ["@peculiar/utils@2.0.3", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ=="], "@peculiar/x509": ["@peculiar/x509@1.14.3", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.0", "@peculiar/asn1-csr": "^2.6.0", "@peculiar/asn1-ecc": "^2.6.0", "@peculiar/asn1-pkcs9": "^2.6.0", "@peculiar/asn1-rsa": "^2.6.0", "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "pvtsutils": "^1.3.6", "reflect-metadata": "^0.2.2", "tslib": "^2.8.1", "tsyringe": "^4.10.0" } }, "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA=="], @@ -639,189 +768,239 @@ "@pnpm/network.ca-file": ["@pnpm/network.ca-file@1.0.2", "", { "dependencies": { "graceful-fs": "4.2.10" } }, "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA=="], - "@pnpm/npm-conf": ["@pnpm/npm-conf@3.0.2", "", { "dependencies": { "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", "config-chain": "^1.1.11" } }, "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA=="], + "@pnpm/npm-conf": ["@pnpm/npm-conf@3.0.3", "", { "dependencies": { "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", "config-chain": "^1.1.11" } }, "sha512-//0sR/cow/s4ICQaYoAobOl4aU8cjU6x/V24V7XkKotb9+O+3zySIYp146vpaobYHnxa4pZX8NkV54Z5AwbDKA=="], "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], "@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.2", "", {}, "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig=="], - "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.5", "", {}, "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg=="], - "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@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-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="], + "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.11", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.7" }, "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-HQDOFTKwSnmUij6l54wYJJtxTAnxI71+YJLOrjm2ladFB8HAV5Jt7hwaZPhWTGBkYoW4+ZAOfNZrLDh/qvxSYA=="], - "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.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-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collapsible": "1.1.16", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "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-BpZJNmetujnGgUI6OX0jEhEmlA46WPqgub8Rv09Kyquwd0cc1ndMKpiPYCjmBU6KSSRPAMtgLpEoZSG/tdNIWQ=="], - "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "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-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="], + "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-dialog": "1.1.19", "@radix-ui/react-primitive": "2.1.7" }, "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-FA7n1f6D/DwGE0+AWxiY5LacNbbExQuEgMubeG06idEaH+mSLuf9dp/qBNqOnvbTQ+4gZ2ue1RATF1Ub91Mg5g=="], - "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.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-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7" }, "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-Kdil9BB1rIFC/khmf4hC35bn8701AJcizTU7G7cUbEbk5XqqbjDuHW60uUfKqO5WojjZcbAW51Q7P0hRmMLw8A=="], - "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.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-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="], + "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7" }, "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-IUAhIVpBUvP5NNICjlaB1OFmtRLGqQqTF3ZOSGPoq3XeLXRFtHiWTRxSVEULgOd9GQR2c7tsYqDnhUennapZnw=="], - "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="], + "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.2.2", "", { "dependencies": { "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-is-hydrated": "0.1.1", "@radix-ui/react-use-layout-effect": "1.1.2" }, "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-sST0qh8GzOB7besQ3tMLWLyngnRuSk0gc/Hm+667KYKQFCt6Y6ZXv25WlqM7dIDK54ULCh5+CHmk4LIolzfz+A=="], - "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "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-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="], + "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "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-JroKHfQBfh+fDuzpPsBC+pESkhuq8ql4hljTguz8MWnS35cISr3d/Jhl9kYrB44FlDtxCArYdDvTx+BSsJ64rQ=="], - "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2" }, "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-opfXRe6nnzyGmCDPx+l1Aqo/RbqWtQal2FnsBqF9hhePp6j0LsRoBaRxcMOlTv+uYTJVtWYZKg9t9wTe+BA/ZA=="], - "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "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-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.12", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0" }, "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-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q=="], - "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="], - "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + "@radix-ui/react-context": ["@radix-ui/react-context@1.2.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg=="], - "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="], + "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-menu": "2.1.20", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "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-PS+gKE0z2prJ74Y0sM+brAGK4mYOHIR7TlcV5EJgUQ6E0xMvyswkK2X4yRqyganrzsRL+WCSKAPu0NQITICRWg=="], - "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.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-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.12", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "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-+HhbN2+YtkRgVirjZ2afMeutQRuGOrdkWR5+EFC58SJojGmtyNQwYzgi6tHBpOxvFHefMtPeHdgtjz0BOGxFQg=="], - "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA=="], - "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "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-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-effect-event": "0.0.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-b0XaRlzn2QKuo10XyNgi2DAJDf5XC9d1nD3FJcuvCjbR7+4Ad28zmZsLsqx+hvDEzMnRuZaZxZm9gYObV6RmRA=="], - "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="], + "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.20", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-menu": "2.1.20", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "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-slfm+rRaZRuQBvHq60lXvSVUPhid0IPtjSZzIuUlWZMUs01iYZNlGS3mJgRD3ChLQVBAYlKiL/tFyWGX+dz8Xw=="], - "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q=="], - "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "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-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.12", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2" }, "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-jjk/lqTeNL0azUx5ZYzVrl4NgaDIrdzTNE4mABV9yBFI7FQqN7pIgzV1bTleUezP2QiTGA1BFTqY8MegDgWX9A=="], - "@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.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-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="], + "@radix-ui/react-form": ["@radix-ui/react-form@0.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-label": "2.1.11", "@radix-ui/react-primitive": "2.1.7" }, "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-JTX94E4LDL91rzLg7X0mHPdxr0A8JEdVwZEmeOwZJSMDHCGW5DFtSlTSJozUyUs807IQmnvbfzKZFVCK5DmkqQ=="], - "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@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-use-controllable-state": "1.2.2" }, "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-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="], + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-popper": "1.3.3", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "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-2KTgMLQtKvicznQgbindEI2RZ3QbDIwU5gabjUPwFJsormjGDz+rUvO4NANmYwzEEpTcTONUt33vBHIfTIVSfw=="], - "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="], - "@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.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-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], + "@radix-ui/react-label": ["@radix-ui/react-label@2.1.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7" }, "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-3PKvDDxOn62k0oV1n4QtNtD2vpu+zYjXR7ojLBPaO6SPvhy53yg0vAmgNeBQeJW5rV3dffoRG+HYfLBZuzw0CQ=="], - "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@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-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@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-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.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-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="], + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.20", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.12", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.3", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-callback-ref": "1.1.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "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-VsUrXxFe9d2ScbZF0fR/oPR1+qjyeLs5p0jzG8h90puMoA9bq4SirYlXbE+USRg9Q2qTeJSFNqjw2nts8jJe4w=="], - "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@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-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="], + "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.20", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-menu": "2.1.20", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-use-controllable-state": "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-gzFZvybgmwYsFBWDqanycIoEYnhyk8MMnuLamdFVHUZYGp4COM+sqXiwbnn0VMWqGLeeU7GV7jm+dXRa+Wufag=="], - "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@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-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "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-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.18", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-visually-hidden": "1.2.7" }, "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-K9HiuxZ6xCwSaHcIuUpxyhy4w5gpwzWjh9dHTSbMN3Ix4qAyVObS9RlU3zMycb0PO3v9Tpk0BXMwWvXOUbVXew=="], - "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@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-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="], + "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.12", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-is-hydrated": "0.1.1", "@radix-ui/react-use-layout-effect": "1.1.2" }, "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-nQLu5OAcORDQp1EHAv6k3mJGV1hjMTw2NTGVAsGE1g/mWeNqAd1R5jyaAs3U+A8ZD/W8XNPY2yKT0ZdQnqo3NA=="], - "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "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-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="], + "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-is-hydrated": "0.1.1" }, "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-gB1Mr8vzdv1XzDjrtJTXmL0JORRs1B4g7ngUs0F+H2VvMOwXTZMTmLCl0wZZ3m7ylX8TssI7NCvgiSHmLuTm/A=="], - "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@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-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.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-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.12", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.3", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "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-jkrTdQVxnIB8fpn0NyyxW9CTB5aCXZZelVz5z+Xmii6g5WxMqS3fInNslZ63puP39+Puu4jYohUK31y3dT87gQ=="], - "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "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-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.3.3", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.11", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-rect": "1.1.2", "@radix-ui/react-use-size": "1.1.2", "@radix-ui/rect": "1.1.2" }, "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-mS7dGpyjv6b+gsDjLF7e0ia1W4Im1B1hSCy2yuXlHuvnZxHKagfDaobt/KAKt27EpZMit2pss8eJBVyVjEWM+g=="], - "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.13", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-layout-effect": "1.1.2" }, "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-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA=="], - "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.7", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "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-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA=="], - "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "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-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.7", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "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-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ=="], - "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.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-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="], + "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.12", "", { "dependencies": { "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7" }, "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-ZPHyI0JyzoH/rP0tq2uRaIZTj/4s8+kAbqPz+e2N8+ejHvwPJ889dHhqn+vh7PNvNeq+boAoH9yzqeoShzwF2w=="], - "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "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-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="], + "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "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-WwZFjWV4s3aC1QtR3k04R+oANHtX2q6fgKlc7MCEiDNlnTxCZ3H8k3mHtEgVlOejystwk1WQgarQhNOQZ2bK1g=="], - "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@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-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-is-hydrated": "0.1.1", "@radix-ui/react-use-layout-effect": "1.1.2" }, "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-40svmmugfM3mUN7VUDGVE1tQGOhyi8enlGD0CNJEcMM36C1f71PKM21DFgNHUfem0XnA+d8H8oN3Z9ZpJjSslg=="], - "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "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-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], + "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.14", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.2" }, "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-bBODCWZK7JTbQLHs0uIP4f73wIWatakK4OS33UzkR1x897wu0PuO658a3f+6P2GEGyDzGYMuHRatMVoAk9WZTw=="], - "@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@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-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.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-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="], + "@radix-ui/react-select": ["@radix-ui/react-select@2.3.3", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.12", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.3", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-visually-hidden": "1.2.7", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "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-L5RQTXz6Anxsf9CCv+pTgiAsUpyVj7rJxsGtmhFaEOJ++cVfXucv4qWfsIO0AIB4NAhi3yovWGVMKKS1Xf1Wrg=="], - "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.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-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], + "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7" }, "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-jRhe86+8PF7VZ1u14eOWVOuh2BuAhALg/FT1VcMC4OHedMTRUazDnDlKTt+yxo5cRNKHMfmvZ4sSQtWDeMV4CQ=="], - "@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@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-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "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-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="], + "@radix-ui/react-slider": ["@radix-ui/react-slider@1.4.3", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "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-CWVVj+XaTom0SKCqw1EUgb0NuiLwS+N3OFG73mVEezKEjgNIvZiu0EevMelSSU+CbX3owbqJweG2gPU31WGC5A=="], - "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="], - "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "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-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="], + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "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-1+mlB4/lxJfk5tgJ4g+R5mUCbRpPE1T9+UsEyeLYbGgMtwiMgmuTnfKz4Mw1nHALHjuwyxw4MLd4cSHn6pNSlQ=="], - "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.17", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-use-controllable-state": "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-nRyXnrAVCwjeXcHbvEbLS6ndbTeKHG1RqCP4A8Gw5L4cemDzPXdD8rAmr6wet0v57R69wGvuIIsFjHSVkZiMzQ=="], - "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@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-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "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-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="], + "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.19", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-visually-hidden": "1.2.7" }, "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-SxfVZfVOibWKWdkf0Xx1awW2d09fQu4V4PXDY1j5hi4MVf7MWdJZqTBJMa1KWtOr1S6GGtCk02nniZ0Iia+dHw=="], - "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="], + "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-use-controllable-state": "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-QI/hB65XKWACA66P64A+aHxtLUgHJeJLkaQa+awUNXT6T3swndtY5DojeHA+vldrTspMTtFBd7HfZ9QGbM1Qrw=="], - "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="], + "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-toggle": "1.1.14", "@radix-ui/react-use-controllable-state": "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-gIC5Q+Xljg7lmUdzSuDoy0t97yZn1sZl00Ra37ZvKrYdWnQLU6sWLd09yG8cIB9jUAlQfHgJ2ACAG00MFwsqSQ=="], - "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "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-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="], + "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-separator": "1.1.11", "@radix-ui/react-toggle-group": "1.1.15" }, "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-t/iEuVjUnXXtrsGK40AA43uIx37sn3AqZ7oAVnPICK6lFJP6dzMzWR3U9b6eCfFjb6wtSEqkJ9Rn9xDjiOx20g=="], - "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@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-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@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-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.3", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-visually-hidden": "1.2.7" }, "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-U3HoftgWnmla78vzQbLvKKb7bUYJxoiiqYFzp1wu/TBMyDqMZSuCl3aRICsD6EfVEwcJD2mumGDGUXLFVqQHKA=="], - "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="], - "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.3", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA=="], - "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.3", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA=="], - "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.3", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-3wEkMiPHXha/2VadZ68rYBcmYnPINVGl4Y3gtcM7fKRjANk0OscK+cdqBgUWdozb7YJxsh0vefM7vgAMHXOjqg=="], - "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="], + "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A=="], - "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA=="], - "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], + "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw=="], - "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="], + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.2", "", { "dependencies": { "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw=="], - "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w=="], - "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.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-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="], + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.7" }, "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-1wNZBggTDK3GRuuQ6nP4k2yi7a6l7I5qbMPbZcRsrGsGVead/f/d5FhEzUvqFs0bcrDLx7n1zKQ3JvLR6whaaw=="], - "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], + "@radix-ui/rect": ["@radix-ui/rect@1.1.2", "", {}, "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA=="], "@radix-ui/themes": ["@radix-ui/themes@3.3.0", "", { "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-I0/h2CRNTpYNB7Mi3xFIvSsQq5a108d7kK8dTO5zp5b9HR5QJXKag6B8tjpz2ITkVYkFdkGk45doNkSr7OxwNw=="], - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.3", "", { "os": "android", "cpu": "arm64" }, "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw=="], + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.1.5", "", { "os": "android", "cpu": "arm64" }, "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ=="], - "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA=="], + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.1.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw=="], - "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg=="], + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.1.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g=="], - "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g=="], + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.1.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA=="], - "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.3", "", { "os": "linux", "cpu": "arm" }, "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw=="], + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.1.5", "", { "os": "linux", "cpu": "arm" }, "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw=="], - "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw=="], + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.1.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q=="], - "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q=="], + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.1.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA=="], - "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg=="], + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.1.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg=="], - "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg=="], + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.1.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA=="], - "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg=="], + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.1.5", "", { "os": "linux", "cpu": "x64" }, "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ=="], - "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow=="], + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.1.5", "", { "os": "linux", "cpu": "x64" }, "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg=="], - "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg=="], + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.1.5", "", { "os": "none", "cpu": "arm64" }, "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw=="], - "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.3", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg=="], + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.1.5", "", { "dependencies": { "@emnapi/core": "1.11.1", "@emnapi/runtime": "1.11.1", "@napi-rs/wasm-runtime": "^1.1.6" }, "cpu": "none" }, "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA=="], - "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g=="], + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.1.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw=="], - "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA=="], + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.1.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="], - "@rspack/binding": ["@rspack/binding@1.7.11", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.7.11", "@rspack/binding-darwin-x64": "1.7.11", "@rspack/binding-linux-arm64-gnu": "1.7.11", "@rspack/binding-linux-arm64-musl": "1.7.11", "@rspack/binding-linux-x64-gnu": "1.7.11", "@rspack/binding-linux-x64-musl": "1.7.11", "@rspack/binding-wasm32-wasi": "1.7.11", "@rspack/binding-win32-arm64-msvc": "1.7.11", "@rspack/binding-win32-ia32-msvc": "1.7.11", "@rspack/binding-win32-x64-msvc": "1.7.11" } }, "sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.62.2", "", { "os": "android", "cpu": "arm" }, "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg=="], - "@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@1.7.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.62.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw=="], - "@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@1.7.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.62.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A=="], - "@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@1.7.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.62.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA=="], - "@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@1.7.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.62.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw=="], - "@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@1.7.11", "", { "os": "linux", "cpu": "x64" }, "sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.62.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg=="], - "@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@1.7.11", "", { "os": "linux", "cpu": "x64" }, "sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.62.2", "", { "os": "linux", "cpu": "arm" }, "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg=="], - "@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@1.7.11", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.0.7" }, "cpu": "none" }, "sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.62.2", "", { "os": "linux", "cpu": "arm" }, "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA=="], - "@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@1.7.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.62.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA=="], - "@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@1.7.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.62.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ=="], - "@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@1.7.11", "", { "os": "win32", "cpu": "x64" }, "sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg=="], - "@rspack/core": ["@rspack/core@1.7.11", "", { "dependencies": { "@module-federation/runtime-tools": "0.22.0", "@rspack/binding": "1.7.11", "@rspack/lite-tapable": "1.1.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" }, "optionalPeers": ["@swc/helpers"] }, "sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew=="], + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.62.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.62.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.62.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.62.2", "", { "os": "linux", "cpu": "x64" }, "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.62.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.62.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.62.2", "", { "os": "none", "cpu": "arm64" }, "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.62.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.62.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA=="], + + "@rspack/binding": ["@rspack/binding@1.7.12", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.7.12", "@rspack/binding-darwin-x64": "1.7.12", "@rspack/binding-linux-arm64-gnu": "1.7.12", "@rspack/binding-linux-arm64-musl": "1.7.12", "@rspack/binding-linux-x64-gnu": "1.7.12", "@rspack/binding-linux-x64-musl": "1.7.12", "@rspack/binding-wasm32-wasi": "1.7.12", "@rspack/binding-win32-arm64-msvc": "1.7.12", "@rspack/binding-win32-ia32-msvc": "1.7.12", "@rspack/binding-win32-x64-msvc": "1.7.12" } }, "sha512-f4HHuLbvuld8Ba4iB/4ibse5XrKxFrgmM3S4P2AOKnPlekAFlBjmltCuaTL/W2ggYvILaVY+YcFXrEH1rrKeQA=="], + + "@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@1.7.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rbFprJaJiqrmfy8SHth8EsoRS0wg4bXcucwj9NiMzpGFq14Opw8c04iQ6H9BECYzgmN0PKZ9rh41LdVvhdZe4A=="], + + "@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@1.7.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-jnOp+/UXOJa9xqUb8KXH03sysoO2e4Ij6tw6MqDdmdj8n/A8PQENRPUbW9AwXpPtVDJPus9r4fi7b3+6e4B8Hg=="], + + "@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@1.7.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-C8owWG+yvo7X0oVLIXetkoJhIFBP1LYNcAQqtgLmJnQLQDklGuP83dKC+zISGQWpjawHfZ1ER96vLgoTrxKZdw=="], + + "@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@1.7.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-i51WWI64aRpsfSki6rN0aepPqXkVfS+vZM7+4bWDcmnhUmdMvhIPcYg0QRk3DtyJnu33jqNLM0WHY78k00NyfA=="], + + "@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@1.7.12", "", { "os": "linux", "cpu": "x64" }, "sha512-MSos0FuPEefqo9V92ULd5hggKG29EkSNg1zDcypy0OkpsKh5pfjVxTLYFXgTcVyFoUQQbdG8zFBzYbwmJ8V4ew=="], + + "@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@1.7.12", "", { "os": "linux", "cpu": "x64" }, "sha512-JcAMVKXOnjfpC3coWjCFPWD3Yl8RBw6a+IXQQ8mfRlHaHMIiOv8IfZqx15XRxMUn49CtP7Z0Na8iiAg2aKrcfw=="], + + "@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@1.7.12", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.0.7" }, "cpu": "none" }, "sha512-n+ZqP6ZMc0nhOgvadg5VhEs9ojtbES80AcWeFnmGkbzIszvGSO63GKNiRkXtjJ9KFuRzytbbmsCqkUVH+Tywxg=="], + + "@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@1.7.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-8+h5fYDXYdmugbdfZ+D1y8IQ3rv2EhSfyGP7vBe+bjNyaMa4jWrpucmZbtxojUL1AzaeuHbvMdj9UO/gelk/+g=="], + + "@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@1.7.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-cDMGwTRSa2p9fNBVe1wTRkF2AEXZ9ARWW36QeC5CkLaI0Ezz8lvhF2+CSOPnhaQ1O1qtn0L0SF+lFnrY+I7xGQ=="], + + "@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@1.7.12", "", { "os": "win32", "cpu": "x64" }, "sha512-wIqFvlgFqrgUyj/6S/FJcvShnkZOmIeXTfqvheLY67MGq8qd8jb1YimQVKAIrmWB3yuJKUFACI3Ag1UBtEedEA=="], + + "@rspack/core": ["@rspack/core@1.7.12", "", { "dependencies": { "@module-federation/runtime-tools": "0.22.0", "@rspack/binding": "1.7.12", "@rspack/lite-tapable": "1.1.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" }, "optionalPeers": ["@swc/helpers"] }, "sha512-6CwFIHlhRmXfZoMj3v9MZ1SMTPBn+cHVXeMIeaGp5sufqinKsISbsqHu6ZMJu2wDSmZLdmQJX6zLxkhcAUlhkQ=="], "@rspack/lite-tapable": ["@rspack/lite-tapable@1.1.0", "", {}, "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw=="], @@ -831,7 +1010,7 @@ "@sideway/pinpoint": ["@sideway/pinpoint@2.0.0", "", {}, "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ=="], - "@sinclair/typebox": ["@sinclair/typebox@0.27.10", "", {}, "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA=="], + "@sinclair/typebox": ["@sinclair/typebox@0.27.12", "", {}, "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g=="], "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], @@ -867,129 +1046,133 @@ "@svgr/webpack": ["@svgr/webpack@8.1.0", "", { "dependencies": { "@babel/core": "^7.21.3", "@babel/plugin-transform-react-constant-elements": "^7.21.3", "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.0", "@svgr/core": "8.1.0", "@svgr/plugin-jsx": "8.1.0", "@svgr/plugin-svgo": "8.1.0" } }, "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA=="], - "@swc/core": ["@swc/core@1.15.33", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.26" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.15.33", "@swc/core-darwin-x64": "1.15.33", "@swc/core-linux-arm-gnueabihf": "1.15.33", "@swc/core-linux-arm64-gnu": "1.15.33", "@swc/core-linux-arm64-musl": "1.15.33", "@swc/core-linux-ppc64-gnu": "1.15.33", "@swc/core-linux-s390x-gnu": "1.15.33", "@swc/core-linux-x64-gnu": "1.15.33", "@swc/core-linux-x64-musl": "1.15.33", "@swc/core-win32-arm64-msvc": "1.15.33", "@swc/core-win32-ia32-msvc": "1.15.33", "@swc/core-win32-x64-msvc": "1.15.33" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-jOlwnFV2xhuuZeAUILGFULeR6vDPfijEJ57evfocwznQldLU3w2cZ9bSDryY9ip+AsM3r1NJKzf47V2NXebkeQ=="], + "@swc/core": ["@swc/core@1.15.43", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.27" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.15.43", "@swc/core-darwin-x64": "1.15.43", "@swc/core-linux-arm-gnueabihf": "1.15.43", "@swc/core-linux-arm64-gnu": "1.15.43", "@swc/core-linux-arm64-musl": "1.15.43", "@swc/core-linux-ppc64-gnu": "1.15.43", "@swc/core-linux-s390x-gnu": "1.15.43", "@swc/core-linux-x64-gnu": "1.15.43", "@swc/core-linux-x64-musl": "1.15.43", "@swc/core-win32-arm64-msvc": "1.15.43", "@swc/core-win32-ia32-msvc": "1.15.43", "@swc/core-win32-x64-msvc": "1.15.43" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw=="], - "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.15.33", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N+L0uXhuO7FIfzqwgxmzv0zIpV0qEp8wPX3QQs2p4atjMoywup2JTeDlXPw+z9pWJGCae3JjM+tZ6myclI+2gA=="], + "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.15.43", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA=="], - "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.15.33", "", { "os": "darwin", "cpu": "x64" }, "sha512-/Il4QHSOhV4FekbsDtkrNmKbsX26oSysvgrRswa/RYOHXAkwXDbB4jaeKq6PsJLSPkzJ2KzQ061gtBnk0vNHfA=="], + "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.15.43", "", { "os": "darwin", "cpu": "x64" }, "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ=="], - "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.15.33", "", { "os": "linux", "cpu": "arm" }, "sha512-C64hBnBxq4viOPQ8hlx+2lJ23bzZBGnjw7ryALmS+0Q3zHmwO8lw1/DArLENw4Q18/0w5wdEO1k3m1wWNtKGqQ=="], + "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.15.43", "", { "os": "linux", "cpu": "arm" }, "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA=="], - "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.15.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-TRJfnJbX3jqpxRDRoieMzRiCBS5jOmXNb3iQXmcgjFEHKLnAgK1RZRU8Cq1MsPqO4jAJp/ld1G4O3fXuxv85uw=="], + "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.15.43", "", { "os": "linux", "cpu": "arm64" }, "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw=="], - "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.15.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-il7tYM+CpUNzieQbwAjFT1P8zqAhmGWNAGhQZBnxurXZ0aNn+5nqYFTEUKNZl7QibtT0uQXzTZrNGHCIj6Y1Og=="], + "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.15.43", "", { "os": "linux", "cpu": "arm64" }, "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ=="], - "@swc/core-linux-ppc64-gnu": ["@swc/core-linux-ppc64-gnu@1.15.33", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ZtNBwN0Z7CFj9Il0FcPaKdjgP7URyKu/3RfH46vq+0paOBqLj4NYldD6Qo//Duif/7IOtAraUfDOmp0PLAufog=="], + "@swc/core-linux-ppc64-gnu": ["@swc/core-linux-ppc64-gnu@1.15.43", "", { "os": "linux", "cpu": "ppc64" }, "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg=="], - "@swc/core-linux-s390x-gnu": ["@swc/core-linux-s390x-gnu@1.15.33", "", { "os": "linux", "cpu": "s390x" }, "sha512-De1IyajoOmhOYYjw/lx66bKlyDpHZTueqwpDrWgf5O7T6d1ODeJJO9/OqMBmrBQc5C+dNnlmIufHsp4QVCWufA=="], + "@swc/core-linux-s390x-gnu": ["@swc/core-linux-s390x-gnu@1.15.43", "", { "os": "linux", "cpu": "s390x" }, "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA=="], - "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.15.33", "", { "os": "linux", "cpu": "x64" }, "sha512-mGTH0YxmUN+x6vRN/I6NOk5X0ogNktkwPnJ94IMvR7QjhRDwL0O8RXEDhyUM0YtwWrryBOqaJQBX4zruxEPRGw=="], + "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.15.43", "", { "os": "linux", "cpu": "x64" }, "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg=="], - "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.15.33", "", { "os": "linux", "cpu": "x64" }, "sha512-hj628ZkSEJf6zMf5VMbYrG2O6QqyTIp2qwY6VlCjvIa9lAEZ5c2lfPblCLVGYubTeLJDxadLB/CxqQYOQABeEQ=="], + "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.15.43", "", { "os": "linux", "cpu": "x64" }, "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ=="], - "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.15.33", "", { "os": "win32", "cpu": "arm64" }, "sha512-GV2oohtN2/5+KSccl86VULu3aT+LrISC8uzgSq0FRnikpD+Zwc+sBlXmoKQ+Db6jI57ITUOIB8jRkdGMABC29g=="], + "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.15.43", "", { "os": "win32", "cpu": "arm64" }, "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw=="], - "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.15.33", "", { "os": "win32", "cpu": "ia32" }, "sha512-gtyvzSNR8DHKfFEA2uqb8Ld1myqi6uEg2jyeUq3ikn5ytYs7H8RpZYC8mdy4NXr8hfcdJfCLXPlYaqqfBXpoEQ=="], + "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.15.43", "", { "os": "win32", "cpu": "ia32" }, "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g=="], - "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.15.33", "", { "os": "win32", "cpu": "x64" }, "sha512-d6fRqQSkJI+kmMEBWaDQ7TMl8+YjLYbwRUPZQ9DY0ORBJeTzOrG0twvfvlZ2xgw6jA0ScQKgfBm4vHLSLl5Hqg=="], + "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.15.43", "", { "os": "win32", "cpu": "x64" }, "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg=="], "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], - "@swc/html": ["@swc/html@1.15.33", "", { "dependencies": { "@swc/counter": "^0.1.3" }, "optionalDependencies": { "@swc/html-darwin-arm64": "1.15.33", "@swc/html-darwin-x64": "1.15.33", "@swc/html-linux-arm-gnueabihf": "1.15.33", "@swc/html-linux-arm64-gnu": "1.15.33", "@swc/html-linux-arm64-musl": "1.15.33", "@swc/html-linux-ppc64-gnu": "1.15.33", "@swc/html-linux-s390x-gnu": "1.15.33", "@swc/html-linux-x64-gnu": "1.15.33", "@swc/html-linux-x64-musl": "1.15.33", "@swc/html-win32-arm64-msvc": "1.15.33", "@swc/html-win32-ia32-msvc": "1.15.33", "@swc/html-win32-x64-msvc": "1.15.33" } }, "sha512-PZIfmj5zYpAJ2eMptf0My2q9Bl8bkraW28+FD1pRnxOiYMrKrP5vL2tB2PdxMRjS0ziLFVM5HEuGFw8PxEDOaw=="], + "@swc/html": ["@swc/html@1.15.43", "", { "dependencies": { "@swc/counter": "^0.1.3" }, "optionalDependencies": { "@swc/html-darwin-arm64": "1.15.43", "@swc/html-darwin-x64": "1.15.43", "@swc/html-linux-arm-gnueabihf": "1.15.43", "@swc/html-linux-arm64-gnu": "1.15.43", "@swc/html-linux-arm64-musl": "1.15.43", "@swc/html-linux-ppc64-gnu": "1.15.43", "@swc/html-linux-s390x-gnu": "1.15.43", "@swc/html-linux-x64-gnu": "1.15.43", "@swc/html-linux-x64-musl": "1.15.43", "@swc/html-win32-arm64-msvc": "1.15.43", "@swc/html-win32-ia32-msvc": "1.15.43", "@swc/html-win32-x64-msvc": "1.15.43" } }, "sha512-SKbkbdGi9SDO9cTdV+6H0/AYifnb2nDOlz5BlWxlWMXACV3kmX6WwZDo0bBdyGlO/G4jCVWdR5r84qfotU2now=="], - "@swc/html-darwin-arm64": ["@swc/html-darwin-arm64@1.15.33", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zyO6uMBfLyCh55wundAxKX+8P/f98ecuyir4VX6nTmn6y7x37ndB8f01LUrd9Tiq6eEAvDXLiqEUvuGjEc7Pmg=="], + "@swc/html-darwin-arm64": ["@swc/html-darwin-arm64@1.15.43", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+PFbHbeeN+zB0zfvR1V1NmvPriuWPI+sijQXpI+wq/nLIujxvtENWjOKVHgouC9TIN/uKmL2zu9HAq6L6YxnPA=="], - "@swc/html-darwin-x64": ["@swc/html-darwin-x64@1.15.33", "", { "os": "darwin", "cpu": "x64" }, "sha512-MaGunsY/J5l7Rb5OmoztEWh+ikooydT7nWkjiDovj7UfkB9HLk5sLr9O7ZdNGJ2u9dD6FX89SzMdA0Psm9NJrQ=="], + "@swc/html-darwin-x64": ["@swc/html-darwin-x64@1.15.43", "", { "os": "darwin", "cpu": "x64" }, "sha512-LQJ2U8Oxcx4T1rRF25y4h+/p05nn58FugTe/uGxC5OT3K83c2MftcSZLYaahOu4GVHRZeS1NI94CkSvQV++TVw=="], - "@swc/html-linux-arm-gnueabihf": ["@swc/html-linux-arm-gnueabihf@1.15.33", "", { "os": "linux", "cpu": "arm" }, "sha512-CrbUDjVl6/hQ1C5KPMiK4vxk/eOMjxkVELqwnOxsZ+aFVTv3L3YrGMaJ5H47vvIihkPhqiSOUPmMEFqxvqKmXg=="], + "@swc/html-linux-arm-gnueabihf": ["@swc/html-linux-arm-gnueabihf@1.15.43", "", { "os": "linux", "cpu": "arm" }, "sha512-DKIen6DuIRO7Xc5gAbgBT5QyRHJGEGXreIdM1VBosYWTGnnrQ//Hwd7bLD6UbT8X8eU1vqvpXwQ1E24QRqRaBQ=="], - "@swc/html-linux-arm64-gnu": ["@swc/html-linux-arm64-gnu@1.15.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-7tZ0IgmUslI9Extu/TpxJS0GjJoDx0j9zeq2cIidPdM/njSBpyRB7n4B292Q5WFVh7PcZl7WXqqqMczibQ27aA=="], + "@swc/html-linux-arm64-gnu": ["@swc/html-linux-arm64-gnu@1.15.43", "", { "os": "linux", "cpu": "arm64" }, "sha512-0AuHiyfcE86CZ/CajFIszLzZVzbM2wn5p01oet8Q9RikflCGwyH79Nv9TrAKD1Cx7juUrONzDk+f2b/x73wLTg=="], - "@swc/html-linux-arm64-musl": ["@swc/html-linux-arm64-musl@1.15.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-gYi2ainYZV2z+jwjp9UKuPVOf3c5q+NkH3QRDjqDrIPLagqDsYNjobi8p5oajGcPGFLNTcVw08VTcubJGChReA=="], + "@swc/html-linux-arm64-musl": ["@swc/html-linux-arm64-musl@1.15.43", "", { "os": "linux", "cpu": "arm64" }, "sha512-TweIdl/g9ugkoiYvcL/qbu+gbglDY3TqNxfXH84WXc4rSqEP20owVlxLya2NjVct8LIP2wDrtutpOwAXWC+Eew=="], - "@swc/html-linux-ppc64-gnu": ["@swc/html-linux-ppc64-gnu@1.15.33", "", { "os": "linux", "cpu": "ppc64" }, "sha512-6CfzyVQSdD8ezFdxFve4J/b6qTgXIwYFWEvSdaJvXSgwTy976uUV5Ff1LOF86mt2zWMhZJX9DqmkGyIhepbyWw=="], + "@swc/html-linux-ppc64-gnu": ["@swc/html-linux-ppc64-gnu@1.15.43", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4oue1pB38/W6mbudp+w0q1jbwxuwdbdbaOj85ay0pisCs213WkgP+MPN8Zqa5VVPjQnVk2CTY9kmEc74XQI/sA=="], - "@swc/html-linux-s390x-gnu": ["@swc/html-linux-s390x-gnu@1.15.33", "", { "os": "linux", "cpu": "s390x" }, "sha512-Msx1eniw95lhMHUSe3D5FXweKHtkHtzJLsHJDj920uL4Dm7UHqzwaCuZdCmzbkHnO96YjjQvAm266djg8wupmQ=="], + "@swc/html-linux-s390x-gnu": ["@swc/html-linux-s390x-gnu@1.15.43", "", { "os": "linux", "cpu": "s390x" }, "sha512-/tceMNvAxK70SKUZtcn3X+K0vcElMGk3i8Sz0CmPdtooso8MZ7WfAvVP1qi3TWgh1rpQ3cC+Al3433AHlET6+w=="], - "@swc/html-linux-x64-gnu": ["@swc/html-linux-x64-gnu@1.15.33", "", { "os": "linux", "cpu": "x64" }, "sha512-JDNb4Uq+7g+23QuOtwWnP0/EqztWIHFFdQdeBIS5zx83YBG2dYRMdPAjnHJWh2YRZxdepd8q6S9MUIxpSrouAg=="], + "@swc/html-linux-x64-gnu": ["@swc/html-linux-x64-gnu@1.15.43", "", { "os": "linux", "cpu": "x64" }, "sha512-YE7ltlTt5ZFl59GsoHTDrIHnCBY8EDBio66CVj4bqkElFXbE/28xmpVE5ksdGoI5c5aQ/8byUCfHxqzCzQQSVg=="], - "@swc/html-linux-x64-musl": ["@swc/html-linux-x64-musl@1.15.33", "", { "os": "linux", "cpu": "x64" }, "sha512-NSpZdbz4dj0pu1A0Z9l68Bll5HAzEMtBAeMe6jc4GEVfpIw6eeafQHm2/yMUEh09tgl8t9LzM9DycfdTZDjM4g=="], + "@swc/html-linux-x64-musl": ["@swc/html-linux-x64-musl@1.15.43", "", { "os": "linux", "cpu": "x64" }, "sha512-nS20HmbOk+dEEzdosJqqxAeyjMIiS5yrCAti8LUf0+dgr4eRmjkH4MlkjfPjf49aayR8o+eMJ1jsDZ7whx4zog=="], - "@swc/html-win32-arm64-msvc": ["@swc/html-win32-arm64-msvc@1.15.33", "", { "os": "win32", "cpu": "arm64" }, "sha512-w7iho3/zS3lCDqgUZMDLMBO0ElX7j+KgvMb8BOrKqLDOSTDDj3lY/BClNJ7vBpAliI2kPQs/mUikdZyzi4MBjQ=="], + "@swc/html-win32-arm64-msvc": ["@swc/html-win32-arm64-msvc@1.15.43", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yz7aQQhXT/Yc6QcuMDQDZP9jqf2phkVyU+qSu8ZRWEcJgIorrPL6q7YLqMk+MB5PpZyu5XJEODvc1/UVDE1Kyg=="], - "@swc/html-win32-ia32-msvc": ["@swc/html-win32-ia32-msvc@1.15.33", "", { "os": "win32", "cpu": "ia32" }, "sha512-6hJ2pBweSfZ38trYHXmzTBDpRNvqJgFl2PkIWdy4IXbV/Fv0v9Dqe0t9Gi2ZVEBpgI7PD6pF42AT4HmrNTVFyQ=="], + "@swc/html-win32-ia32-msvc": ["@swc/html-win32-ia32-msvc@1.15.43", "", { "os": "win32", "cpu": "ia32" }, "sha512-muUgfsSQRZk6YBRuhaGKSLvXy0bV9BW6/mHLI0N/06btWuf0hekoHhIzR7dUmS98NXKCA7Hv+buBPE/0vXUwyA=="], - "@swc/html-win32-x64-msvc": ["@swc/html-win32-x64-msvc@1.15.33", "", { "os": "win32", "cpu": "x64" }, "sha512-eaY/vNE7rkPKluJYjhOiQOA1tto5VbJOoD1C1xFTBmr9t7WsqYUfbQhYQy5A26/z83NNgtDwELM85rkMB+/vWA=="], + "@swc/html-win32-x64-msvc": ["@swc/html-win32-x64-msvc@1.15.43", "", { "os": "win32", "cpu": "x64" }, "sha512-tuLDy4MxPXsLi6jW+ozCdFWO61AoMMnlhePWJxMafefC2Ojm+iILxP2zI2Hgfu6F16y1q7ITdXdpEuqptu5fHw=="], - "@swc/types": ["@swc/types@0.1.26", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw=="], + "@swc/types": ["@swc/types@0.1.27", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-K6h3iUlqeM946U4sXFYeahefR1YBbXJvko+hv8WS8/0BNJ4OHiHRywMnQUJCqkR7Y9+hqQ1TvEpiKqUhz7NEFg=="], "@szmarczak/http-timer": ["@szmarczak/http-timer@5.0.1", "", { "dependencies": { "defer-to-connect": "^2.0.1" } }, "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw=="], "@tanstack/history": ["@tanstack/history@1.162.0", "", {}, "sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA=="], - "@tanstack/react-router": ["@tanstack/react-router@1.170.10", "", { "dependencies": { "@tanstack/history": "1.162.0", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "1.171.8", "isbot": "^5.1.22" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-gVmWYq0ucWr+OB97Nud0YhKa9NOipB7/QrWI7wRZJJWEL0qUS8WPqAs0vA1f3IBXZpXmf8xxzf/tl5cmo4tlmA=="], + "@tanstack/react-router": ["@tanstack/react-router@1.170.18", "", { "dependencies": { "@tanstack/history": "1.162.0", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "1.171.15", "isbot": "^5.1.22" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-wpbGYZEp/fmz1q4bn7BD8VZ+/VZ7GBqSJv5V969pU+chP8y7dquWDmKTFMohvUegb9lg12m1uPVvD6kB2wORvQ=="], "@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.167.0", "", { "dependencies": { "@tanstack/router-devtools-core": "1.168.0" }, "peerDependencies": { "@tanstack/react-router": "^1.170.0", "@tanstack/router-core": "^1.170.0", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-nGw095EG7IHx0h5NtlEmzf6vcCTaFNPWdTSuDKazajhN0ct/v/TkekJ9J6KYUCeV1a8/2ZmToc58M+0rrOyn7w=="], "@tanstack/react-store": ["@tanstack/react-store@0.9.3", "", { "dependencies": { "@tanstack/store": "0.9.3", "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-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg=="], - "@tanstack/router-core": ["@tanstack/router-core@1.171.8", "", { "dependencies": { "@tanstack/history": "1.162.0", "cookie-es": "^3.0.0", "seroval": "^1.5.4", "seroval-plugins": "^1.5.4" } }, "sha512-PbrTBbofFcacrH3RLgHYILRqTFnAGq+gXrXoA/vo7qUSkJpSO4GWfLtrtCahD4VayzRm19IPwcjPPLEugag6pw=="], + "@tanstack/router-core": ["@tanstack/router-core@1.171.15", "", { "dependencies": { "@tanstack/history": "1.162.0", "cookie-es": "^3.0.0", "seroval": "^1.5.4", "seroval-plugins": "^1.5.4" } }, "sha512-IILCDcLaItMZQ2jEmCABHY1Nhjjn5XUvwpQp3e4Nmu+vfg0BgYFuu/QASz2SwE2ZNbVMrvt8X/wxa+Gg5aErxA=="], "@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.168.0", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16" }, "peerDependencies": { "@tanstack/router-core": "^1.170.0", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-wQoQhlBK7nlZgqzaqdYXKWNTpdHdsaREdaPhFZVH0/Ador+F+eM3/NF2i3f2LPeS0GgKraZUQXe1Q/1+KHyEYg=="], - "@tanstack/router-generator": ["@tanstack/router-generator@1.167.12", "", { "dependencies": { "@babel/types": "^7.28.5", "@tanstack/router-core": "1.171.8", "@tanstack/router-utils": "1.162.1", "@tanstack/virtual-file-routes": "1.162.0", "jiti": "^2.7.0", "magic-string": "^0.30.21", "prettier": "^3.5.0", "zod": "^4.4.3" } }, "sha512-FGr7nn6VhjL53TUCTyDgApSkAYRxhId+v0HVQdSu0ADkNuHY+sUnYEMqiF6aN82jYWuXzrSL1xazg6/rfEP82g=="], + "@tanstack/router-generator": ["@tanstack/router-generator@1.167.20", "", { "dependencies": { "@babel/types": "^7.28.5", "@tanstack/router-core": "1.171.15", "@tanstack/router-utils": "1.162.2", "@tanstack/virtual-file-routes": "1.162.0", "jiti": "^2.7.0", "magic-string": "^0.30.21", "prettier": "^3.5.0", "zod": "^4.4.3" } }, "sha512-SCLPDE1ne+l1pf30T2mMGKwG3Q5rffGAs/lDqEXmoj0PwYeMwpChs/pLzLN+KH/oDGzSmXKmiK9aGKZy3aSwXA=="], - "@tanstack/router-plugin": ["@tanstack/router-plugin@1.168.13", "", { "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.171.8", "@tanstack/router-generator": "1.167.12", "@tanstack/router-utils": "1.162.1", "@tanstack/virtual-file-routes": "1.162.0", "chokidar": "^5.0.0", "unplugin": "^3.0.0", "zod": "^4.4.3" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2 || ^2.0.0", "@tanstack/react-router": "^1.170.10", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-LnepwDai+TaC4K3aZeXrrKpnGoP8xGGilVGFfa5flGgC3+jCSBysb8SktidRE8eF2/iOzCQC0LIGirtMyZepSA=="], + "@tanstack/router-plugin": ["@tanstack/router-plugin@1.168.21", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.171.15", "@tanstack/router-generator": "1.167.20", "@tanstack/router-utils": "1.162.2", "chokidar": "^5.0.0", "unplugin": "^3.0.0", "zod": "^4.4.3" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2 || ^2.0.0", "@tanstack/react-router": "^1.170.18", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-76erhrm1jGJ4NvwQZdEZjgUfwaw9jJJjv+w45qx5TNZwemW0zeskYSNSDhxmfnW7ZnMTY7bFCy3zUUBoR6cF7Q=="], - "@tanstack/router-utils": ["@tanstack/router-utils@1.162.1", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "ansis": "^4.1.0", "babel-dead-code-elimination": "^1.0.12", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-62layyTGmclHDQS/eidwKRfN1hhCKwViG7iEBcVmL0MXgcAB3OOucWCEcDDGd9Cu11H6b4QQ5oOo47MWIqwz0A=="], + "@tanstack/router-utils": ["@tanstack/router-utils@1.162.2", "", { "dependencies": { "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "ansis": "^4.1.0", "babel-dead-code-elimination": "^1.0.12", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-hTWqJtqIFFdvuCl8WXNyrodp2L9zo2G37xKRrcVmVRWpAB2h+U1LuRAfS4tsFTiWOIoE/B+WDVFB8JpoEdw6jQ=="], "@tanstack/store": ["@tanstack/store@0.9.3", "", {}, "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw=="], "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.162.0", "", {}, "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA=="], - "@turbo/darwin-64": ["@turbo/darwin-64@2.9.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-jLjApWTSNd7JZ5JaLYfelW1ytnGQOvB7ivl+2RD1xQvJTbi8I9gBjzcga7tDZVPyaxpl10YTfJt3BrYXR18KDw=="], + "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="], - "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-YPgrn+5HIGzrx0O2a631SV4MBQUe4W/DafMFUuBVgaU32PW9/OTT0ehviF0QSxTXuRJlHvW2eUTemddF5/spmw=="], + "@testing-library/react": ["@testing-library/react@16.3.2", "", { "dependencies": { "@babel/runtime": "^7.12.5" }, "peerDependencies": { "@testing-library/dom": "^10.0.0", "@types/react": "^18.0.0 || ^19.0.0", "@types/react-dom": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g=="], - "@turbo/linux-64": ["@turbo/linux-64@2.9.16", "", { "os": "linux", "cpu": "x64" }, "sha512-vAEf1H6l26lTpl9FJ/peQo1NUB8RC0sbEJJz5mPcUhHA2bPDup2x3CZPgo/bH8S4cUcBLm4FN3UHd5iUO2RAew=="], + "@turbo/darwin-64": ["@turbo/darwin-64@2.10.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-ENvPwy3x5yS7MwNYHeWjqOBXkwIMp39Pd+/zXC6PoiNzF8EIvvLZOZZ+ny6L9x4WgS5vxUii2LM5gM+zjPdnWw=="], - "@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-xDBLR2PZg4BrQOchfG6svgpv5FCNJ2TOtT2psLdEJcdKo1BH+pnPs9Xj6pvUjgfkHbuvBOfeE4R6tvxMoQKDHQ=="], + "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.10.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rqROo9zsF/P9RqsdtbLD1nFJicjSrYyvQ9kNJC38AbxA3pAs6VAlATvtvOFx7bqOv6vicf20SP9kF33avJjy2w=="], - "@turbo/windows-64": ["@turbo/windows-64@2.9.16", "", { "os": "win32", "cpu": "x64" }, "sha512-NBAJnaUiGdgkSzQwUIdOvkCkcpTSu58G/sBGa0mvBtzfvFOOgrQwepKOOQ8cp6sWM6OcKDNFj2p1dsZA1OWjPg=="], + "@turbo/linux-64": ["@turbo/linux-64@2.10.5", "", { "os": "linux", "cpu": "x64" }, "sha512-RoSSiNFUxi27zLJuM9F6GyWWjHgLch9t6nwD6K0FkXRirZkTLlzIj6IhFnK8H9++nefLtdFqylE4vGjZAv6AAA=="], - "@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-Y7SJppD0Z8wjO3Ec0ZGd9KQ4Yv0BMnA8CIowj5Vp+OEVsosXDG2weK6/t1RRLfJmc2Ozrnd6y4DOgQys+mn3WQ=="], + "@turbo/linux-arm64": ["@turbo/linux-arm64@2.10.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-4ZComcpzmHGmVynQqvvi+iZOSq/tBvY1SltXB8g4NZRsrA01W8E+yRL8RNM+PLoyWsrCnJa8xa+DkWkv+xg4iQ=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + "@turbo/windows-64": ["@turbo/windows-64@2.10.5", "", { "os": "win32", "cpu": "x64" }, "sha512-eL2Iyj4DbMINq1Sr1w0iAi6nAiZOF16KSlRGwCJpVh+IWZeY33MAsLHVOBMj1xoFtncVJXclCVpTPL2nBoYkFg=="], + + "@turbo/windows-arm64": ["@turbo/windows-arm64@2.10.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-sog+wP+8YSJrdWZ/rUJg8xghVTrwoG+BrSlDQpnK5fzSgJHn1INRWXbVWRH0d3vX8dBI01E3yxXRre9Dn+OXQA=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], "@typed/id": ["@typed/id@0.17.2", "", { "peerDependencies": { "effect": "^3.14.7" } }, "sha512-z/Z14/moeu9x45IpkGaRwuvb+CQ3s3UCc/agcpZibTz1yPb3RgSDXx4rOHIuyb6hG6oNzqe9yY4GbbMq3Hb5Ug=="], + "@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="], + "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], "@types/bonjour": ["@types/bonjour@3.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ=="], "@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="], + "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], + "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], "@types/connect-history-api-fallback": ["@types/connect-history-api-fallback@1.5.4", "", { "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw=="], "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], - "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], + "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], - "@types/eslint-scope": ["@types/eslint-scope@3.7.7", "", { "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg=="], - - "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], "@types/express": ["@types/express@4.17.25", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "^1" } }, "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw=="], - "@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.8", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA=="], + "@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.9", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-QP2ESEe/ImWY0HDwNAnK9PvEffUyhLTnWkk7KXzHfyeWAnlrDe1fN77bXl6ia8KT3wPlmA7t9/VPRpnf4Ex9sg=="], - "@types/gtag.js": ["@types/gtag.js@0.0.20", "", {}, "sha512-wwAbk3SA2QeU67unN7zPxjEHmPmlXwZXZvQEpbEUQuMCRGgKyE1m6XDuTUA9b6pCGb/GqJmdfMOY5LuDjJSbbg=="], - - "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + "@types/hast": ["@types/hast@3.0.5", "", { "dependencies": { "@types/unist": "*" } }, "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g=="], "@types/history": ["@types/history@4.7.11", "", {}, "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA=="], @@ -1011,21 +1194,21 @@ "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], - "@types/mdx": ["@types/mdx@2.0.13", "", {}, "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw=="], + "@types/mdx": ["@types/mdx@2.0.14", "", {}, "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg=="], "@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="], "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="], + "@types/node": ["@types/node@26.1.1", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], "@types/prismjs": ["@types/prismjs@1.26.6", "", {}, "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw=="], - "@types/qs": ["@types/qs@6.15.0", "", {}, "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow=="], + "@types/qs": ["@types/qs@6.15.1", "", {}, "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw=="], "@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="], - "@types/react": ["@types/react@19.2.15", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q=="], + "@types/react": ["@types/react@19.2.17", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw=="], "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], @@ -1055,9 +1238,23 @@ "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], - "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.3", "", {}, "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg=="], - "@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.2", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.0" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg=="], + "@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.3", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.1" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg=="], + + "@vitest/expect": ["@vitest/expect@3.2.7", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.7", "@vitest/utils": "3.2.7", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w=="], + + "@vitest/mocker": ["@vitest/mocker@3.2.7", "", { "dependencies": { "@vitest/spy": "3.2.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA=="], + + "@vitest/pretty-format": ["@vitest/pretty-format@3.2.7", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA=="], + + "@vitest/runner": ["@vitest/runner@3.2.7", "", { "dependencies": { "@vitest/utils": "3.2.7", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA=="], + + "@vitest/snapshot": ["@vitest/snapshot@3.2.7", "", { "dependencies": { "@vitest/pretty-format": "3.2.7", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g=="], + + "@vitest/spy": ["@vitest/spy@3.2.7", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ=="], + + "@vitest/utils": ["@vitest/utils@3.2.7", "", { "dependencies": { "@vitest/pretty-format": "3.2.7", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw=="], "@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="], @@ -1095,7 +1292,7 @@ "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], - "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + "acorn": ["acorn@8.17.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg=="], "acorn-import-phases": ["acorn-import-phases@1.0.4", "", { "peerDependencies": { "acorn": "^8.14.0" } }, "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ=="], @@ -1103,29 +1300,31 @@ "acorn-walk": ["acorn-walk@8.3.5", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw=="], - "address": ["address@1.2.2", "", {}, "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA=="], + "address": ["address@2.0.3", "", {}, "sha512-XNAb/a6TCqou+TufU8/u11HCu9x1gYvOoxLwtlXgIqmkrYQADVv6ljyW2zwiPhHz9R1gItAWpuDrdJMmrOBFEA=="], + + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], - "ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], + "ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], "ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="], "ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="], - "algoliasearch": ["algoliasearch@5.50.0", "", { "dependencies": { "@algolia/abtesting": "1.16.0", "@algolia/client-abtesting": "5.50.0", "@algolia/client-analytics": "5.50.0", "@algolia/client-common": "5.50.0", "@algolia/client-insights": "5.50.0", "@algolia/client-personalization": "5.50.0", "@algolia/client-query-suggestions": "5.50.0", "@algolia/client-search": "5.50.0", "@algolia/ingestion": "1.50.0", "@algolia/monitoring": "1.50.0", "@algolia/recommend": "5.50.0", "@algolia/requester-browser-xhr": "5.50.0", "@algolia/requester-fetch": "5.50.0", "@algolia/requester-node-http": "5.50.0" } }, "sha512-yE5I83Q2s8euVou8Y3feXK08wyZInJWLYXgWO6Xti9jBUEZAGUahyeQ7wSZWkifLWVnQVKEz5RAmBlXG5nqxog=="], + "algoliasearch": ["algoliasearch@5.56.0", "", { "dependencies": { "@algolia/abtesting": "1.22.0", "@algolia/client-abtesting": "5.56.0", "@algolia/client-analytics": "5.56.0", "@algolia/client-common": "5.56.0", "@algolia/client-insights": "5.56.0", "@algolia/client-personalization": "5.56.0", "@algolia/client-query-suggestions": "5.56.0", "@algolia/client-search": "5.56.0", "@algolia/ingestion": "1.56.0", "@algolia/monitoring": "1.56.0", "@algolia/recommend": "5.56.0", "@algolia/requester-browser-xhr": "5.56.0", "@algolia/requester-fetch": "5.56.0", "@algolia/requester-node-http": "5.56.0" } }, "sha512-PrqppUmhT4ENdas2pH9caE7efUcxy6EcSFhWzosiVuQBzu2tQ5yLTI6jwomT/1cuBnivzGfxiJCqDNN9FRRh+Q=="], - "algoliasearch-helper": ["algoliasearch-helper@3.28.1", "", { "dependencies": { "@algolia/events": "^4.0.1" }, "peerDependencies": { "algoliasearch": ">= 3.1 < 6" } }, "sha512-6iXpbkkrAI5HFpCWXlNmIDSBuoN/U1XnEvb2yJAoWfqrZ+DrybI7MQ5P5mthFaprmocq+zbi6HxnR28xnZAYBw=="], + "algoliasearch-helper": ["algoliasearch-helper@3.29.2", "", { "dependencies": { "@algolia/events": "^4.0.1" }, "peerDependencies": { "algoliasearch": ">= 3.1 < 6" } }, "sha512-SaV+rZM3drExb0punEYYjT+sNcH74YFwN8ocjya7IDOyQvKWeQpEaSMVG3+IGTVos+feuatj7ljQ4BXlXdUp3w=="], "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], "ansi-html-community": ["ansi-html-community@0.0.8", "", { "bin": { "ansi-html": "bin/ansi-html" } }, "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw=="], - "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="], + "ansis": ["ansis@4.3.1", "", {}, "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -1135,15 +1334,19 @@ "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + "aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="], + "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], - "asn1js": ["asn1js@3.0.7", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ=="], + "asn1js": ["asn1js@3.0.10", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.5", "tslib": "^2.8.1" } }, "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg=="], + + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], - "autoprefixer": ["autoprefixer@10.4.27", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001774", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA=="], + "autoprefixer": ["autoprefixer@10.5.4", "", { "dependencies": { "browserslist": "^4.28.6", "caniuse-lite": "^1.0.30001806", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA=="], "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=="], @@ -1161,7 +1364,7 @@ "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.10.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.43", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ=="], "batch": ["batch@0.6.1", "", {}, "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw=="], @@ -1169,19 +1372,19 @@ "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - "body-parser": ["body-parser@1.20.4", "", { "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "~1.2.0", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", "qs": "~6.14.0", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" } }, "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA=="], + "body-parser": ["body-parser@1.20.6", "", { "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "~1.2.0", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", "qs": "~6.15.1", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" } }, "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g=="], - "bonjour-service": ["bonjour-service@1.3.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } }, "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA=="], + "bonjour-service": ["bonjour-service@1.4.3", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } }, "sha512-2Kd5UYlFUVgAKMTyuBLl6w49wqfOnbxHqmuH0oCl/n7TfAikR0zoowNOP5BU4dfXmm+Vr9JyEN370auSMx+CNg=="], "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], "boxen": ["boxen@6.2.1", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^6.2.0", "chalk": "^4.1.2", "cli-boxes": "^3.0.0", "string-width": "^5.0.1", "type-fest": "^2.5.0", "widest-line": "^4.0.1", "wrap-ansi": "^8.0.1" } }, "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw=="], - "brace-expansion": ["brace-expansion@1.1.13", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w=="], + "brace-expansion": ["brace-expansion@1.1.16", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], + "browserslist": ["browserslist@4.28.6", "", { "dependencies": { "baseline-browser-mapping": "^2.10.42", "caniuse-lite": "^1.0.30001803", "electron-to-chromium": "^1.5.389", "node-releases": "^2.0.51", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw=="], "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], @@ -1193,11 +1396,13 @@ "bytestreamjs": ["bytestreamjs@2.0.1", "", {}, "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ=="], + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + "cacheable-lookup": ["cacheable-lookup@7.0.0", "", {}, "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w=="], "cacheable-request": ["cacheable-request@10.2.14", "", { "dependencies": { "@types/http-cache-semantics": "^4.0.2", "get-stream": "^6.0.1", "http-cache-semantics": "^4.1.1", "keyv": "^4.5.3", "mimic-response": "^4.0.0", "normalize-url": "^8.0.0", "responselike": "^3.0.0" } }, "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ=="], - "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], + "call-bind": ["call-bind@1.0.9", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" } }, "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], @@ -1211,10 +1416,12 @@ "caniuse-api": ["caniuse-api@3.0.0", "", { "dependencies": { "browserslist": "^4.0.0", "caniuse-lite": "^1.0.0", "lodash.memoize": "^4.1.2", "lodash.uniq": "^4.5.0" } }, "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw=="], - "caniuse-lite": ["caniuse-lite@1.0.30001782", "", {}, "sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw=="], + "caniuse-lite": ["caniuse-lite@1.0.30001806", "", {}, "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], + "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="], @@ -1227,6 +1434,8 @@ "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], + "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], + "cheerio": ["cheerio@1.0.0-rc.12", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "htmlparser2": "^8.0.1", "parse5": "^7.0.0", "parse5-htmlparser2-tree-adapter": "^7.0.0" } }, "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q=="], "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], @@ -1313,7 +1522,7 @@ "css-blank-pseudo": ["css-blank-pseudo@7.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag=="], - "css-declaration-sorter": ["css-declaration-sorter@7.3.1", "", { "peerDependencies": { "postcss": "^8.0.9" } }, "sha512-gz6x+KkgNCjxq3Var03pRYLhyNfwhkKF1g/yoLgDNtFvVu0/fOLV9C8fFEZRjACp/XQLumjAYo7JVjzH3wLbxA=="], + "css-declaration-sorter": ["css-declaration-sorter@7.4.0", "", { "peerDependencies": { "postcss": "^8.0.9" } }, "sha512-LTuzjPoyA2vMGKKcaOqKSp7Ub2eGrNfKiZH4LpezxpNrsICGCSFvsQOI29psISxNZtaXibkC2CXzrQ5enMeGGw=="], "css-has-pseudo": ["css-has-pseudo@7.0.3", "", { "dependencies": { "@csstools/selector-specificity": "^5.0.0", "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA=="], @@ -1325,11 +1534,11 @@ "css-select": ["css-select@4.3.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" } }, "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ=="], - "css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="], + "css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], - "cssdb": ["cssdb@8.8.0", "", {}, "sha512-QbLeyz2Bgso1iRlh7IpWk6OKa3lLNGXsujVjDMPl9rOZpxKeiG69icLpbLCFxeURwmcdIfZqQyhlooKJYM4f8Q=="], + "cssdb": ["cssdb@8.9.0", "", {}, "sha512-J8jOU/hLjaXcO1LldOLraJSQpfLXRKof0I7mtbRyOy2AAXgqst0x9rlgi2qXeD6d0ou3ZLqcPAMqYVbpCbrxEw=="], "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], @@ -1343,16 +1552,24 @@ "csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="], + "cssstyle": ["cssstyle@4.6.0", "", { "dependencies": { "@asamuzakjp/css-color": "^3.2.0", "rrweb-cssom": "^0.8.0" } }, "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="], + "debounce": ["debounce@1.2.1", "", {}, "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="], + "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], + "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], @@ -1381,7 +1598,7 @@ "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], - "detect-port": ["detect-port@1.6.1", "", { "dependencies": { "address": "^1.0.1", "debug": "4" }, "bin": { "detect": "bin/detect-port.js", "detect-port": "bin/detect-port.js" } }, "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q=="], + "detect-port": ["detect-port@2.1.0", "", { "dependencies": { "address": "^2.0.1" }, "bin": { "detect": "dist/commonjs/bin/detect-port.js", "detect-port": "dist/commonjs/bin/detect-port.js" } }, "sha512-epZuWb/6Q62L+nDHJc/hQAqf8pylsqgk3BpZXVBx1CDnr3nkrVNn73Uu1rXcFzkNcc+hkP3whuOg7JZYaQB65Q=="], "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], @@ -1393,6 +1610,8 @@ "docs": ["docs@workspace:packages/docs"], + "dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], + "dom-converter": ["dom-converter@0.2.0", "", { "dependencies": { "utila": "~0.4" } }, "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA=="], "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], @@ -1415,13 +1634,15 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "effect": ["effect@3.21.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-rXd2FGDM8KdjSIrc+mqEELo7ScW7xTVxEf1iInmPSpIde9/nyGuFM710cjTo7/EreGXiUX2MOonPpprbz2XHCg=="], + "effect": ["effect@3.22.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-jhYFe0zTlIRqYFrKTS+6luhmS/Tm0f+JLo0K9KUxvtFab1SUGEszQi2ehOP6QzAZvy831lDmTwwzvVDZSPNz3g=="], "effect-fc": ["effect-fc@workspace:packages/effect-fc"], - "effect-lens": ["effect-lens@0.2.0", "", { "peerDependencies": { "effect": "^3.21.0" } }, "sha512-Cfyps811WQVSxnbxm6xqJldL08YXUU1jAzWtdKXSKWZfF6LAEqm1l8swnw4ltVky1TSfi2vvS+I/tFPqwObrMg=="], + "effect-fc-next": ["effect-fc-next@workspace:packages/effect-fc-next"], - "electron-to-chromium": ["electron-to-chromium@1.5.329", "", {}, "sha512-/4t+AS1l4S3ZC0Ja7PHFIWeBIxGA3QGqV8/yKsP36v7NcyUCl+bIcmw6s5zVuMIECWwBrAK/6QLzTmbJChBboQ=="], + "effect-lens": ["effect-lens@0.2.2", "", { "peerDependencies": { "effect": "^3.21.0" } }, "sha512-kt+aLq9djFFAH3sj+/YapcIzx/tqmkTO+ofU2HiEIm34zB/zx+0PvWLXqhK1EuCEjl9Ueififg711J1FvvzIqw=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.393", "", {}, "sha512-kiDJdIUawuEIcp9XoICKp1iTYDEbgguIPq526N1Q7jIQDeQ3CqoMx71025PI/7E48Ddtw2HuWsVjY7afEgNxmg=="], "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], @@ -1433,9 +1654,9 @@ "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], - "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], + "enhanced-resolve": ["enhanced-resolve@5.24.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-rpsZEGT1jFuve6QlpyRp9ckQ+kN61hvF9BzCPyMdaKTm8UJce96KBn3sorXOFXlzjPrs3Vc4T1NsSroZ3PxlFw=="], - "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], @@ -1443,14 +1664,16 @@ "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - "es-module-lexer": ["es-module-lexer@2.0.0", "", {}, "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw=="], + "es-module-lexer": ["es-module-lexer@2.3.1", "", {}, "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA=="], - "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + "es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="], "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "unist-util-position-from-estree": "^2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="], "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="], + "esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escape-goat": ["escape-goat@4.0.0", "", {}, "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg=="], @@ -1461,8 +1684,6 @@ "eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], - "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], "estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], @@ -1497,7 +1718,9 @@ "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], - "express": ["express@4.22.1", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "~1.20.3", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "~1.3.1", "fresh": "~0.5.2", "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", "serve-static": "~1.16.2", "setprototypeof": "1.2.0", "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g=="], + "expect-type": ["expect-type@1.4.0", "", {}, "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA=="], + + "express": ["express@4.22.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "~1.20.5", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "~1.3.1", "fresh": "~0.5.2", "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", "qs": "~6.15.1", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", "serve-static": "~1.16.2", "setprototypeof": "1.2.0", "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q=="], "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], @@ -1511,7 +1734,7 @@ "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], + "fast-uri": ["fast-uri@3.1.3", "", {}, "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg=="], "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], @@ -1537,7 +1760,7 @@ "flat": ["flat@5.0.2", "", { "bin": { "flat": "cli.js" } }, "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="], - "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], + "follow-redirects": ["follow-redirects@1.16.0", "", {}, "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw=="], "form-data-encoder": ["form-data-encoder@2.1.4", "", {}, "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw=="], @@ -1549,7 +1772,7 @@ "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], - "fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], + "fs-extra": ["fs-extra@11.3.6", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], @@ -1573,15 +1796,13 @@ "glob-to-regex.js": ["glob-to-regex.js@1.2.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ=="], - "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], - "global-dirs": ["global-dirs@3.0.1", "", { "dependencies": { "ini": "2.0.0" } }, "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA=="], - "globals": ["globals@17.6.0", "", {}, "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA=="], + "globals": ["globals@17.7.0", "", {}, "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg=="], "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], - "goober": ["goober@2.1.18", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw=="], + "goober": ["goober@2.1.19", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg=="], "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], @@ -1589,8 +1810,6 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="], - "gzip-size": ["gzip-size@6.0.0", "", { "dependencies": { "duplexer": "^0.1.2" } }, "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q=="], "handle-thing": ["handle-thing@2.0.1", "", {}, "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg=="], @@ -1603,7 +1822,7 @@ "has-yarn": ["has-yarn@3.0.0", "", {}, "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA=="], - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="], "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="], @@ -1629,6 +1848,8 @@ "hpack.js": ["hpack.js@2.1.6", "", { "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", "readable-stream": "^2.0.1", "wbuf": "^1.1.0" } }, "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ=="], + "html-encoding-sniffer": ["html-encoding-sniffer@4.0.0", "", { "dependencies": { "whatwg-encoding": "^3.1.1" } }, "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ=="], + "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], "html-minifier-terser": ["html-minifier-terser@7.2.0", "", { "dependencies": { "camel-case": "^4.1.2", "clean-css": "~5.3.2", "commander": "^10.0.0", "entities": "^4.4.0", "param-case": "^3.0.4", "relateurl": "^0.2.7", "terser": "^5.15.1" }, "bin": { "html-minifier-terser": "cli.js" } }, "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA=="], @@ -1637,7 +1858,7 @@ "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], - "html-webpack-plugin": ["html-webpack-plugin@5.6.6", "", { "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", "lodash": "^4.17.21", "pretty-error": "^4.0.0", "tapable": "^2.0.0" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "webpack": "^5.20.0" }, "optionalPeers": ["@rspack/core", "webpack"] }, "sha512-bLjW01UTrvoWTJQL5LsMRo1SypHW80FTm12OJRSnr3v6YHNhfe+1r0MYUZJMACxnCHURVnBWRwAsWs2yPU9Ezw=="], + "html-webpack-plugin": ["html-webpack-plugin@5.6.7", "", { "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", "lodash": "^4.17.21", "pretty-error": "^4.0.0", "tapable": "^2.0.0" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "webpack": "^5.20.0" }, "optionalPeers": ["@rspack/core", "webpack"] }, "sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw=="], "htmlparser2": ["htmlparser2@8.0.2", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1", "entities": "^4.4.0" } }, "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA=="], @@ -1651,15 +1872,19 @@ "http-proxy": ["http-proxy@1.18.1", "", { "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } }, "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ=="], - "http-proxy-middleware": ["http-proxy-middleware@2.0.9", "", { "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", "micromatch": "^4.0.2" }, "peerDependencies": { "@types/express": "^4.17.13" }, "optionalPeers": ["@types/express"] }, "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q=="], + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + + "http-proxy-middleware": ["http-proxy-middleware@2.0.10", "", { "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", "micromatch": "^4.0.2" }, "peerDependencies": { "@types/express": "^4.17.13" }, "optionalPeers": ["@types/express"] }, "sha512-RKzRWNPxUZqbuk3BC5mGVJbBnWgr+diEnjJexIOytFbBzDy88Fbh/YvBr3DsNrl1jYAfjWfpATEv0NO35FDuPQ=="], "http2-wrapper": ["http2-wrapper@2.2.1", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.2.0" } }, "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ=="], + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], "hyperdyperid": ["hyperdyperid@1.2.0", "", {}, "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A=="], - "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "icss-utils": ["icss-utils@5.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA=="], @@ -1679,13 +1904,13 @@ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - "ini": ["ini@2.0.0", "", {}, "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA=="], + "ini": ["ini@7.0.0", "", {}, "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w=="], "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], - "ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="], + "ipaddr.js": ["ipaddr.js@2.4.0", "", {}, "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ=="], "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], @@ -1697,7 +1922,7 @@ "is-ci": ["is-ci@3.0.1", "", { "dependencies": { "ci-info": "^3.2.0" }, "bin": { "is-ci": "bin.js" } }, "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ=="], - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + "is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "^2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="], "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], @@ -1717,7 +1942,7 @@ "is-installed-globally": ["is-installed-globally@0.4.0", "", { "dependencies": { "global-dirs": "^3.0.0", "is-path-inside": "^3.0.2" } }, "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ=="], - "is-network-error": ["is-network-error@1.3.1", "", {}, "sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw=="], + "is-network-error": ["is-network-error@1.3.2", "", {}, "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA=="], "is-npm": ["is-npm@6.1.0", "", {}, "sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA=="], @@ -1731,6 +1956,8 @@ "is-plain-object": ["is-plain-object@2.0.4", "", { "dependencies": { "isobject": "^3.0.1" } }, "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="], + "is-potential-custom-element-name": ["is-potential-custom-element-name@1.0.1", "", {}, "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="], + "is-regexp": ["is-regexp@1.0.0", "", {}, "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA=="], "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], @@ -1743,7 +1970,7 @@ "isarray": ["isarray@0.0.1", "", {}, "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="], - "isbot": ["isbot@5.1.37", "", {}, "sha512-5bcicX81xf6NlTEV8rWdg7Pk01LFizDetuYGHx6d/f6y3lR2/oo8IfxjzJqn1UdDEyCcwT9e7NRloj8DwCYujQ=="], + "isbot": ["isbot@5.2.1", "", {}, "sha512-dJ+LpKyClQZ7NG+j3OensC/mAZkGpukE9YUrgPYvAZj2doVL0edfDgywTUh5CXa0o+nW9a1V9e5+CJTX8+SxRw=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -1755,11 +1982,13 @@ "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], - "joi": ["joi@17.13.3", "", { "dependencies": { "@hapi/hoek": "^9.3.0", "@hapi/topo": "^5.1.0", "@sideway/address": "^4.1.5", "@sideway/formula": "^3.0.1", "@sideway/pinpoint": "^2.0.0" } }, "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA=="], + "joi": ["joi@17.13.4", "", { "dependencies": { "@hapi/hoek": "^9.3.0", "@hapi/topo": "^5.1.0", "@sideway/address": "^4.1.5", "@sideway/formula": "^3.0.1", "@sideway/pinpoint": "^2.0.0" } }, "sha512-1RuuER6kmt8K8I3nIWvPZKi5RQCb568ZPyY4Pwjlua+yo+63ZTmIwxLZH0heBmiKN4uxjvCiarDrjaeH84xicQ=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + "js-yaml": ["js-yaml@4.3.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q=="], + + "jsdom": ["jsdom@26.1.0", "", { "dependencies": { "cssstyle": "^4.2.1", "data-urls": "^5.0.0", "decimal.js": "^10.5.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.16", "parse5": "^7.2.1", "rrweb-cssom": "^0.8.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^5.1.1", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.1.1", "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg=="], "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], @@ -1771,7 +2000,7 @@ "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], @@ -1779,9 +2008,11 @@ "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], + "kubernetes-types": ["kubernetes-types@1.30.0", "", {}, "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q=="], + "latest-version": ["latest-version@7.0.0", "", { "dependencies": { "package-json": "^8.1.0" } }, "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg=="], - "launch-editor": ["launch-editor@2.13.2", "", { "dependencies": { "picocolors": "^1.1.1", "shell-quote": "^1.8.3" } }, "sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg=="], + "launch-editor": ["launch-editor@2.14.1", "", { "dependencies": { "picocolors": "^1.1.1", "shell-quote": "^1.8.4" } }, "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA=="], "leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], @@ -1813,13 +2044,13 @@ "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], - "loader-runner": ["loader-runner@4.3.1", "", {}, "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q=="], + "loader-runner": ["loader-runner@4.3.2", "", {}, "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w=="], "loader-utils": ["loader-utils@2.0.4", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^2.1.2" } }, "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw=="], "locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="], - "lodash": ["lodash@4.18.0", "", {}, "sha512-l1mfj2atMqndAHI3ls7XqPxEjV2J9ZkcNyHpoZA3r2T1LLwDB69jgkMWh71YKwhBbK0G2f4WSn05ahmQXVxupA=="], + "lodash": ["lodash@4.18.1", "", {}, "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q=="], "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], @@ -1831,12 +2062,16 @@ "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], + "lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="], "lowercase-keys": ["lowercase-keys@3.0.0", "", {}, "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ=="], "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], @@ -1881,11 +2116,11 @@ "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], - "mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="], + "mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], - "memfs": ["memfs@4.57.1", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.57.1", "@jsonjoy.com/fs-fsa": "4.57.1", "@jsonjoy.com/fs-node": "4.57.1", "@jsonjoy.com/fs-node-builtins": "4.57.1", "@jsonjoy.com/fs-node-to-fsa": "4.57.1", "@jsonjoy.com/fs-node-utils": "4.57.1", "@jsonjoy.com/fs-print": "4.57.1", "@jsonjoy.com/fs-snapshot": "4.57.1", "@jsonjoy.com/json-pack": "^1.11.0", "@jsonjoy.com/util": "^1.9.0", "glob-to-regex.js": "^1.0.1", "thingies": "^2.5.0", "tree-dump": "^1.0.3", "tslib": "^2.0.0" } }, "sha512-WvzrWPwMQT+PtbX2Et64R4qXKK0fj/8pO85MrUCzymX3twwCiJCdvntW3HdhG1teLJcHDDLIKx5+c3HckWYZtQ=="], + "memfs": ["memfs@4.64.0", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.64.0", "@jsonjoy.com/fs-fsa": "4.64.0", "@jsonjoy.com/fs-node": "4.64.0", "@jsonjoy.com/fs-node-builtins": "4.64.0", "@jsonjoy.com/fs-node-to-fsa": "4.64.0", "@jsonjoy.com/fs-node-utils": "4.64.0", "@jsonjoy.com/fs-print": "4.64.0", "@jsonjoy.com/fs-snapshot": "4.64.0", "@jsonjoy.com/json-pack": "^1.11.0", "@jsonjoy.com/util": "^1.9.0", "glob-to-regex.js": "^1.0.1", "thingies": "^2.5.0", "tree-dump": "^1.0.3", "tslib": "^2.0.0" } }, "sha512-Kw72fgY7Wn+sD8KmtNWSafl1dz0UvAsE/PHs3YVfLiaZuA3HxNm9sRLqAu0ATiBGJvME1PxZXbBZPv5GycDeAw=="], "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], @@ -1973,9 +2208,9 @@ "mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], - "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "mime-types": ["mime-types@2.1.18", "", { "dependencies": { "mime-db": "~1.33.0" } }, "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ=="], "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], @@ -1989,19 +2224,21 @@ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "minimizer-webpack-plugin": ["minimizer-webpack-plugin@5.6.1", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "terser": "^5.31.1" }, "peerDependencies": { "@minify-html/node": "*", "@swc/core": "*", "@swc/css": "*", "@swc/html": "*", "clean-css": "*", "cssnano": "*", "csso": "*", "esbuild": "*", "html-minifier-terser": "*", "lightningcss": "*", "postcss": "*", "uglify-js": "*", "webpack": "^5.1.0" }, "optionalPeers": ["@minify-html/node", "@swc/core", "@swc/css", "@swc/html", "clean-css", "cssnano", "csso", "esbuild", "html-minifier-terser", "lightningcss", "postcss", "uglify-js"] }, "sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw=="], + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "msgpackr": ["msgpackr@1.11.10", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-iCZNq+HszvF+fC3anCm4nBmWEnbeIAfpDs6IStAEKhQ2YSgkjzVG2FF9XJqwwQh5bH3N9OUTUt4QwVN6MLMLtA=="], + "msgpackr": ["msgpackr@1.12.1", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-4EUH9tQHnMmEgzW/MdAP0KIfa1T9AF+htl0ffe2n5vb2EKn9y2co8ccpgWko6S52Jy1PQZKwRnx5/KkYjtd9MQ=="], - "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.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="], "multicast-dns": ["multicast-dns@7.2.5", "", { "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" }, "bin": { "multicast-dns": "cli.js" } }, "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg=="], - "multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="], + "multipasta": ["multipasta@0.2.8", "", {}, "sha512-ZPWuMKyv0cSO29f7hozp+k6+crZbQijV8ipMvxNxRf2SwtYGTX1ZX89Kd20VV4H9Znonx+EQn+iy1wGQsJ+b+Q=="], - "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], + "nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="], "negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], @@ -2013,13 +2250,13 @@ "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.36", "", {}, "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA=="], + "node-releases": ["node-releases@2.0.51", "", {}, "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], "normalize-url": ["normalize-url@8.1.1", "", {}, "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ=="], - "npm-check-updates": ["npm-check-updates@22.2.1", "", { "bin": { "npm-check-updates": "build/cli.js", "ncu": "build/cli.js" } }, "sha512-mGdIJfhtg+q0BzhbOpbOL73zhMZlgBQMG4wnBwPMMD5k96028UCuV0753YeSYk9odoh7HWK6/cY69bWxT7o+yg=="], + "npm-check-updates": ["npm-check-updates@22.2.9", "", { "bin": { "npm-check-updates": "build/cli.js", "ncu": "build/cli.js" } }, "sha512-DVeZ0KirHfliSsHuR2o7cHE+tW439sVHfJjF6cGWeDiY0Wyl3BI/jS4zV0eixtcMOquFbcF1Su/FsxOvk5MoYA=="], "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], @@ -2031,6 +2268,8 @@ "null-loader": ["null-loader@4.0.1", "", { "dependencies": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" }, "peerDependencies": { "webpack": "^4.0.0 || ^5.0.0" } }, "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg=="], + "nwsapi": ["nwsapi@2.2.24", "", {}, "sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], @@ -2101,15 +2340,17 @@ "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + "picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="], "pkg-dir": ["pkg-dir@7.0.0", "", { "dependencies": { "find-up": "^6.3.0" } }, "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA=="], "pkijs": ["pkijs@3.4.0", "", { "dependencies": { "@noble/hashes": "1.4.0", "asn1js": "^3.0.6", "bytestreamjs": "^2.0.1", "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw=="], - "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], + "postcss": ["postcss@8.5.19", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ=="], "postcss-attribute-case-insensitive": ["postcss-attribute-case-insensitive@7.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw=="], @@ -2229,7 +2470,7 @@ "postcss-selector-not": ["postcss-selector-not@8.0.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA=="], - "postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="], + "postcss-selector-parser": ["postcss-selector-parser@7.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg=="], "postcss-sort-media-queries": ["postcss-sort-media-queries@5.2.0", "", { "dependencies": { "sort-css-media-queries": "2.2.0" }, "peerDependencies": { "postcss": "^8.4.23" } }, "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA=="], @@ -2241,10 +2482,12 @@ "postcss-zindex": ["postcss-zindex@6.0.2", "", { "peerDependencies": { "postcss": "^8.4.31" } }, "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg=="], - "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], + "prettier": ["prettier@3.9.5", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg=="], "pretty-error": ["pretty-error@4.0.0", "", { "dependencies": { "lodash": "^4.17.20", "renderkid": "^3.0.0" } }, "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw=="], + "pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="], + "pretty-time": ["pretty-time@1.1.0", "", {}, "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA=="], "prism-react-renderer": ["prism-react-renderer@2.4.1", "", { "dependencies": { "@types/prismjs": "^1.26.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": ">=16.0.0" } }, "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig=="], @@ -2257,7 +2500,7 @@ "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], - "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + "property-information": ["property-information@7.2.0", "", {}, "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg=="], "proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="], @@ -2273,13 +2516,13 @@ "pvutils": ["pvutils@1.1.5", "", {}, "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA=="], - "qs": ["qs@6.14.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q=="], + "qs": ["qs@6.15.3", "", { "dependencies": { "es-define-property": "^1.0.1", "side-channel": "^1.1.1" } }, "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="], - "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.6.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.5", "@radix-ui/react-accessible-icon": "1.1.11", "@radix-ui/react-accordion": "1.2.16", "@radix-ui/react-alert-dialog": "1.1.19", "@radix-ui/react-arrow": "1.1.11", "@radix-ui/react-aspect-ratio": "1.1.11", "@radix-ui/react-avatar": "1.2.2", "@radix-ui/react-checkbox": "1.3.7", "@radix-ui/react-collapsible": "1.1.16", "@radix-ui/react-collection": "1.1.12", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.2.0", "@radix-ui/react-context-menu": "2.3.3", "@radix-ui/react-dialog": "1.1.19", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.15", "@radix-ui/react-dropdown-menu": "2.1.20", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.12", "@radix-ui/react-form": "0.1.12", "@radix-ui/react-hover-card": "1.1.19", "@radix-ui/react-label": "2.1.11", "@radix-ui/react-menu": "2.1.20", "@radix-ui/react-menubar": "1.1.20", "@radix-ui/react-navigation-menu": "1.2.18", "@radix-ui/react-one-time-password-field": "0.1.12", "@radix-ui/react-password-toggle-field": "0.1.7", "@radix-ui/react-popover": "1.1.19", "@radix-ui/react-popper": "1.3.3", "@radix-ui/react-portal": "1.1.13", "@radix-ui/react-presence": "1.1.7", "@radix-ui/react-primitive": "2.1.7", "@radix-ui/react-progress": "1.1.12", "@radix-ui/react-radio-group": "1.4.3", "@radix-ui/react-roving-focus": "1.1.15", "@radix-ui/react-scroll-area": "1.2.14", "@radix-ui/react-select": "2.3.3", "@radix-ui/react-separator": "1.1.11", "@radix-ui/react-slider": "1.4.3", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-switch": "1.3.3", "@radix-ui/react-tabs": "1.1.17", "@radix-ui/react-toast": "1.2.19", "@radix-ui/react-toggle": "1.1.14", "@radix-ui/react-toggle-group": "1.1.15", "@radix-ui/react-toolbar": "1.1.15", "@radix-ui/react-tooltip": "1.2.12", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-escape-keydown": "1.1.3", "@radix-ui/react-use-is-hydrated": "0.1.1", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-size": "1.1.2", "@radix-ui/react-visually-hidden": "1.2.7" }, "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-OwYUjzMwiInCUxgAWpPsavXC3Kh4iyi/49uU1/qZTG3RQDlvegyk1GOMiGvSkjua1RDb3JD3fo3eroL9FV4GQw=="], "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], @@ -2289,15 +2532,15 @@ "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], - "react": ["react@19.2.6", "", {}, "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q=="], + "react": ["react@19.2.7", "", {}, "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ=="], - "react-dom": ["react-dom@19.2.6", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.6" } }, "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g=="], + "react-dom": ["react-dom@19.2.7", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.7" } }, "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ=="], "react-fast-compare": ["react-fast-compare@3.2.2", "", {}, "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="], "react-helmet-async": ["@slorber/react-helmet-async@1.3.0", "", { "dependencies": { "@babel/runtime": "^7.12.5", "invariant": "^2.2.4", "prop-types": "^15.7.2", "react-fast-compare": "^3.2.0", "shallowequal": "^1.1.0" }, "peerDependencies": { "react": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A=="], - "react-icons": ["react-icons@5.6.0", "", { "peerDependencies": { "react": "*" } }, "sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA=="], + "react-icons": ["react-icons@5.7.0", "", { "peerDependencies": { "react": "*" } }, "sha512-LBLy340Rzqy6+/yVhZKT3B/QpP1BZaesGqasf09HPOBzRarcDIFH0WwXlXQfE7q7ipxK4MSiC5DIBWURCny6fw=="], "react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], @@ -2345,7 +2588,7 @@ "regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="], - "regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="], + "regjsparser": ["regjsparser@0.13.2", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ=="], "rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", "vfile": "^6.0.0" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="], @@ -2377,7 +2620,7 @@ "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="], - "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + "resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="], "resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="], @@ -2391,7 +2634,11 @@ "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - "rolldown": ["rolldown@1.0.3", "", { "dependencies": { "@oxc-project/types": "=0.133.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.3", "@rolldown/binding-darwin-arm64": "1.0.3", "@rolldown/binding-darwin-x64": "1.0.3", "@rolldown/binding-freebsd-x64": "1.0.3", "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", "@rolldown/binding-linux-arm64-gnu": "1.0.3", "@rolldown/binding-linux-arm64-musl": "1.0.3", "@rolldown/binding-linux-ppc64-gnu": "1.0.3", "@rolldown/binding-linux-s390x-gnu": "1.0.3", "@rolldown/binding-linux-x64-gnu": "1.0.3", "@rolldown/binding-linux-x64-musl": "1.0.3", "@rolldown/binding-openharmony-arm64": "1.0.3", "@rolldown/binding-wasm32-wasi": "1.0.3", "@rolldown/binding-win32-arm64-msvc": "1.0.3", "@rolldown/binding-win32-x64-msvc": "1.0.3" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g=="], + "rolldown": ["rolldown@1.1.5", "", { "dependencies": { "@oxc-project/types": "=0.139.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.1.5", "@rolldown/binding-darwin-arm64": "1.1.5", "@rolldown/binding-darwin-x64": "1.1.5", "@rolldown/binding-freebsd-x64": "1.1.5", "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", "@rolldown/binding-linux-arm64-gnu": "1.1.5", "@rolldown/binding-linux-arm64-musl": "1.1.5", "@rolldown/binding-linux-ppc64-gnu": "1.1.5", "@rolldown/binding-linux-s390x-gnu": "1.1.5", "@rolldown/binding-linux-x64-gnu": "1.1.5", "@rolldown/binding-linux-x64-musl": "1.1.5", "@rolldown/binding-openharmony-arm64": "1.1.5", "@rolldown/binding-wasm32-wasi": "1.1.5", "@rolldown/binding-win32-arm64-msvc": "1.1.5", "@rolldown/binding-win32-x64-msvc": "1.1.5" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA=="], + + "rollup": ["rollup@4.62.2", "", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.62.2", "@rollup/rollup-android-arm64": "4.62.2", "@rollup/rollup-darwin-arm64": "4.62.2", "@rollup/rollup-darwin-x64": "4.62.2", "@rollup/rollup-freebsd-arm64": "4.62.2", "@rollup/rollup-freebsd-x64": "4.62.2", "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", "@rollup/rollup-linux-arm-musleabihf": "4.62.2", "@rollup/rollup-linux-arm64-gnu": "4.62.2", "@rollup/rollup-linux-arm64-musl": "4.62.2", "@rollup/rollup-linux-loong64-gnu": "4.62.2", "@rollup/rollup-linux-loong64-musl": "4.62.2", "@rollup/rollup-linux-ppc64-gnu": "4.62.2", "@rollup/rollup-linux-ppc64-musl": "4.62.2", "@rollup/rollup-linux-riscv64-gnu": "4.62.2", "@rollup/rollup-linux-riscv64-musl": "4.62.2", "@rollup/rollup-linux-s390x-gnu": "4.62.2", "@rollup/rollup-linux-x64-gnu": "4.62.2", "@rollup/rollup-linux-x64-musl": "4.62.2", "@rollup/rollup-openbsd-x64": "4.62.2", "@rollup/rollup-openharmony-arm64": "4.62.2", "@rollup/rollup-win32-arm64-msvc": "4.62.2", "@rollup/rollup-win32-ia32-msvc": "4.62.2", "@rollup/rollup-win32-x64-gnu": "4.62.2", "@rollup/rollup-win32-x64-msvc": "4.62.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA=="], + + "rrweb-cssom": ["rrweb-cssom@0.8.0", "", {}, "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw=="], "rtlcss": ["rtlcss@4.3.0", "", { "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0", "postcss": "^8.4.21", "strip-json-comments": "^3.1.1" }, "bin": { "rtlcss": "bin/rtlcss.js" } }, "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig=="], @@ -2405,6 +2652,8 @@ "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], + "saxes": ["saxes@6.0.0", "", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA=="], + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], "schema-dts": ["schema-dts@1.1.5", "", {}, "sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg=="], @@ -2419,7 +2668,7 @@ "selfsigned": ["selfsigned@5.5.0", "", { "dependencies": { "@peculiar/x509": "^1.14.2", "pkijs": "^3.3.3" } }, "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew=="], - "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], "semver-diff": ["semver-diff@4.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA=="], @@ -2427,9 +2676,9 @@ "serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="], - "seroval": ["seroval@1.5.4", "", {}, "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw=="], + "seroval": ["seroval@1.5.5", "", {}, "sha512-bSjOuPcwPKLSJNhr9+bZxA20nQxVle5J5MNsYRVE6cIg7KpRLXGupymePavu0jrxlPiPsr4xGZSB8yUY2sH2sw=="], - "seroval-plugins": ["seroval-plugins@1.5.4", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw=="], + "seroval-plugins": ["seroval-plugins@1.5.5", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-+BDhqYM6CEn3x09v44dpa9p6974FuUB2dxk+Ctn04k0cO1Zt6QODTXfmEZK0eBaTe/fJBvP4NMGuNJ+R8T+QMg=="], "serve-handler": ["serve-handler@6.1.7", "", { "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", "mime-types": "2.1.18", "minimatch": "3.1.5", "path-is-inside": "1.0.2", "path-to-regexp": "3.3.0", "range-parser": "1.2.0" } }, "sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg=="], @@ -2449,16 +2698,18 @@ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], + "shell-quote": ["shell-quote@1.10.0", "", {}, "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA=="], - "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + "side-channel": ["side-channel@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4", "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ=="], - "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + "side-channel-list": ["side-channel-list@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4" } }, "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w=="], "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], "sirv": ["sirv@2.0.4", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ=="], @@ -2489,10 +2740,10 @@ "spdy-transport": ["spdy-transport@3.0.0", "", { "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", "hpack.js": "^2.1.6", "obuf": "^1.1.2", "readable-stream": "^3.0.6", "wbuf": "^1.7.3" } }, "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw=="], - "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], - "srcset": ["srcset@4.0.0", "", {}, "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw=="], + "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], @@ -2513,6 +2764,8 @@ "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], @@ -2525,17 +2778,19 @@ "svg-parser": ["svg-parser@2.0.4", "", {}, "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ=="], - "svgo": ["svgo@3.3.3", "", { "dependencies": { "commander": "^7.2.0", "css-select": "^5.1.0", "css-tree": "^2.3.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.0.0", "sax": "^1.5.0" }, "bin": "./bin/svgo" }, "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng=="], + "svgo": ["svgo@3.3.4", "", { "dependencies": { "commander": "^7.2.0", "css-select": "^5.1.0", "css-tree": "^2.3.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.0.0", "sax": "^1.5.0" }, "bin": "./bin/svgo" }, "sha512-GsNRis4e8jxn2Y9ENz/8lbJ93CstG8svtMnuRaHbiF2LTJ5tK0/q3t/URPq9Zc7zVWBJnNnJMIp6bevK7bSmNg=="], "swc-loader": ["swc-loader@0.2.7", "", { "dependencies": { "@swc/counter": "^0.1.3" }, "peerDependencies": { "@swc/core": "^1.2.147", "webpack": ">=2" } }, "sha512-nwYWw3Fh9ame3Rtm7StS9SBLpHRRnYcK7bnpF3UKZmesAK0gw2/ADvlURFAINmPvKtDLzp+GBiP9yLoEjg6S9w=="], + "symbol-tree": ["symbol-tree@3.2.4", "", {}, "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="], + "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], - "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], + "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], - "terser": ["terser@5.46.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ=="], + "terser": ["terser@5.49.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA=="], - "terser-webpack-plugin": ["terser-webpack-plugin@5.4.0", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g=="], + "terser-webpack-plugin": ["terser-webpack-plugin@5.6.1", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ=="], "thingies": ["thingies@2.6.0", "", { "peerDependencies": { "tslib": "^2" } }, "sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg=="], @@ -2545,16 +2800,34 @@ "tiny-warning": ["tiny-warning@1.0.3", "", {}, "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="], + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], + + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], + "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], + + "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], + + "tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="], + + "tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="], + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + "toml": ["toml@4.3.0", "", {}, "sha512-lVb8X9BsPVuH0M4BKeS91tXAmJvCjQ5UIyAbQFaxkKGyUFK2RPkhwaFSQH8vbpl1d23eu/IBH+dwVMHWaq9A5A=="], + "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], + "tough-cookie": ["tough-cookie@5.1.2", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A=="], + + "tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="], + "tree-dump": ["tree-dump@1.1.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA=="], "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], @@ -2565,9 +2838,9 @@ "tsyringe": ["tsyringe@4.10.0", "", { "dependencies": { "tslib": "^1.9.3" } }, "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw=="], - "turbo": ["turbo@2.9.16", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.16", "@turbo/darwin-arm64": "2.9.16", "@turbo/linux-64": "2.9.16", "@turbo/linux-arm64": "2.9.16", "@turbo/windows-64": "2.9.16", "@turbo/windows-arm64": "2.9.16" }, "bin": { "turbo": "bin/turbo" } }, "sha512-NqgRQy6j6dPYcdSdv0q1g9QsZg7SWg87RERM8otw/1AtKU2yTFVClOM7cbwKzOonZr/Ek1blTBucw64L9H0Bwg=="], + "turbo": ["turbo@2.10.5", "", { "optionalDependencies": { "@turbo/darwin-64": "2.10.5", "@turbo/darwin-arm64": "2.10.5", "@turbo/linux-64": "2.10.5", "@turbo/linux-arm64": "2.10.5", "@turbo/windows-64": "2.10.5", "@turbo/windows-arm64": "2.10.5" }, "bin": { "turbo": "bin/turbo" } }, "sha512-07Y/C7OUp23l4P92PJoYtFNbHjLhftrZH5Ce7dbczS4kX2Re+wtbXvZLoxn/pUtzgsQaRCBaRuZPJp4zmAn0WQ=="], - "type-fest": ["type-fest@5.7.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg=="], + "type-fest": ["type-fest@5.8.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA=="], "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], @@ -2575,7 +2848,7 @@ "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], - "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], + "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], "unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="], @@ -2607,7 +2880,7 @@ "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], - "unplugin": ["unplugin@3.0.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg=="], + "unplugin": ["unplugin@3.3.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "picomatch": "^4.0.4", "webpack-virtual-modules": "^0.6.2" }, "peerDependencies": { "@farmfe/core": "*", "@rspack/core": "*", "bun-types-no-globals": "*", "esbuild": "*", "rolldown": "*", "rollup": "*", "unloader": "*", "vite": "*", "webpack": "*" }, "optionalPeers": ["@farmfe/core", "@rspack/core", "bun-types-no-globals", "esbuild", "rolldown", "rollup", "unloader", "vite", "webpack"] }, "sha512-qa66K+crbfyE6JK10GjvbJeRrOsuC/JpbnHctfyp/i4oBTxWOzJfRZyDiOk1PtErMFRu8JhsU/wPvOdBNWe5Rg=="], "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=="], @@ -2631,7 +2904,7 @@ "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], - "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "uuid": ["uuid@14.0.1", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew=="], "value-equal": ["value-equal@1.0.1", "", {}, "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="], @@ -2643,36 +2916,52 @@ "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], - "vite": ["vite@8.0.16", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", "rolldown": "1.0.3", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.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", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw=="], + "vite": ["vite@8.1.5", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.5", "postcss": "^8.5.17", "rolldown": "~1.1.5", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.3.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.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", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw=="], - "watchpack": ["watchpack@2.5.1", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg=="], + "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], + + "vitest": ["vitest@3.2.7", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.7", "@vitest/mocker": "3.2.7", "@vitest/pretty-format": "^3.2.7", "@vitest/runner": "3.2.7", "@vitest/snapshot": "3.2.7", "@vitest/spy": "3.2.7", "@vitest/utils": "3.2.7", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.7", "@vitest/ui": "3.2.7", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "./vitest.mjs" } }, "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg=="], + + "w3c-xmlserializer": ["w3c-xmlserializer@5.0.0", "", { "dependencies": { "xml-name-validator": "^5.0.0" } }, "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA=="], + + "watchpack": ["watchpack@2.5.2", "", { "dependencies": { "graceful-fs": "^4.1.2" } }, "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg=="], "wbuf": ["wbuf@1.7.3", "", { "dependencies": { "minimalistic-assert": "^1.0.0" } }, "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA=="], "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], - "webpack": ["webpack@5.105.4", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.16.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.20.0", "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "terser-webpack-plugin": "^5.3.17", "watchpack": "^2.5.1", "webpack-sources": "^3.3.4" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw=="], + "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], + + "webpack": ["webpack@5.108.4", "", { "dependencies": { "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.16.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.22.2", "es-module-lexer": "^2.1.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "graceful-fs": "^4.2.11", "loader-runner": "^4.3.2", "mime-db": "^1.54.0", "minimizer-webpack-plugin": "^5.6.1", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "watchpack": "^2.5.2", "webpack-sources": "^3.5.0" }, "peerDependencies": { "webpack-cli": "*" }, "optionalPeers": ["webpack-cli"], "bin": { "webpack": "bin/webpack.js" } }, "sha512-yur8LyJoeiWh47dErD+Ok7vlbmDsJ3UbbRPAoxbGJ54WpE2y5yVo5G/inUzujnYgw3tPmBRdn+G7PoxXaYC33w=="], "webpack-bundle-analyzer": ["webpack-bundle-analyzer@4.10.2", "", { "dependencies": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", "acorn-walk": "^8.0.0", "commander": "^7.2.0", "debounce": "^1.2.1", "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", "html-escaper": "^2.0.2", "opener": "^1.5.2", "picocolors": "^1.0.0", "sirv": "^2.0.3", "ws": "^7.3.1" }, "bin": { "webpack-bundle-analyzer": "lib/bin/analyzer.js" } }, "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw=="], "webpack-dev-middleware": ["webpack-dev-middleware@7.4.5", "", { "dependencies": { "colorette": "^2.0.10", "memfs": "^4.43.1", "mime-types": "^3.0.1", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "peerDependencies": { "webpack": "^5.0.0" }, "optionalPeers": ["webpack"] }, "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA=="], - "webpack-dev-server": ["webpack-dev-server@5.2.3", "", { "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", "@types/express": "^4.17.25", "@types/express-serve-static-core": "^4.17.21", "@types/serve-index": "^1.9.4", "@types/serve-static": "^1.15.5", "@types/sockjs": "^0.3.36", "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.2.1", "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.8.1", "connect-history-api-fallback": "^2.0.0", "express": "^4.22.1", "graceful-fs": "^4.2.6", "http-proxy-middleware": "^2.0.9", "ipaddr.js": "^2.1.0", "launch-editor": "^2.6.1", "open": "^10.0.3", "p-retry": "^6.2.0", "schema-utils": "^4.2.0", "selfsigned": "^5.5.0", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", "webpack-dev-middleware": "^7.4.2", "ws": "^8.18.0" }, "peerDependencies": { "webpack": "^5.0.0" }, "optionalPeers": ["webpack"], "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" } }, "sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ=="], + "webpack-dev-server": ["webpack-dev-server@5.2.6", "", { "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", "@types/express": "^4.17.25", "@types/express-serve-static-core": "^4.17.21", "@types/serve-index": "^1.9.4", "@types/serve-static": "^1.15.5", "@types/sockjs": "^0.3.36", "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.2.1", "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.8.1", "connect-history-api-fallback": "^2.0.0", "express": "^4.22.1", "graceful-fs": "^4.2.6", "http-proxy-middleware": "^2.0.9", "ipaddr.js": "^2.1.0", "launch-editor": "^2.14.1", "open": "^10.0.3", "p-retry": "^6.2.0", "schema-utils": "^4.2.0", "selfsigned": "^5.5.0", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", "webpack-dev-middleware": "^7.4.2", "ws": "^8.18.0" }, "peerDependencies": { "webpack": "^5.0.0", "webpack-cli": "*" }, "optionalPeers": ["webpack", "webpack-cli"], "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" } }, "sha512-HNLRmamRvVavZQ+avceZifmv8hmdUjg43t6MI4SqJDwFdW7RPQwH5vzGhDRZSX59SgfbeHhLnq3g+uooWo7pVw=="], "webpack-merge": ["webpack-merge@5.10.0", "", { "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", "wildcard": "^2.0.0" } }, "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA=="], - "webpack-sources": ["webpack-sources@3.3.4", "", {}, "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q=="], + "webpack-sources": ["webpack-sources@3.5.1", "", {}, "sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw=="], "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], "webpackbar": ["webpackbar@7.0.0", "", { "dependencies": { "ansis": "^3.2.0", "consola": "^3.2.3", "pretty-time": "^1.1.0", "std-env": "^3.7.0" }, "peerDependencies": { "@rspack/core": "*", "webpack": "3 || 4 || 5" }, "optionalPeers": ["@rspack/core", "webpack"] }, "sha512-aS9soqSO2iCHgqHoCrj4LbfGQUboDCYJPSFOAchEK+9psIjNrfSWW4Y0YEz67MKURNvMmfo0ycOg9d/+OOf9/Q=="], - "websocket-driver": ["websocket-driver@0.7.4", "", { "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg=="], + "websocket-driver": ["websocket-driver@0.7.5", "", { "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA=="], "websocket-extensions": ["websocket-extensions@0.1.4", "", {}, "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="], + "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="], + + "whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], + + "whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], + "widest-line": ["widest-line@4.0.1", "", { "dependencies": { "string-width": "^5.0.1" } }, "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig=="], "wildcard": ["wildcard@2.0.1", "", {}, "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ=="], @@ -2681,7 +2970,7 @@ "write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], - "ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + "ws": ["ws@8.21.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw=="], "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], @@ -2689,14 +2978,22 @@ "xml-js": ["xml-js@1.6.11", "", { "dependencies": { "sax": "^1.2.4" }, "bin": { "xml-js": "./bin/cli.js" } }, "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g=="], + "xml-name-validator": ["xml-name-validator@5.0.0", "", {}, "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg=="], + + "xmlchars": ["xmlchars@2.2.0", "", {}, "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="], + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], + "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + "@asamuzakjp/css-color/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -2711,24 +3008,18 @@ "@babel/preset-env/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@docusaurus/bundler/postcss": ["postcss@8.5.12", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA=="], + "@docsearch/react/@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.19.2", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", "@algolia/autocomplete-shared": "1.19.2" } }, "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw=="], "@docusaurus/core/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=="], "@docusaurus/core/webpack-merge": ["webpack-merge@6.0.1", "", { "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", "wildcard": "^2.0.1" } }, "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg=="], - "@docusaurus/cssnano-preset/postcss": ["postcss@8.5.12", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA=="], - - "@docusaurus/module-type-aliases/@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], - - "@docusaurus/theme-classic/postcss": ["postcss@8.5.12", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA=="], - - "@docusaurus/theme-common/@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], - - "@docusaurus/types/@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], - "@docusaurus/utils/jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], + "@effect-fc/example-next/@effect/platform-browser": ["@effect/platform-browser@4.0.0-beta.98", "", { "dependencies": { "multipasta": "^0.2.8" }, "peerDependencies": { "effect": "^4.0.0-beta.98" } }, "sha512-Y0BEe0N8clKmJTHqmZpS85pLZbqAxP5uV3IYF0tDw/1dcs8AbTRHjbRmOLdyLtmU32NBVAiaUD3Vopb5Et5R/g=="], + + "@effect-fc/example-next/effect": ["effect@4.0.0-beta.98", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.4", "multipasta": "^0.2.8", "toml": "^4.1.2", "uuid": "^14.0.1", "yaml": "^2.9.0" } }, "sha512-oz+bsG5h+6RNrw4t5GMfQrk/xBS8ROoqkYsuvRhBr5O7mCOrpvH/hbw+QrDzvKIpX4HJClwm86F94c87W0sJxg=="], + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack": ["@jsonjoy.com/json-pack@17.67.0", "", { "dependencies": { "@jsonjoy.com/base64": "17.67.0", "@jsonjoy.com/buffers": "17.67.0", "@jsonjoy.com/codegen": "17.67.0", "@jsonjoy.com/json-pointer": "17.67.0", "@jsonjoy.com/util": "17.67.0", "hyperdyperid": "^1.2.0", "thingies": "^2.5.0", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w=="], "@jsonjoy.com/fs-snapshot/@jsonjoy.com/util": ["@jsonjoy.com/util@17.67.0", "", { "dependencies": { "@jsonjoy.com/buffers": "17.67.0", "@jsonjoy.com/codegen": "17.67.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew=="], @@ -2741,11 +3032,9 @@ "@rspack/binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], - "@types/react-router/@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], + "@svgr/hast-util-to-babel-ast/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], - "@types/react-router-config/@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], - - "@types/react-router-dom/@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], + "accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], @@ -2759,6 +3048,8 @@ "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + "boxen/type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="], "cheerio-select/css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], @@ -2767,8 +3058,6 @@ "cli-table3/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "compressible/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "compression/bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], @@ -2781,26 +3070,24 @@ "crypto-random-string/type-fest": ["type-fest@1.4.0", "", {}, "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA=="], - "css-loader/postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], - "css-minimizer-webpack-plugin/jest-worker": ["jest-worker@29.7.0", "", { "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw=="], - "css-minimizer-webpack-plugin/postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], - "css-select/domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="], "css-select/domutils": ["domutils@2.8.0", "", { "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", "domhandler": "^4.2.0" } }, "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A=="], - "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], - "decompress-response/mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - "docs/react": ["react@19.2.5", "", {}, "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA=="], - - "docs/react-dom": ["react-dom@19.2.5", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.5" } }, "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag=="], + "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "dot-prop/is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], + "effect-fc-next/@effect/platform-browser": ["@effect/platform-browser@4.0.0-beta.98", "", { "dependencies": { "multipasta": "^0.2.8" }, "peerDependencies": { "effect": "^4.0.0-beta.98" } }, "sha512-Y0BEe0N8clKmJTHqmZpS85pLZbqAxP5uV3IYF0tDw/1dcs8AbTRHjbRmOLdyLtmU32NBVAiaUD3Vopb5Et5R/g=="], + + "effect-fc-next/effect": ["effect@4.0.0-beta.98", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.4", "multipasta": "^0.2.8", "toml": "^4.1.2", "uuid": "^14.0.1", "yaml": "^2.9.0" } }, "sha512-oz+bsG5h+6RNrw4t5GMfQrk/xBS8ROoqkYsuvRhBr5O7mCOrpvH/hbw+QrDzvKIpX4HJClwm86F94c87W0sJxg=="], + + "effect-fc-next/effect-lens": ["effect-lens@2.0.0-beta.1", "", { "peerDependencies": { "effect": "4.0.0-beta.98" } }, "sha512-3MwsrezPczZHH4Tl2SvliZdiNRq9e/XbH+Vr1ckr/FPCEp6Wv8IYQL4Ie/hhI+XBiLlxbQERbgL8FlHW21avtw=="], + "esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], "express/content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], @@ -2815,16 +3102,20 @@ "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "got/@sindresorhus/is": ["@sindresorhus/is@5.6.0", "", {}, "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g=="], + "global-dirs/ini": ["ini@2.0.0", "", {}, "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA=="], - "gray-matter/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], + "got/@sindresorhus/is": ["@sindresorhus/is@5.6.0", "", {}, "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g=="], "hpack.js/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "html-minifier-terser/commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], + "html-minifier-terser/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "html-webpack-plugin/html-minifier-terser": ["html-minifier-terser@6.1.0", "", { "dependencies": { "camel-case": "^4.1.2", "clean-css": "^5.2.2", "commander": "^8.3.0", "he": "^1.2.0", "param-case": "^3.0.4", "relateurl": "^0.2.7", "terser": "^5.10.0" }, "bin": { "html-minifier-terser": "cli.js" } }, "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw=="], + "htmlparser2/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "http-proxy-middleware/is-plain-obj": ["is-plain-obj@3.0.0", "", {}, "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA=="], "is-inside-container/is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], @@ -2957,74 +3248,96 @@ "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + "mime-types/mime-db": ["mime-db@1.33.0", "", {}, "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="], + "null-loader/schema-utils": ["schema-utils@3.3.0", "", { "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } }, "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg=="], "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], - "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "postcss-calc/postcss-selector-parser": ["postcss-selector-parser@6.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ=="], - "postcss-calc/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], - - "postcss-discard-unused/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + "postcss-discard-unused/postcss-selector-parser": ["postcss-selector-parser@6.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ=="], "postcss-loader/jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], - "postcss-merge-rules/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + "postcss-merge-rules/postcss-selector-parser": ["postcss-selector-parser@6.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ=="], - "postcss-minify-selectors/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + "postcss-minify-selectors/postcss-selector-parser": ["postcss-selector-parser@6.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ=="], - "postcss-unique-selectors/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + "postcss-unique-selectors/postcss-selector-parser": ["postcss-selector-parser@6.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ=="], + + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], "proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], "raw-body/bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + "rc/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], - "react-loadable/@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], - "renderkid/htmlparser2": ["htmlparser2@6.1.0", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", "domutils": "^2.5.2", "entities": "^2.0.0" } }, "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A=="], "renderkid/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "rtlcss/postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], - "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], - "serve-handler/mime-types": ["mime-types@2.1.18", "", { "dependencies": { "mime-db": "~1.33.0" } }, "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ=="], - "serve-handler/path-to-regexp": ["path-to-regexp@3.3.0", "", {}, "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw=="], "serve-index/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "serve-index/http-errors": ["http-errors@1.8.1", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.1" } }, "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g=="], + "serve-index/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "sitemap/@types/node": ["@types/node@17.0.45", "", {}, "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="], + "sockjs/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "stylehacks/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + "strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + + "stylehacks/postcss-selector-parser": ["postcss-selector-parser@6.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ=="], "svgo/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], "svgo/css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + "svgo/css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="], + "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], "tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + "type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "update-notifier/boxen": ["boxen@7.1.1", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^7.0.1", "chalk": "^5.2.0", "cli-boxes": "^3.0.0", "string-width": "^5.1.2", "type-fest": "^2.13.0", "widest-line": "^4.0.1", "wrap-ansi": "^8.1.0" } }, "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog=="], "update-notifier/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + "url-loader/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "url-loader/schema-utils": ["schema-utils@3.3.0", "", { "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } }, "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg=="], + "vite-node/es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + + "vite-node/vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.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-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="], + + "vitest/vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.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-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="], + "webpack-bundle-analyzer/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + "webpack-bundle-analyzer/ws": ["ws@7.5.13", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA=="], + "webpack-dev-middleware/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], "webpack-dev-middleware/range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], @@ -3033,21 +3346,21 @@ "webpack-dev-server/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], - "webpack-dev-server/ws": ["ws@8.20.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA=="], - "webpackbar/ansis": ["ansis@3.17.0", "", {}, "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg=="], "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "wsl-utils/is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], - "@docusaurus/bundler/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "@docsearch/react/@algolia/autocomplete-core/@algolia/autocomplete-plugin-algolia-insights": ["@algolia/autocomplete-plugin-algolia-insights@1.19.2", "", { "dependencies": { "@algolia/autocomplete-shared": "1.19.2" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg=="], + + "@docsearch/react/@algolia/autocomplete-core/@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.19.2", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w=="], "@docusaurus/core/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "@docusaurus/cssnano-preset/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "@effect-fc/example-next/effect/fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="], - "@docusaurus/theme-classic/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "@effect-fc/example-next/effect/msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="], "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack/@jsonjoy.com/base64": ["@jsonjoy.com/base64@17.67.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw=="], @@ -3057,6 +3370,8 @@ "@jsonjoy.com/fs-snapshot/@jsonjoy.com/util/@jsonjoy.com/codegen": ["@jsonjoy.com/codegen@17.67.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q=="], + "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -3071,26 +3386,22 @@ "copy-webpack-plugin/globby/slash": ["slash@4.0.0", "", {}, "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew=="], - "css-loader/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "css-minimizer-webpack-plugin/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "css-minimizer-webpack-plugin/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "css-select/domutils/dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], - "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], + "effect-fc-next/effect/fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="], + + "effect-fc-next/effect/msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="], "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "file-loader/schema-utils/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + "file-loader/schema-utils/ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], "file-loader/schema-utils/ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - "hpack.js/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], "hpack.js/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], @@ -3101,7 +3412,7 @@ "mdast-util-gfm-autolink-literal/micromark-util-character/micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], - "null-loader/schema-utils/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + "null-loader/schema-utils/ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], "null-loader/schema-utils/ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], @@ -3111,42 +3422,42 @@ "renderkid/htmlparser2/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], - "renderkid/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "rtlcss/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "serve-handler/mime-types/mime-db": ["mime-db@1.33.0", "", {}, "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="], - "serve-index/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "serve-index/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], "serve-index/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], + "serve-index/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "svgo/css-tree/mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="], + + "type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "update-notifier/boxen/camelcase": ["camelcase@7.0.1", "", {}, "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw=="], "update-notifier/boxen/type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="], - "url-loader/schema-utils/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + "url-loader/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "url-loader/schema-utils/ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], "url-loader/schema-utils/ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], - "webpack-dev-middleware/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "webpack-dev-server/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "webpack-dev-server/open/define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], "@docusaurus/core/chokidar/readdirp/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - "ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "cli-table3/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@effect-fc/example-next/effect/fast-check/pure-rand": ["pure-rand@8.4.2", "", {}, "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng=="], "css-select/domutils/dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], + "effect-fc-next/effect/fast-check/pure-rand": ["pure-rand@8.4.2", "", {}, "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng=="], + "file-loader/schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], "null-loader/schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], diff --git a/package.json b/package.json index 3005ac9..b50664d 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,10 @@ "./packages/*" ], "scripts": { - "build": "turbo build", "lint:tsc": "turbo lint:tsc", "lint:biome": "turbo lint:biome", + "test": "turbo test", + "build": "turbo build", "pack": "turbo pack", "clean:cache": "turbo clean:cache", "clean:dist": "turbo clean:dist", diff --git a/packages/docs/README.md b/packages/docs/README.md index b28211a..189dc20 100644 --- a/packages/docs/README.md +++ b/packages/docs/README.md @@ -1,41 +1,17 @@ -# Website +# effect-fc Docs -This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. - -## Installation - -```bash -yarn -``` +The documentation site is built with Docusaurus. ## Local Development ```bash -yarn start +bun run --cwd packages/docs start ``` -This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. - ## Build ```bash -yarn build +bun run --cwd packages/docs build ``` -This command generates static content into the `build` directory and can be served using any static contents hosting service. - -## Deployment - -Using SSH: - -```bash -USE_SSH=true yarn deploy -``` - -Not using SSH: - -```bash -GIT_USER= yarn deploy -``` - -If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. +The static site is written to `packages/docs/build`. diff --git a/packages/docs/biome.json b/packages/docs/biome.json index 41d707b..8182858 100644 --- a/packages/docs/biome.json +++ b/packages/docs/biome.json @@ -4,5 +4,15 @@ "extends": "//", "files": { "includes": ["./src/**"] + }, + "linter": { + "rules": { + "complexity": { + "noImportantStyles": "off" + }, + "style": { + "noDescendingSpecificity": "off" + } + } } } diff --git a/packages/docs/blog/2019-05-28-first-blog-post.md b/packages/docs/blog/2019-05-28-first-blog-post.md deleted file mode 100644 index 8fc0194..0000000 --- a/packages/docs/blog/2019-05-28-first-blog-post.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -slug: first-blog-post -title: First Blog Post -authors: [slorber, yangshun] -tags: [hola, docusaurus] ---- - -Lorem ipsum dolor sit amet... - -...consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/packages/docs/blog/2019-05-29-long-blog-post.md b/packages/docs/blog/2019-05-29-long-blog-post.md deleted file mode 100644 index 0705713..0000000 --- a/packages/docs/blog/2019-05-29-long-blog-post.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -slug: long-blog-post -title: Long Blog Post -authors: yangshun -tags: [hello, docusaurus] ---- - -This is the summary of a very long blog post, - -Use a `` comment to limit blog post size in the list view. - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/packages/docs/blog/2021-08-01-mdx-blog-post.mdx b/packages/docs/blog/2021-08-01-mdx-blog-post.mdx deleted file mode 100644 index 0c4b4a4..0000000 --- a/packages/docs/blog/2021-08-01-mdx-blog-post.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -slug: mdx-blog-post -title: MDX Blog Post -authors: [slorber] -tags: [docusaurus] ---- - -Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/). - -:::tip - -Use the power of React to create interactive blog posts. - -::: - -{/* truncate */} - -For example, use JSX to create an interactive button: - -```js - -``` - - diff --git a/packages/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg b/packages/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg deleted file mode 100644 index 11bda09..0000000 Binary files a/packages/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg and /dev/null differ diff --git a/packages/docs/blog/2021-08-26-welcome/index.md b/packages/docs/blog/2021-08-26-welcome/index.md deleted file mode 100644 index 69ca7be..0000000 --- a/packages/docs/blog/2021-08-26-welcome/index.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -slug: welcome -title: Welcome -authors: [slorber, yangshun] -tags: [facebook, hello, docusaurus] ---- - -[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog). - -Here are a few tips you might find useful. - -Simply add Markdown files (or folders) to the `blog` directory. - -Regular blog authors can be added to `authors.yml`. - -The blog post date can be extracted from filenames, such as: - -- `2019-05-30-welcome.md` -- `2019-05-30-welcome/index.md` - -A blog post folder can be convenient to co-locate blog post images: - -![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg) - -The blog supports tags as well! - -**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config. diff --git a/packages/docs/blog/authors.yml b/packages/docs/blog/authors.yml deleted file mode 100644 index 0fd3987..0000000 --- a/packages/docs/blog/authors.yml +++ /dev/null @@ -1,25 +0,0 @@ -yangshun: - name: Yangshun Tay - title: Ex-Meta Staff Engineer, Co-founder GreatFrontEnd - url: https://linkedin.com/in/yangshun - image_url: https://github.com/yangshun.png - page: true - socials: - x: yangshunz - linkedin: yangshun - github: yangshun - newsletter: https://www.greatfrontend.com - -slorber: - name: Sébastien Lorber - title: Docusaurus maintainer - url: https://sebastienlorber.com - image_url: https://github.com/slorber.png - page: - # customize the url of the author page at /blog/authors/ - permalink: '/all-sebastien-lorber-articles' - socials: - x: sebastienlorber - linkedin: sebastienlorber - github: slorber - newsletter: https://thisweekinreact.com diff --git a/packages/docs/blog/tags.yml b/packages/docs/blog/tags.yml deleted file mode 100644 index bfaa778..0000000 --- a/packages/docs/blog/tags.yml +++ /dev/null @@ -1,19 +0,0 @@ -facebook: - label: Facebook - permalink: /facebook - description: Facebook tag description - -hello: - label: Hello - permalink: /hello - description: Hello tag description - -docusaurus: - label: Docusaurus - permalink: /docusaurus - description: Docusaurus tag description - -hola: - label: Hola - permalink: /hola - description: Hola tag description diff --git a/packages/docs/docs/forms.md b/packages/docs/docs/forms.md new file mode 100644 index 0000000..115300b --- /dev/null +++ b/packages/docs/docs/forms.md @@ -0,0 +1,457 @@ +--- +sidebar_position: 5 +title: Forms +--- + +# Forms + +Effect View forms are built from an Effect `Schema`. The schema is the source of +truth for the shape of the form, its validation rules, and the value your +application receives. The form layer supplies reactive state and lifecycle; it +does not replace your UI components. + +A schema distinguishes the **encoded value** edited by the UI from the +**decoded value** used by the application. For example, an `` edits an +age as a string, while the submit handler or application state receives a +number: + +```tsx +import { Schema } from "effect" + +const ProfileSchema = Schema.Struct({ + displayName: Schema.String.check( + Schema.isMinLength(1, { message: "Enter a display name" }), + ), + age: Schema.NumberFromString, + contact: Schema.Struct({ + email: Schema.String.check( + Schema.isPattern(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, { + message: "Enter a valid email address", + }), + ), + }), +}) +``` + +That schema gives the form several useful properties: + +- Validation stays next to the data definition instead of being duplicated in + components and submit handlers. +- Inputs can keep UI-friendly encoded values while business logic receives + decoded, typed values. +- Nested schema issue paths can be routed automatically to the matching + subform or field. +- Synchronous and effectful schema validation use the same form model. +- The same schema can validate a local draft or protect writes to shared state. + +There are two concrete root form implementations. Choose one based on where a +valid decoded value should go: + +| Implementation | Owns a local draft | What happens to a valid value | +| --- | --- | --- | +| `MutationForm` | Yes | It is passed to a mutation when `submit` runs. | +| `LensForm` | Yes | It is written automatically to a target `Lens`. | + +## MutationForm: validate, then submit + +Use `MutationForm` for registration, checkout, search, and other workflows with +an explicit submit action. It owns the encoded draft, continuously decodes it +with the schema, and exposes the last valid decoded value. Calling `submit` +runs the mutation only when the form can commit. + +```tsx +import { Effect } from "effect" +import { Component, MutationForm, View } from "effect-view" + +const CreateProfileView = Component.make("CreateProfile")(function* () { + const form = yield* Component.useOnMount(() => + MutationForm.service({ + schema: ProfileSchema, + initialEncodedValue: { + displayName: "", + age: "", + contact: { email: "" }, + }, + f: ([profile]) => + Effect.log( + `Creating ${profile.displayName}, age ${profile.age}`, + ), + }), + ) + + const [canCommit, isCommitting] = yield* View.useAll([ + form.canCommit, + form.isCommitting, + ]) + const runPromise = yield* Component.useRunPromise() + + // Focused inputs are added in "Focus into subforms" below. + return ( + + ) +}) +``` + +Notice that `age` starts as a string because it is an encoded input value. The +mutation receives the schema's decoded profile, so `profile.age` is a number. +Schema transformations happen before the mutation and schema issues prevent an +invalid draft from being submitted. + +`MutationForm.service` also starts initial validation in the current scope. Use +it inside `Component.useOnMount`, a scoped service, or another Effect scope so +its validation and mutation work is cleaned up with its owner. + +## LensForm: validate, then synchronize + +Use `LensForm` for settings panels, inspectors, and edit screens where valid +changes should update existing state without a final submit. Its target holds +decoded application data; the form derives an encoded draft from that target +and keeps the two synchronized in both directions. + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, LensForm, View } from "effect-view" + +const EditProfileView = Component.make("EditProfile")(function* () { + const [form, profile] = yield* Component.useOnMount(() => + Effect.gen(function* () { + const profile = Lens.fromSubscriptionRef( + yield* SubscriptionRef.make({ + displayName: "Ada", + age: 37, + contact: { email: "ada@example.com" }, + }), + ) + + const form = yield* LensForm.service({ + schema: ProfileSchema, + target: profile, + }) + + return [form, profile] as const + }), + ) + + const [savedProfile, isCommitting] = yield* View.useAll([ + profile, + form.isCommitting, + ]) + + // Focused inputs are added in "Focus into subforms" below. + return ( + + {isCommitting + ? "Saving..." + : `${savedProfile.displayName} is ${savedProfile.age}`} + + ) +}) +``` + +Here the target contains `age: 37`, while the form exposes the encoded value +`age: "37"` to an input. A valid edit is decoded and written to `profile`. +Invalid input remains in the form so the user can correct it, but it never +reaches the target. If another part of the application updates the target, +`LensForm` encodes that value back into the draft. + +Pass `initialEncodedValue` only when the first draft should differ from the +encoded target. Otherwise `LensForm.service` obtains the initial draft by +encoding the target through the schema. + +## Example: local date input, UTC domain value + +The encoded/decoded distinction is especially useful for dates. An HTML +`datetime-local` input produces a wall-clock string such as +`"2026-07-22T14:30"`. It contains no time-zone or UTC offset, while application +state and APIs usually need an unambiguous UTC instant. + +A schema can own that entire conversion. The following schema interprets the +input in the current time zone and decodes it to `DateTime.Utc`: + +```tsx title="src/DateTimeUtcFromZonedInput.ts" +import { DateTime, Effect, Option, ParseResult, Schema } from "effect" + +class DateTimeUtcFromZoned extends Schema.transformOrFail( + Schema.DateTimeZonedFromSelf, + Schema.DateTimeUtcFromSelf, + { + strict: true, + decode: (input) => ParseResult.succeed(DateTime.toUtc(input)), + encode: DateTime.setZoneCurrent, + }, +) {} + +export class DateTimeUtcFromZonedInput extends Schema.transformOrFail( + Schema.String, + DateTimeUtcFromZoned, + { + strict: true, + decode: (input, _options, ast) => + Effect.flatMap(DateTime.CurrentTimeZone, (timeZone) => + Option.match( + DateTime.makeZoned(input, { + timeZone, + adjustForTimeZone: true, + }), + { + onSome: ParseResult.succeed, + onNone: () => + ParseResult.fail( + new ParseResult.Type( + ast, + input, + "Enter a valid date and time", + ), + ), + }, + ), + ), + encode: (value) => + ParseResult.succeed( + DateTime.formatIsoZoned(value).slice(0, 16), + ), + }, +) {} +``` + +Use it like any other field schema. The form and input work with a string, but +the mutation receives UTC: + +```tsx +import { DateTime, Effect, Schema } from "effect" +import { Component, Form, MutationForm, View } from "effect-view" +import { DateTimeUtcFromZonedInput } from "./DateTimeUtcFromZonedInput" + +const AppointmentSchema = Schema.Struct({ + startsAt: DateTimeUtcFromZonedInput, +}) + +const AppointmentView = Component.make("Appointment")(function* () { + const [form, startsAtField] = yield* Component.useOnMount(() => + Effect.gen(function* () { + const form = yield* MutationForm.service({ + schema: AppointmentSchema, + initialEncodedValue: { startsAt: "" }, + f: ([appointment]) => + Effect.log( + `Saving ${DateTime.formatIso(appointment.startsAt)}`, + ), + }) + + return [form, Form.focusObjectOn(form, "startsAt")] as const + }), + ) + + const startsAt = yield* Form.useInput(startsAtField) + const [canCommit] = yield* View.useAll([form.canCommit]) + const runPromise = yield* Component.useRunPromise() + + return ( +
{ + event.preventDefault() + void runPromise(form.submit) + }} + > + + startsAt.setValue(event.currentTarget.value) + } + /> + +
+ ) +}) +``` + +The schema requires `DateTime.CurrentTimeZone`; provide +`DateTime.layerCurrentZoneLocal` in the application runtime. If the current +zone is `Europe/Paris`, for example, entering `2026-07-22T14:30` decodes to the +UTC instant `2026-07-22T12:30:00.000Z`. + +Encoding works in the other direction. A `LensForm` whose target contains that +UTC instant presents `2026-07-22T14:30` to the local input. The component never +manually parses dates, applies offsets, or maintains a second representation; +the schema defines both directions and the form keeps them synchronized. + +## Focus into subforms + +The root `MutationForm` or `LensForm` represents the complete schema. UI +components usually need a smaller form representing one field, so they do not +have to receive or understand the entire root form. **Focusing** creates that +smaller form. + +Every root form and every focused subform implements the same `Form.Form` +interface. There is no separate field abstraction: an individual field is +simply a `Form` focused on that part of its parent. + +```tsx +const displayNameField = Form.focusObjectOn(form, "displayName") +const ageField = Form.focusObjectOn(form, "age") + +const contactForm = Form.focusObjectOn(form, "contact") +const emailField = Form.focusObjectOn(contactForm, "email") +``` + +`displayNameField`, `ageField`, and `emailField` can each be passed to the input +component responsible for that field. Focusing can also be repeated: +`contactForm` represents the complete contact section, and `emailField` +represents its email field. + +A focused form exposes only the relevant: + +- `encodedValue`: the UI-facing value that can be edited. +- `value`: the decoded value as an `Option`. +- `issues`: the schema issues for that subform. + +Validation and commit state remain connected to the root form. An input can +show its own issues while still observing the root form's `isValidating`, +`canCommit`, and `isCommitting` state. + +Use the focusing helper that matches the value being represented: + +```tsx +const property = Form.focusObjectOn(form, "contact") +const item = Form.focusArrayAt(itemsForm, 0) +const tupleMember = Form.focusTupleAt(tupleForm, 1) +const chunkItem = Form.focusChunkAt(chunkForm, 0) +``` + +Schema issue paths are focused at the same time. A component receiving +`emailField` gets its email issues directly instead of searching through every +issue on the root form. + +## Bind a subform to an input + +`Form.useInput` is the liaison between an Effect form and a React controlled +component. It reads the subform's encoded value and returns the familiar React +`{ value, setValue }` interface. Calling `setValue` updates the form, which in +turn runs the schema pipeline and updates validation state. + +```tsx +const input = yield* Form.useInput(emailField, { + debounce: "250 millis", +}) + +return ( + input.setValue(event.currentTarget.value)} + /> +) +``` + +The debounce is useful for text inputs, which can otherwise update the form and +run schema validation on every keystroke. The displayed value still updates +immediately; propagation to the form waits until the user pauses typing. + +Use `Form.useOptionalInput` when the encoded field is an Effect `Option`. It +returns `value` and `setValue` together with `enabled` and `setEnabled`, making +it suitable for an optional input that the user can toggle on and off. + +`useInput` and `useOptionalInput` can be used directly, but they are primarily +building blocks for your own reusable input components. A component library +can wrap them to consistently handle labels, validation issues, validating +indicators, disabled state, accessibility, styling, and a standard debounce. +Because both hooks accept a `Form.Form`, the same input components work with +subforms from both `MutationForm` and `LensForm`. + +```tsx title="TextFieldFormInputView.tsx" +import { Callout, Flex, Spinner, TextField } from "@radix-ui/themes" +import { Array, Option, Struct } from "effect" +import { Component, Form, View } from "effect-view" +import type * as React from "react" + +export declare namespace TextFieldFormInputView { + export interface Props< + out P extends readonly PropertyKey[], + A, + ER, + EW, + > extends Omit, + Form.useInput.Options { + readonly form: Form.Form + } + + export type Signature = < + P extends readonly PropertyKey[], + A, + ER, + EW, + >( + props: Props, + ) => React.ReactNode +} + +export const TextFieldFormInputView = Component.make( + "TextFieldFormInputView", +)(function* ( + props: TextFieldFormInputView.Props< + readonly PropertyKey[], + any, + any, + any + >, +) { + const input = yield* Form.useInput(props.form, props) + const [issues, isValidating, isCommitting] = yield* View.useAll([ + props.form.issues, + props.form.isValidating, + props.form.isCommitting, + ]) + + return ( + + input.setValue(event.target.value)} + disabled={isCommitting} + {...Struct.omit(props, ["form", "debounce"])} + > + {isValidating && ( + + + + )} + {props.children} + + + {Option.match(Array.head(issues), { + onSome: (issue) => ( + + {issue.message} + + ), + onNone: () => null, + })} + + ) +}).pipe( + Component.withSignature(), +) +``` + +## The common Form model + +Both root implementations and every focused subform implement `Form.Form`. +They expose the schema pipeline as reactive Lenses and Views: + +| Member | Meaning | +| --- | --- | +| `encodedValue` | Writable input-shaped state. | +| `value` | The decoded value as an `Option`; `None` until decoding succeeds. | +| `issues` | Standard Schema issues scoped to this form's path. | +| `isValidating` | Whether schema decoding is currently running. | +| `canCommit` | Whether the root has a valid value and is ready to commit. | +| `isCommitting` | Whether a mutation or target write is in progress. | + +The form model itself is Effect code. Effect View adds the React-facing hooks, +including `Form.useInput` and `Form.useOptionalInput`, while your own component +library remains responsible for rendering controls and layout. diff --git a/packages/docs/docs/getting-started.md b/packages/docs/docs/getting-started.md new file mode 100644 index 0000000..393e36b --- /dev/null +++ b/packages/docs/docs/getting-started.md @@ -0,0 +1,541 @@ +--- +sidebar_position: 1 +title: Getting Started +--- + +# Getting Started + +`effect-view` lets a React function component be described as an Effect +program. Inside a component you can yield services, create scoped resources, +subscribe to Effect-powered state, and turn Effects into React callbacks. At a +React boundary, that description becomes a normal function component. + +The core model has four pieces: + +1. `ReactRuntime` builds the Effect services available to the UI. +2. `Component.make` defines an Effect View component. +3. `Component.withContext` converts an Effect View component into a normal + React component at an application or router boundary. +4. Effect View children are composed through their `.use` Effect. + +## Install + +For a web application, install Effect View with Effect 4 and React 19.2 or +newer: + +```bash npm2yarn +npm install effect-view effect@beta react react-dom +``` + +```bash npm2yarn +npm install --save-dev @types/react @types/react-dom +``` + +Effect View is not tied to React DOM. For React Native or another renderer, +install that renderer instead of `react-dom` and keep the rest of the setup the +same. + +## Set up hot reloading with Vite + +Install the Effect View Vite plugin to preserve component state while editing +Effect View components: + +```bash npm2yarn +npm install --save-dev @effect-view/vite-plugin +``` + +Add `effectViewPlugin()` before the React plugin in your Vite configuration: + +```ts title="vite.config.ts" +import { effectViewPlugin } from "@effect-view/vite-plugin" +import react from "@vitejs/plugin-react" +import { defineConfig } from "vite" + +export default defineConfig({ + plugins: [ + effectViewPlugin(), + react(), + ], +}) +``` + +Vite is the only bundler supported for Effect View hot reloading at the moment. +Support for other bundlers will follow. + +## Create the runtime + +`ReactRuntime` owns a managed Effect runtime. Define it at module scope from the +layers needed by the UI: + +```tsx title="src/runtime.ts" +import { Layer } from "effect" +import { FetchHttpClient } from "effect/unstable/http" +import { ReactRuntime } from "effect-view" + +const AppLive = Layer.empty.pipe( + Layer.provideMerge(FetchHttpClient.layer), +) + +export const runtime = ReactRuntime.make(AppLive) +``` + +Keep the runtime stable. Creating it during a React render would create new +managed resources and a new React context on every render. + +## Provide the runtime + +Place `ReactRuntime.Provider` above every Effect View entrypoint. The provider +builds the runtime layer, makes its Effect context available through React, and +disposes the managed runtime when the provider unmounts. + +Runtime construction can suspend, so give the provider a fallback: + +```tsx title="src/main.tsx" +import { StrictMode } from "react" +import { createRoot } from "react-dom/client" +import { ReactRuntime } from "effect-view" +import { App } from "./App" +import { runtime } from "./runtime" + +createRoot(document.getElementById("root")!).render( + + Starting application...

} + > + +
+
, +) +``` + +With a router, keep the provider above the router provider: + +```tsx +Starting...

}> + +
+``` + +If runtime layer construction can fail, place an appropriate React error +boundary above `ReactRuntime.Provider` as well. + +## Write your first component + +`Component.make` defines a component body using the same generator style as +`Effect.gen` and `Effect.fn`. Providing a name creates a tracing span and also +sets the React DevTools display name: + +```tsx title="src/HelloView.tsx" +import { Effect } from "effect" +import { Component } from "effect-view" + +export const HelloView = Component.make("HelloView")( + function* (props: { readonly name: string }) { + const message = yield* Effect.succeed(`Hello, ${props.name}`) + + return

{message}

+ }, +) +``` + +Use `Component.makeUntraced("HelloView")` when you want the display name but do +not want an automatic tracing span. + +`HelloView` is an Effect View component description, not yet a normal React +component. Convert it at the point where plain React, a router, or a third-party +library needs a function component: + +```tsx title="src/Hello.tsx" +import { Component } from "effect-view" +import { HelloView } from "./HelloView" +import { runtime } from "./runtime" + +export const Hello = HelloView.pipe( + Component.withContext(runtime.context), +) +``` + +It can now be rendered by ordinary React: + +```tsx title="src/App.tsx" +import { Hello } from "./Hello" + +export function App() { + return +} +``` + +`Component.withContext` reads the context populated by the matching +`ReactRuntime.Provider`. It does not build or provide the runtime by itself. + +## Compose Effect View components + +Inside another Effect View component, yield a child's `.use` Effect. This binds +the child to the current Effect context and returns a component that can be used +in JSX: + +```tsx title="src/GreetingCardView.tsx" +import { Component } from "effect-view" +import { HelloView } from "./HelloView" + +export const GreetingCardView = Component.make("GreetingCard")( + function* () { + const Hello = yield* HelloView.use + + return ( +
+ +

Both components use the same Effect context.

+
+ ) + }, +) +``` + +Only apply `Component.withContext` when crossing from Effect View into plain +React. Applying it to every nested component is unnecessary and makes it harder +to provide local services to a subtree. + +## Synchronous and asynchronous components + +A regular Effect View component runs its body during React render. That Effect +must complete synchronously: yielding a service, reading synchronous state, or +creating a scoped object is fine; sleeping, fetching, or awaiting a promise is +not. + +Use `Async.async` when render genuinely depends on an asynchronous Effect. The +component then suspends and accepts React Suspense props such as `fallback`: + +```tsx title="src/UserView.tsx" +import { Async, Component, Memoized } from "effect-view" +import { loadUser } from "./api" + +export const UserView = Component.make("UserView")( + function* (props: { readonly userId: string }) { + const user = yield* Component.useOnChange( + () => loadUser(props.userId), + [props.userId], + ) + + return

{user.name}

+ }, +).pipe( + Async.async, + Async.withOptions({ defaultFallback:

Loading user...

}), + Memoized.memoized, +) +``` + +Use it from an Effect View parent in the usual way: + +```tsx +const User = yield* UserView.use + +return +``` + +`Memoized.memoized` prevents an unrelated parent re-render from restarting an +async child whose props have not changed. A changed `userId` creates a new +dependency scope, cleans up the previous one, and runs `loadUser` again. + +An async component's rejected Effect is handled by the nearest React error +boundary. Suspense handles waiting, not failures. + +For server data that should be cached, refreshed, and shared, prefer the +[Query module](./query) over a raw async component. + +## Use Effect services + +Components can yield Effect service tags directly. Their required service type +becomes part of the component type, so the final runtime or a local layer must +provide it: + +```tsx title="src/GreetingService.ts" +import { Context, Layer } from "effect" + +export class GreetingService extends Context.Service< + GreetingService, + { readonly greet: (name: string) => string } +>()("GreetingService") { + static readonly layer = Layer.succeed(GreetingService, { + greet: (name) => `Hello, ${name}`, + }) +} +``` + +```tsx title="src/GreetingView.tsx" +import { Component } from "effect-view" +import { GreetingService } from "./GreetingService" + +export const GreetingView = Component.make("Greeting")( + function* (props: { readonly name: string }) { + const greeting = yield* GreetingService + + return

{greeting.greet(props.name)}

+ }, +) +``` + +Add `GreetingService.layer` to the application runtime, or provide it only to a +subtree as shown later on this page. + +Effect service instances are reactive at component boundaries. If the supplied +context changes to contain a different service instance, dependent Effect View +components are recreated so they read the new environment and restart their +scoped lifecycle. + +## Understand lifecycle hooks + +Effect View hooks are still React hooks internally. Call them unconditionally +at the top level of the component body, in a consistent order, and never inside +branches, loops, event handlers, or nested callbacks. + +### The component root scope + +Every rendered Effect View component gets a root `Scope.Scope`. Effect View +creates it when the component instance is rendered, provides it to the entire +component body, and closes it when that React component unmounts. + +Effects yielded directly from the body therefore see the root scope. This also +means that `Effect.addFinalizer`, `Effect.acquireRelease`, and +`Effect.forkScoped` can be used naturally inside component setup: + +```tsx +import { Effect } from "effect" +import { Component } from "effect-view" + +const ResourceView = Component.make("Resource")(function* () { + const resource = yield* Component.useOnMount(() => + Effect.acquireRelease( + openResource, + (resource) => closeResource(resource), + ), + ) + + return

{resource.name}

+}) +``` + +`useOnMount` does **not** create or provide another scope. It runs its Effect +with the context already available in the component body, so the resource above +is owned by the component's root scope. + +`useOnChange`, `useReactEffect`, and `useReactLayoutEffect` each create a scope +that can be replaced without closing the component root scope. + +The main lifecycle choices are: + +| Hook | What it does | Scope seen by setup | Scope closes when | +| --- | --- | --- | --- | +| Component body | Produces the component's rendered value | Component root scope | The component unmounts | +| `useOnMount` | Computes and caches a value for the component instance | The same component root scope | The component unmounts | +| `useOnChange` | Recomputes a cached value when dependencies change | A new dependency scope | Dependencies change or the component unmounts | +| `useReactEffect` | Runs a post-commit side effect | A new effect scope | Dependencies change or the component unmounts | +| `useReactLayoutEffect` | Runs a layout effect before the browser paints | A new layout-effect scope | Dependencies change or the component unmounts | +| `useLayer` | Builds and provides a layer context | A dependency scope created through `useOnChange` | The layer reference changes or the component unmounts | + +`useRunSync`, `useRunPromise`, `useCallbackSync`, and `useCallbackPromise` do +not create lifecycle scopes either. They capture the component context, so an +Effect invoked through them sees the component root scope unless it explicitly +provides another one. + +### useOnMount + +`Component.useOnMount` computes a value during the initial render and caches it +for later renders. It uses the component root scope, so its resources live +until the component unmounts. + +```tsx title="src/LocalStateView.tsx" +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, View } from "effect-view" + +export const LocalStateView = Component.make("LocalState")( + function* () { + const count = yield* Component.useOnMount(() => + Effect.gen(function* () { + yield* Effect.addFinalizer(() => + Effect.log("LocalState disposed"), + ) + + return Lens.fromSubscriptionRef( + yield* SubscriptionRef.make(0), + ) + }), + ) + + const [value] = yield* View.useAll([count]) + return

Count: {value}

+ }, +) +``` + +In a regular component, the setup Effect must be synchronous because it runs +during render. In a component enhanced with `Async.async`, it may be +asynchronous and will suspend the component. + +### useOnChange + +`Component.useOnChange` computes and caches a value, then recomputes it when its +dependencies change. Each dependency set gets its own scope, which closes when +the dependencies change or the component unmounts. + +```tsx +const label = yield* Component.useOnChange( + () => + Effect.gen(function* () { + yield* Effect.addFinalizer(() => + Effect.log(`Stopped viewing ${props.userId}`), + ) + + return `Viewing user ${props.userId}` + }), + [props.userId], +) +``` + +Dependency arrays follow normal React semantics. Include every reactive value +read by the setup Effect. + +### useReactEffect and useReactLayoutEffect + +`Component.useReactEffect` runs side effects after React commits, while +`Component.useReactLayoutEffect` runs before the browser paints. Each hook owns +a scope that closes when its dependencies change or the component unmounts. + +Setup must complete synchronously, but it can fork asynchronous work into the +hook scope: + +```tsx +yield* Component.useReactEffect( + () => Effect.forkScoped(listenForNotifications(props.userId)), + [props.userId], +) +``` + +React Strict Mode may intentionally repeat development-only render and effect +setup. Initializers and resource acquisition should therefore be safe to run +more than once; production retains the normal component lifetime semantics. + +## Run Effects from event handlers + +React event handlers are plain functions. Use Effect View runners to execute an +Effect with the component's current context and scope: + +```tsx +const runPromise = yield* Component.useRunPromise() + +return ( + +) +``` + +Use `Component.useRunSync` only for Effects known to complete synchronously. +Use `Component.useRunPromise` for Effects that may suspend, sleep, fetch, or +otherwise continue asynchronously. + +When a callback is passed to a memoized child or used as a dependency, use the +callback variants to preserve its identity: + +```tsx +const save = yield* Component.useCallbackPromise( + (nextUser: User) => saveUser(nextUser), + [saveUser], +) + +return void save(user)} /> +``` + +`useCallbackSync` and `useCallbackPromise` follow the same dependency rules as +`React.useCallback`, while also supplying the Effect context when invoked. + +## Use React normally + +Effect View components can use regular React hooks, refs, context, event +handlers, and JSX composition: + +```tsx +import { Component } from "effect-view" +import * as React from "react" + +const CounterView = Component.make("Counter")(function* () { + const [count, setCount] = React.useState(0) + const buttonRef = React.useRef(null) + + return ( + + ) +}) +``` + +Prefer regular React state for simple, component-local UI concerns. Use +`Lens`/`View` when state needs Effect integration, subscriptions, focusing, or +sharing. The [State Management guide](./state-management) covers that model. + +## Provide services to a subtree + +Use `Component.useLayer` when only one Effect View subtree needs extra +services. It builds the layer in a scope and returns the resulting Effect +context: + +```tsx title="src/GreetingPageView.tsx" +import { Effect } from "effect" +import { Component } from "effect-view" +import { GreetingView } from "./GreetingView" +import { GreetingService } from "./GreetingService" + +export const GreetingPageView = Component.make("GreetingPage")( + function* () { + const context = yield* Component.useLayer(GreetingService.layer) + const Greeting = yield* GreetingView.use.pipe( + Effect.provide(context), + ) + + return + }, +) +``` + +Keep the layer reference stable. Define static layers outside the component or +memoize a layer that depends on props with `React.useMemo`; a new layer object +causes reconstruction and scoped cleanup. + +Layer construction runs during render through `useOnChange`. A layer with +asynchronous acquisition requires the component to be enhanced with +`Async.async`. Resources built by the layer are released when the owning +component unmounts or the layer reference changes. + +## Common pitfalls + +- Effect View hooks obey React's Rules of Hooks even though they are called + with `yield*`. +- Do not yield an asynchronous Effect from a regular component body. Use + `Async.async`, Query, a Mutation callback, or a post-commit scoped fiber. +- `Component.withContext` needs a matching `ReactRuntime.Provider` above it. +- Apply `withContext` at React boundaries, not between Effect View components. +- Keep runtimes and layers stable instead of creating them on every render. +- Use `useRunPromise` rather than `useRunSync` for asynchronous event work. +- Suspense fallbacks handle waiting; React error boundaries handle failed + component Effects. + +## Where to go next + +- [State Management](./state-management) explains `Lens`, `View`, local state, + and focused state. +- [Query](./query) adds reactive keys, caching, refresh, and invalidation to + Effect-based server reads. +- [Mutation](./mutation) models user-triggered Effect operations and their + `AsyncResult` state. +- [Forms](./forms) builds schema-driven editable state with `MutationForm` and + `LensForm`. + +The repeatable pattern is small: provide one runtime, define components as +Effect programs, cross into plain React with `Component.withContext`, and use +`.use` everywhere inside the Effect View tree. diff --git a/packages/docs/docs/intro.md b/packages/docs/docs/intro.md deleted file mode 100644 index 9c3cd3d..0000000 --- a/packages/docs/docs/intro.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Effect FC - -Welcome to **Effect FC** (as in: Effect **F**unction **C**omponent) – a powerful integration of [Effect](https://effect.website/) with React 19.2+ that enables you to write React function components using Effect generators. - -## What is Effect FC? - -Effect FC allows you to harness the full power of Effect-TS within your React components. Instead of writing traditional React hooks, you can use Effect generators to compose complex, type-safe component logic with built-in error handling, resource management, and dependency injection. - -### Key Features - -- **Effect Integration**: Write your function component logic using Effect. -- **Type Safety**: Full TypeScript support with Effect's comprehensive type system -- **Dependency Injection**: Built-in support for providing dependencies to components using Effect services. -- **Resource Management**: Automatic cleanup and finalization of component resources using the `Scope` API. - -## Quick Example - -Here's what writing an Effect FC component looks like: - -```typescript -export class TodosView extends Component.make("TodosView")(function*() { - const state = yield* TodosState - const [todos] = yield* Component.useSubscribables([state.subscriptionRef]) - - yield* Component.useOnMount(() => Effect.andThen( - Console.log("Todos mounted"), - Effect.addFinalizer(() => Console.log("Todos unmounted")), - )) - - const Todo = yield* TodoView.use - - return ( - - Todos - - - - - {Chunk.map(todos, todo => - - )} - - - ) -}) {} - -const Index = Component.make("IndexView")(function*() { - const context = yield* Component.useContextFromLayer(TodosState.Default) - const Todos = yield* Effect.provide(TodosView.use, context) - - return -}).pipe( - Component.withRuntime(runtime.context) -) - -export const Route = createFileRoute("/")({ - component: Index -}) -``` - -## Getting Started - -### Prerequisites - -Before using Effect FC, make sure you have: - -- **Node.js** version 20.0 or above -- **React** 19.2 or higher -- **Effect** 3.19 or higher - -### Installation - -Install Effect FC and its peer dependencies: - -```bash -npm install effect-fc effect react -``` - -Or with your preferred package manager: - -```bash -yarn add effect-fc effect react -bun add effect-fc effect react -pnpm add effect-fc effect react -``` - -### Next Steps - -- Explore the [Tutorial Basics](./tutorial-basics/create-a-document.md) to learn the fundamentals -- Check out the [Example Project](https://github.com/your-repo/packages/example) for a complete working application - -## Important Notes - -:::info Early Development -This library is in early development. While it is mostly feature-complete and usable, expect bugs and quirks. Things are still being ironed out, so ideas and criticisms are welcome! -::: - -:::warning Known Issues -- React Refresh doesn't work for Effect FC components yet. Page reload is required to view changes. Regular React components are unaffected. -::: - -## Community & Support - -Have questions or want to contribute? We'd love to hear from you! Check out the project repository and feel free to open issues or discussions. diff --git a/packages/docs/docs/mutation.md b/packages/docs/docs/mutation.md new file mode 100644 index 0000000..6d4589a --- /dev/null +++ b/packages/docs/docs/mutation.md @@ -0,0 +1,270 @@ +--- +sidebar_position: 4 +title: Mutation +--- + +# Mutation + +The Mutation module is Effect View's counterpart to TanStack Query mutations. +It models user-triggered asynchronous work such as saving a profile, deleting a +record, uploading a file, or sending a command to an API. + +The familiar concepts are present, but the operation itself is an Effect: + +| TanStack Mutation concept | Effect View equivalent | +| --- | --- | +| Mutation variables | The input key `K` | +| `mutationFn` | `f: (key: K) => Effect` | +| Mutation result | `mutation.state`, a `View>` | +| `isPending` | `result.waiting` | +| `mutateAsync` | `mutation.mutate(key)` | +| Start without awaiting | `mutation.mutateView(key)` | + +Unlike a Query, a Mutation has no cache, reactive key, or automatic execution. +It runs only when `mutate` or `mutateView` is called. This makes it suitable for +commands, while Query remains the model for cached server state. + +## Create a mutation + +Create a mutation in a component scope with `Mutation.make`. Its function can +be any Effect, including one that requires services from the application +runtime: + +```tsx +import { Effect } from "effect" +import { AsyncResult } from "effect/unstable/reactivity" +import { Component, Mutation, View } from "effect-view" +import { sendInvite } from "./api" + +interface InviteInput { + readonly email: string + readonly role: "member" | "admin" +} + +const InviteButtonView = Component.make("InviteButton")( + function* (props: { readonly email: string }) { + const mutation = yield* Component.useOnMount(() => + Mutation.make({ + f: (input: InviteInput) => sendInvite(input), + }), + ) + + const [result] = yield* View.useAll([mutation.state]) + const runSync = yield* Component.useRunSync() + + return ( +
+ + + {AsyncResult.match(result, { + onInitial: () => null, + onFailure: ({ cause }) => ( +

Could not send invite: {cause.toString()}

+ ), + onSuccess: ({ value }) => ( +

Invite sent to {value.email}

+ ), + })} +
+ ) + }, +) +``` + +`Mutation.make` captures the current Effect context. If `sendInvite` requires +an HTTP client, authentication service, tracer, or another service, provide it +to the runtime or component layer before creating the mutation. The click +handler does not need to reconstruct those dependencies. + +The mutation also belongs to the creation scope. Any mutation fibers still +running when that scope closes are interrupted automatically. + +## Understand AsyncResult + +`mutation.state` starts as `Initial` with `waiting: false`. Starting a mutation +changes it to a waiting state, then publishes either `Success` or `Failure`: + +```tsx +const [result] = yield* View.useAll([mutation.state]) + +return AsyncResult.match(result, { + onInitial: ({ waiting }) => + waiting ?

Starting...

:

Ready.

, + onFailure: ({ cause, previousSuccess, waiting }) => ( +
+

{cause.toString()}

+ {previousSuccess._tag === "Some" && ( +

Last saved value: {previousSuccess.value.value.name}

+ )} + {waiting &&

Trying again...

} +
+ ), + onSuccess: ({ value, waiting }) => ( +
+

Saved {value.name}

+ {waiting &&

Saving a newer value...

} +
+ ), +}) +``` + +The `waiting` flag is independent from the result tag. After one successful +call, starting another keeps the successful value and sets `waiting: true`. +If that next call fails, the failure can retain the earlier success in +`previousSuccess`. Components can therefore keep useful feedback visible +during retries or repeated submissions. + +A failure contains an Effect `Cause`, not only `E`. Typed failures, defects, +and interruption information remain available for logging or presentation. + +## Choose mutate or mutateView + +Both methods start the same mutation effect. They differ in what the caller +waits for: + +| Method | Return value | Best suited to | +| --- | --- | --- | +| `mutate(key)` | The final `Success` or `Failure` | Effect workflows that need the outcome. | +| `mutateView(key)` | A live `View>` | UI callbacks that should return after starting the work. | + +Use `mutate` with an asynchronous component runner when later logic depends on +the final result: + +```tsx +const runPromise = yield* Component.useRunPromise() + +const save = () => + void runPromise( + Effect.gen(function* () { + const result = yield* mutation.mutate(input) + + if (AsyncResult.isSuccess(result)) { + yield* Effect.log(`Saved record ${result.value.id}`) + } + }), + ) +``` + +The mutation Effect does not fail with `E`. It captures the operation's `Exit` +and returns a final `AsyncResult.Success` or `AsyncResult.Failure`. Inspect or +match that value when control flow depends on the outcome. + +Use `mutateView` when the UI only needs to start the operation and react to its +state: + +```tsx +const runSync = yield* Component.useRunSync() + +const startSave = () => { + const state = runSync(mutation.mutateView(input)) + // `state` is a View for this specific call. +} +``` + +`mutateView` starts the scoped work and returns immediately with a per-call +View. The shared `mutation.state` is also updated as that call progresses. + +## Track the latest call + +In addition to `state`, a mutation exposes reactive metadata: + +| Member | Meaning | +| --- | --- | +| `state` | The latest mutation state published to the shared View. | +| `latestKey` | The most recently supplied input as an `Option`. | +| `latestFinalResult` | The latest completed success or failure as an `Option`. | +| `fiber` | The most recently started mutation fiber as an `Option`. | + +Subscribe to any of them with `View.useAll`: + +```tsx +const [result, latestInput, latestFinal] = yield* View.useAll([ + mutation.state, + mutation.latestKey, + mutation.latestFinalResult, +]) +``` + +The input is called a `key` in the generic API, but it is equivalent to +mutation variables in TanStack Query. It can be a primitive, tuple, struct, or +any other value accepted by the mutation function. + +## Concurrent mutations + +Starting a mutation does not automatically interrupt an earlier mutation. +Calls may overlap, and each call has its own state View. This is useful for +independent operations such as uploading several files. + +When calls overlap, `mutation.state` reflects updates published by all calls; +the last update to arrive wins. Use the View returned by `mutateView` when each +concurrent operation needs its own progress indicator: + +```tsx +const upload = (file: File) => + Effect.gen(function* () { + const uploadState = yield* mutation.mutateView(file) + // Store or pass `uploadState` to the row rendering this file. + return uploadState + }) +``` + +For a single submit button, disabling it while `mutation.state.waiting` is +usually enough to prevent accidental overlap. For “latest request wins” +behavior, model that policy explicitly or use Query when the operation is +actually a reactive read. + +## Update queries after a mutation + +Mutations do not invalidate Query caches automatically. Compose invalidation +with the mutation result so the relationship remains explicit and typed: + +```tsx +const saveAndRefresh = (input: UpdatePostInput) => + Effect.gen(function* () { + const result = yield* updatePost.mutate(input) + + if (AsyncResult.isSuccess(result)) { + yield* posts.invalidateCacheEntry(["post", result.value.id] as const) + yield* posts.refreshView + } + + return result + }) +``` + +This is the Effect equivalent of an `onSuccess` callback that invalidates a +TanStack Query. Because it is ordinary Effect composition, the workflow can +also include tracing, transactions, retries, notifications, or parallel cache +updates without introducing a separate callback API. + +Remember that Query invalidation removes cached data but does not refetch by +itself. Follow it with `refreshView` when the current screen should update +immediately. + +## The Effect touch + +Mutation follows the ergonomics of TanStack mutations while retaining Effect's +execution model: + +- The mutation function has the full `Effect` type. +- Required services are captured from the creation context. +- Failures are represented as `Cause`, including defects and interruption. +- Fibers are scoped, so component unmounting cleans up in-flight operations. +- `mutate` composes directly inside larger Effect workflows. +- `mutateView` exposes call-specific progress as a View for React or Effect + consumers. +- Retry schedules, timeouts, tracing, logging, metrics, schema validation, and + concurrency controls can be applied with normal Effect operators. + +Mutation is therefore a small bridge: TanStack-style mutation state on one +side, and an ordinary, typed Effect program on the other. diff --git a/packages/docs/docs/query.md b/packages/docs/docs/query.md new file mode 100644 index 0000000..a3b1403 --- /dev/null +++ b/packages/docs/docs/query.md @@ -0,0 +1,288 @@ +--- +sidebar_position: 3 +title: Query +--- + +# Query + +The Query module is Effect View's take on TanStack Query. It provides the same +kind of server-state workflow—reactive query keys, cached results, stale times, +background refreshes, window-focus refetching, and cache invalidation—but the +query function is an `Effect` and the observable state is a `View`. + +If you already know TanStack Query, the main concepts translate directly: + +| TanStack Query concept | Effect View equivalent | +| --- | --- | +| `QueryClient` | The `QueryClient` Effect service | +| `queryKey` | A reactive key supplied as a `View` | +| `queryFn` | `f: (key: K) => Effect` | +| `useQuery` result | `query.state`, a `View>` | +| `isFetching` | `result.waiting` | +| `refetch` | `query.refresh` or `query.refreshView` | +| `invalidateQueries` | `query.invalidateCache` or `invalidateCacheEntry` | + +The goal is familiar query behavior without leaving Effect's model. Query +functions keep their typed success, error, and service channels. They can use +services from the runtime, be composed with schema decoding and retry policies, +and are interrupted automatically when their scope ends or a new key supersedes +the current request. + +## Provide a QueryClient + +Queries share successful results through a `QueryClient`. Add its layer to the +application runtime once, alongside the services used by your query effects: + +```tsx title="src/runtime.ts" +import { Layer } from "effect" +import { FetchHttpClient } from "effect/unstable/http" +import { QueryClient, ReactRuntime } from "effect-view" + +const AppLive = Layer.empty.pipe( + Layer.provideMerge(QueryClient.layer({ + defaultStaleTime: "30 seconds", + defaultRefreshOnWindowFocus: true, + cacheGcTime: "5 minutes", + })), + Layer.provideMerge(FetchHttpClient.layer), +) + +export const runtime = ReactRuntime.make(AppLive) +``` + +The client owns the cache and its cleanup lifecycle. Individual queries can +override `staleTime` and `refreshOnWindowFocus`; otherwise they inherit the +client defaults. + +## Create a reactive query + +A query is driven by a `View` rather than by a value read during one React +render. Whenever that key changes, `Query.service` checks the cache and starts +the query effect when necessary. + +```tsx +import { Effect, Schema, SubscriptionRef } from "effect" +import { HttpClient } from "effect/unstable/http" +import { Component, Lens, Query, View } from "effect-view" + +const Post = Schema.Struct({ + id: Schema.Int, + title: Schema.String, + body: Schema.String, +}) + +const PostView = Component.make("Post")(function* () { + const [postId, query] = yield* Component.useOnMount(() => + Effect.gen(function* () { + const key = Lens.fromSubscriptionRef( + yield* SubscriptionRef.make(["post", 1 as number] as const), + ) + + const query = yield* Query.service({ + key, + staleTime: "1 minute", + f: ([, id]) => + HttpClient.HttpClient.pipe( + Effect.andThen((client) => + client.get(`https://example.com/posts/${id}`), + ), + Effect.andThen((response) => response.json), + Effect.andThen(Schema.decodeUnknownEffect(Post)), + ), + }) + + return [Lens.focusTupleAt(key, 1), query] as const + }), + ) + + const [state] = yield* View.useAll([query.state]) + const [id, setId] = yield* Lens.useState(postId) + + return ( +
+ +
{state.result._tag}
+
+ ) +}) +``` + +The tuple key plays the same role as `['post', id]` in TanStack Query. Keys use +Effect equality by default, so structurally equal Effect data types work well +as query keys. Supply `keyEquivalence` when the key needs different equality +semantics. + +`Query.service` creates the query and starts watching its key in the current +scope. Creating it in `Component.useOnMount` keeps one query instance—and one +stable query function identity—for the component's lifetime. + +## Render AsyncResult + +`query.state` contains both the current key and an `AsyncResult`: + +```ts +interface QueryState { + readonly key: K + readonly result: AsyncResult.AsyncResult +} +``` + +Subscribe with `View.useAll`, then match the result explicitly: + +```tsx +import { AsyncResult } from "effect/unstable/reactivity" + +const [state] = yield* View.useAll([query.state]) + +return AsyncResult.match(state.result, { + onInitial: ({ waiting }) => + waiting ?

Loading...

:

Not loaded.

, + onFailure: ({ cause, previousSuccess, waiting }) => ( +
+

Request failed: {cause.toString()}

+ {previousSuccess._tag === "Some" && ( +

Last post: {previousSuccess.value.value.title}

+ )} + {waiting &&

Trying again...

} +
+ ), + onSuccess: ({ value, waiting }) => ( +
+ {waiting && Refreshing...} +

{value.title}

+

{value.body}

+
+ ), +}) +``` + +The `waiting` flag separates “do I have a result?” from “is work currently in +flight?”. During a background refresh, a successful result remains successful +and keeps its value while `waiting` becomes `true`. A failed refresh can retain +its `previousSuccess`. This avoids replacing useful content with an empty +loading screen every time data is refreshed. + +Failures contain an Effect `Cause`, preserving typed failures, defects, and +interruption information instead of flattening everything into an untyped +exception. + +## Change the query key + +The key is reactive state, so changing it is enough to fetch the corresponding +resource. There is no separate dependency array to keep synchronized: + +```tsx +const [id, setId] = yield* Lens.useState(postId) + +return ( + +) +``` + +When the key changes, the previous in-flight request is interrupted. The query +then reuses a fresh cached success or starts the effect for the new key. + +## Refresh and invalidate + +Refresh resolves the latest key again. A fresh cached result can satisfy it +immediately; a stale or missing result runs the query effect while preserving +previous data as background state. Invalidation removes cached data, so the +next fetch for that key must run the effect again. + +```tsx +const runSync = yield* Component.useRunSync() + +return ( +
+ + + +
+) +``` + +The methods come in two styles: + +| Method | Behavior | +| --- | --- | +| `fetch(key)` | Fetch a specific key and wait for its final state. | +| `fetchView(key)` | Start fetching and immediately return a live state `View`. | +| `refresh` | Resolve the current key again and wait for its final state. | +| `refreshView` | Resolve the current key again and immediately return a live state `View`. | +| `invalidateCacheEntry(key)` | Remove the cached success for one key. | +| `invalidateCache` | Remove every cached success associated with this query function. | + +The `*View` variants are convenient in synchronous UI callbacks: they return +after the scoped request has started, while the returned View and `query.state` +continue to publish progress. The non-View variants are useful in Effect +workflows that need to wait for the final success or failure state. + +Invalidating does not itself refetch. Follow it with `refreshView`, change the +key, or allow a later fetch to repopulate the cache. + +## Staleness and cache lifetime + +`staleTime` controls how long a successful result can satisfy a fetch without +running the effect again. A stale entry remains available as previous data +while the query refreshes it. + +`cacheGcTime` is configured on `QueryClient`. Entries that have not been +accessed are eventually removed after their stale period plus the configured +garbage-collection time. + +By default, the client enables refresh on browser window focus. Set it globally +or override it for one query: + +```tsx +const query = yield* Query.service({ + key, + f: loadPost, + staleTime: "10 seconds", + refreshOnWindowFocus: false, +}) +``` + +Window focus resolves the current key again, subject to the same freshness +check. The browser integration is ignored in non-browser environments. + +## The Effect touch + +The API emulates TanStack Query's server-state ergonomics, but query execution +remains ordinary Effect code: + +- `f` has the full `Effect` type, including required services. +- The query captures its Effect context when it is created, so callbacks do not + need to manually reconstruct dependencies. +- Effects can use `Schema`, retry schedules, tracing, logging, metrics, + cancellation, and any other Effect operator before becoming query state. +- Request fibers belong to the creation scope and are interrupted on unmount, + key replacement, or scope closure. +- Results are `View`s, so the same state can drive React through `View.useAll` + or participate in Effect streams and application logic outside React. +- Failures retain `Cause` rather than losing Effect's error model. + +`Query` is therefore best understood as a TanStack Query-shaped coordinator +for Effect programs: it handles when and whether to run them, while Effect +continues to describe what the work requires and how it behaves. diff --git a/packages/docs/docs/state-management.md b/packages/docs/docs/state-management.md new file mode 100644 index 0000000..19285e8 --- /dev/null +++ b/packages/docs/docs/state-management.md @@ -0,0 +1,274 @@ +--- +sidebar_position: 2 +title: State Management +--- + +# State Management + +`Lens` is the main type used for state management in `effect-view`. + +A Lens is an effectful handle to a piece of state. It can read the current value, +subscribe to changes, and write updates back to the underlying source. A Lens +can point at a whole state object or focus on one nested field inside it. + +`effect-view` re-exports the `Lens` and `View` modules from +[`effect-lens`](https://github.com/Thiladev/effect-lens) for convenience. The +core data model and transformation APIs belong to `effect-lens`, so check the +[`effect-lens` documentation](https://github.com/Thiladev/effect-lens/tree/master/packages/effect-lens) for the full Lens/View API. + +The usual pattern is to create state with Effect primitives such as +`SubscriptionRef`, turn that primitive into a Lens with a matching constructor +such as `Lens.fromSubscriptionRef`, and bind Lens values into components with +`View.useAll`. + +`View` is the read-only side of this model. Every Lens is also a View. + +## Where To Store State + +State can live pretty much anywhere as a `Lens` or `View`: in a +service, in a layer, in a component scope, or alongside plain React state. Pick +the owner based on who needs the state. Once you have a Lens/View +handle, pass it around however you like, including through React props. + +If state is shared by multiple components or belongs to application logic, store +it in an Effect service: + +```tsx +import { Context, Effect, Layer, SubscriptionRef } from "effect" +import { Component, Lens, View } from "effect-view" + +class CounterState extends Context.Service< + CounterState, + { readonly count: Lens.Lens } +>()("CounterState") { + static readonly layer = Layer.effect( + CounterState, + Effect.gen(function*() { + const count = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(0)) + + return { count } as const + }), + ) +} + +const CounterValueView = Component.make("CounterValue")(function*() { + const state = yield* CounterState + const [count] = yield* View.useAll([state.count]) + + return

Count: {count}

+}) +``` + +If state belongs to a single Effect View component instance, or to a shallow +hierarchy of subcomponents that receive it through props, create it with +`Component.useOnMount`: + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, View } from "effect-view" + +const LocalCounterView = Component.make("LocalCounter")(function*() { + const state = yield* Component.useOnMount(() => + Effect.gen(function*() { + const count = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(0)) + + return { count } as const + }), + ) + const [count] = yield* View.useAll([state.count]) + + return

Count: {count}

+}) +``` + +For simple UI state that is not shared and does not need Effect integration, +prefer regular React state. A local "show details" toggle is usually better as +`React.useState(false)` than as a Lens. + +## View.useAll + +A `View` is reactive state with a current value and a stream of changes. Use +`View.useAll` whenever a component needs to bind View values into render output. + +`Lens` is a `View`, so this is also the default way to read Lens values +from a component. + +```tsx +import { Context, Effect, Layer, SubscriptionRef } from "effect" +import { Component, Lens, View } from "effect-view" + +class CounterState extends Context.Service< + CounterState, + { + readonly count: Lens.Lens + readonly doubled: View.View + } +>()("CounterState") { + static readonly layer = Layer.effect( + CounterState, + Effect.gen(function*() { + const count = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(0)) + const doubled = View.map(count, (n) => n * 2) + + return { count, doubled } as const + }), + ) +} + +const CounterReadOnlyView = Component.make("CounterReadOnly")( + function* () { + const state = yield* CounterState + const [count, doubled] = yield* View.useAll([ + state.count, + state.doubled, + ]) + + return

Count: {count}, doubled: {doubled}

+ }, +) +``` + +`View.useAll` reads the current values during render and uses scoped subscriptions to update React state when changes arrive. + +When you need to modify state, write to the Lens with `Lens.set` or `Lens.update`: + +```tsx +const CounterControlsView = Component.make("CounterControls")( + function* () { + const state = yield* CounterState + const [count] = yield* View.useAll([state.count]) + + const increment = yield* Component.useCallbackSync( + () => Lens.update(state.count, (n) => n + 1), + [], + ) + const reset = yield* Component.useCallbackSync( + () => Lens.set(state.count, 0), + [], + ) + + return ( +
+

Count: {count}

+ + +
+ ) + }, +) +``` + +## Lens.useState + +`Lens.useState` is useful when React needs the familiar `[value, setValue]` +tuple, backed by a Lens. Reach for it when the JSX API expects a synchronous +setter, especially controlled inputs such as text fields, checkboxes, selects, +or third-party components with `value` / `onChange` props. + +If a component only needs to display the value, prefer `View.useAll`. +`Lens.useState` is for places where reading and writing need to be wired +together in React's local-state shape. + +```tsx +import { Context, Effect, Layer, SubscriptionRef } from "effect" +import { Component, Lens } from "effect-view" + +class FormState extends Context.Service< + FormState, + { readonly name: Lens.Lens } +>()("FormState") { + static readonly layer = Layer.effect( + FormState, + Effect.gen(function*() { + const name = Lens.fromSubscriptionRef(yield* SubscriptionRef.make("")) + + return { name } as const + }), + ) +} + +const NameInputView = Component.make("NameInput")(function* () { + const state = yield* FormState + const [name, setName] = yield* Lens.useState(state.name) + + return ( + setName(event.currentTarget.value)} + /> + ) +}) +``` + +`Lens.useState` returns the current value and a React-compatible setter. Calling +the setter writes through the Lens, so every other component subscribed to the +same Lens sees the update. + +## Focused Lenses + +Use focused Lenses when a component should work with one part of a larger state +object. A focused Lens is still a Lens, so it can be read with +`View.useAll` or used with `Lens.useState` when React needs a +read/write tuple. + +```tsx +import { Context, Effect, Layer, SubscriptionRef } from "effect" +import { Component, Lens, View } from "effect-view" + +interface UserProfile { + readonly name: string + readonly email: string + readonly role: string +} + +class ProfileState extends Context.Service< + ProfileState, + { + readonly profile: Lens.Lens + readonly name: Lens.Lens + readonly role: Lens.Lens + } +>()("ProfileState") { + static readonly layer = Layer.effect( + ProfileState, + Effect.gen(function*() { + const profile = Lens.fromSubscriptionRef( + yield* SubscriptionRef.make({ + name: "", + email: "", + role: "reader", + }), + ) + const name = Lens.focusObjectOn(profile, "name") + const role = Lens.focusObjectOn(profile, "role") + + return { profile, name, role } as const + }), + ) +} + +const ProfileNameView = Component.make("ProfileName")(function*() { + const state = yield* ProfileState + const [name, setName] = yield* Lens.useState(state.name) + const [role] = yield* View.useAll([state.role]) + + return ( + + ) +}) +``` + +Updating the focused `name` Lens through `Lens.useState` updates the parent +`profile` Lens. The focused `role` Lens is only read, so it stays on the simpler +`View.useAll` path. + +For focusing into nested state, deriving lenses, custom write behavior, and the +complete API, refer to the +[`effect-lens` documentation](https://github.com/Thiladev/effect-lens/tree/master/packages/effect-lens). diff --git a/packages/docs/docs/tutorial-basics/_category_.json b/packages/docs/docs/tutorial-basics/_category_.json deleted file mode 100644 index 2e6db55..0000000 --- a/packages/docs/docs/tutorial-basics/_category_.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "label": "Tutorial - Basics", - "position": 2, - "link": { - "type": "generated-index", - "description": "5 minutes to learn the most important Docusaurus concepts." - } -} diff --git a/packages/docs/docs/tutorial-basics/congratulations.md b/packages/docs/docs/tutorial-basics/congratulations.md deleted file mode 100644 index 04771a0..0000000 --- a/packages/docs/docs/tutorial-basics/congratulations.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -sidebar_position: 6 ---- - -# Congratulations! - -You have just learned the **basics of Docusaurus** and made some changes to the **initial template**. - -Docusaurus has **much more to offer**! - -Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**. - -Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610) - -## What's next? - -- Read the [official documentation](https://docusaurus.io/) -- Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config) -- Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration) -- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout) -- Add a [search bar](https://docusaurus.io/docs/search) -- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase) -- Get involved in the [Docusaurus Community](https://docusaurus.io/community/support) diff --git a/packages/docs/docs/tutorial-basics/create-a-blog-post.md b/packages/docs/docs/tutorial-basics/create-a-blog-post.md deleted file mode 100644 index 550ae17..0000000 --- a/packages/docs/docs/tutorial-basics/create-a-blog-post.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -sidebar_position: 3 ---- - -# Create a Blog Post - -Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed... - -## Create your first Post - -Create a file at `blog/2021-02-28-greetings.md`: - -```md title="blog/2021-02-28-greetings.md" ---- -slug: greetings -title: Greetings! -authors: - - name: Joel Marcey - title: Co-creator of Docusaurus 1 - url: https://github.com/JoelMarcey - image_url: https://github.com/JoelMarcey.png - - name: Sébastien Lorber - title: Docusaurus maintainer - url: https://sebastienlorber.com - image_url: https://github.com/slorber.png -tags: [greetings] ---- - -Congratulations, you have made your first post! - -Feel free to play around and edit this post as much as you like. -``` - -A new blog post is now available at [http://localhost:3000/blog/greetings](http://localhost:3000/blog/greetings). diff --git a/packages/docs/docs/tutorial-basics/create-a-document.md b/packages/docs/docs/tutorial-basics/create-a-document.md deleted file mode 100644 index c22fe29..0000000 --- a/packages/docs/docs/tutorial-basics/create-a-document.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -sidebar_position: 2 ---- - -# Create a Document - -Documents are **groups of pages** connected through: - -- a **sidebar** -- **previous/next navigation** -- **versioning** - -## Create your first Doc - -Create a Markdown file at `docs/hello.md`: - -```md title="docs/hello.md" -# Hello - -This is my **first Docusaurus document**! -``` - -A new document is now available at [http://localhost:3000/docs/hello](http://localhost:3000/docs/hello). - -## Configure the Sidebar - -Docusaurus automatically **creates a sidebar** from the `docs` folder. - -Add metadata to customize the sidebar label and position: - -```md title="docs/hello.md" {1-4} ---- -sidebar_label: 'Hi!' -sidebar_position: 3 ---- - -# Hello - -This is my **first Docusaurus document**! -``` - -It is also possible to create your sidebar explicitly in `sidebars.js`: - -```js title="sidebars.js" -export default { - tutorialSidebar: [ - 'intro', - // highlight-next-line - 'hello', - { - type: 'category', - label: 'Tutorial', - items: ['tutorial-basics/create-a-document'], - }, - ], -}; -``` diff --git a/packages/docs/docs/tutorial-basics/create-a-page.md b/packages/docs/docs/tutorial-basics/create-a-page.md deleted file mode 100644 index 20e2ac3..0000000 --- a/packages/docs/docs/tutorial-basics/create-a-page.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Create a Page - -Add **Markdown or React** files to `src/pages` to create a **standalone page**: - -- `src/pages/index.js` → `localhost:3000/` -- `src/pages/foo.md` → `localhost:3000/foo` -- `src/pages/foo/bar.js` → `localhost:3000/foo/bar` - -## Create your first React Page - -Create a file at `src/pages/my-react-page.js`: - -```jsx title="src/pages/my-react-page.js" -import React from 'react'; -import Layout from '@theme/Layout'; - -export default function MyReactPage() { - return ( - -

My React page

-

This is a React page

-
- ); -} -``` - -A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page). - -## Create your first Markdown Page - -Create a file at `src/pages/my-markdown-page.md`: - -```mdx title="src/pages/my-markdown-page.md" -# My Markdown page - -This is a Markdown page -``` - -A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page). diff --git a/packages/docs/docs/tutorial-basics/deploy-your-site.md b/packages/docs/docs/tutorial-basics/deploy-your-site.md deleted file mode 100644 index 1c50ee0..0000000 --- a/packages/docs/docs/tutorial-basics/deploy-your-site.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -sidebar_position: 5 ---- - -# Deploy your site - -Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**). - -It builds your site as simple **static HTML, JavaScript and CSS files**. - -## Build your site - -Build your site **for production**: - -```bash -npm run build -``` - -The static files are generated in the `build` folder. - -## Deploy your site - -Test your production build locally: - -```bash -npm run serve -``` - -The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/). - -You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**). diff --git a/packages/docs/docs/tutorial-basics/markdown-features.mdx b/packages/docs/docs/tutorial-basics/markdown-features.mdx deleted file mode 100644 index 35e0082..0000000 --- a/packages/docs/docs/tutorial-basics/markdown-features.mdx +++ /dev/null @@ -1,152 +0,0 @@ ---- -sidebar_position: 4 ---- - -# Markdown Features - -Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**. - -## Front Matter - -Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/): - -```text title="my-doc.md" -// highlight-start ---- -id: my-doc-id -title: My document title -description: My document description -slug: /my-custom-url ---- -// highlight-end - -## Markdown heading - -Markdown text with [links](./hello.md) -``` - -## Links - -Regular Markdown links are supported, using url paths or relative file paths. - -```md -Let's see how to [Create a page](/create-a-page). -``` - -```md -Let's see how to [Create a page](./create-a-page.md). -``` - -**Result:** Let's see how to [Create a page](./create-a-page.md). - -## Images - -Regular Markdown images are supported. - -You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`): - -```md -![Docusaurus logo](/img/docusaurus.png) -``` - -![Docusaurus logo](/img/docusaurus.png) - -You can reference images relative to the current file as well. This is particularly useful to colocate images close to the Markdown files using them: - -```md -![Docusaurus logo](./img/docusaurus.png) -``` - -## Code Blocks - -Markdown code blocks are supported with Syntax highlighting. - -````md -```jsx title="src/components/HelloDocusaurus.js" -function HelloDocusaurus() { - return

Hello, Docusaurus!

; -} -``` -```` - -```jsx title="src/components/HelloDocusaurus.js" -function HelloDocusaurus() { - return

Hello, Docusaurus!

; -} -``` - -## Admonitions - -Docusaurus has a special syntax to create admonitions and callouts: - -```md -:::tip My tip - -Use this awesome feature option - -::: - -:::danger Take care - -This action is dangerous - -::: -``` - -:::tip My tip - -Use this awesome feature option - -::: - -:::danger Take care - -This action is dangerous - -::: - -## MDX and React Components - -[MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**: - -```jsx -export const Highlight = ({children, color}) => ( - { - alert(`You clicked the color ${color} with label ${children}`) - }}> - {children} - -); - -This is Docusaurus green ! - -This is Facebook blue ! -``` - -export const Highlight = ({children, color}) => ( - { - alert(`You clicked the color ${color} with label ${children}`); - }}> - {children} - -); - -This is Docusaurus green ! - -This is Facebook blue ! diff --git a/packages/docs/docs/tutorial-extras/_category_.json b/packages/docs/docs/tutorial-extras/_category_.json deleted file mode 100644 index a8ffcc1..0000000 --- a/packages/docs/docs/tutorial-extras/_category_.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "label": "Tutorial - Extras", - "position": 3, - "link": { - "type": "generated-index" - } -} diff --git a/packages/docs/docs/tutorial-extras/img/docsVersionDropdown.png b/packages/docs/docs/tutorial-extras/img/docsVersionDropdown.png deleted file mode 100644 index 97e4164..0000000 Binary files a/packages/docs/docs/tutorial-extras/img/docsVersionDropdown.png and /dev/null differ diff --git a/packages/docs/docs/tutorial-extras/img/localeDropdown.png b/packages/docs/docs/tutorial-extras/img/localeDropdown.png deleted file mode 100644 index e257edc..0000000 Binary files a/packages/docs/docs/tutorial-extras/img/localeDropdown.png and /dev/null differ diff --git a/packages/docs/docs/tutorial-extras/manage-docs-versions.md b/packages/docs/docs/tutorial-extras/manage-docs-versions.md deleted file mode 100644 index ccda0b9..0000000 --- a/packages/docs/docs/tutorial-extras/manage-docs-versions.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Manage Docs Versions - -Docusaurus can manage multiple versions of your docs. - -## Create a docs version - -Release a version 1.0 of your project: - -```bash -npm run docusaurus docs:version 1.0 -``` - -The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created. - -Your docs now have 2 versions: - -- `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs -- `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs** - -## Add a Version Dropdown - -To navigate seamlessly across versions, add a version dropdown. - -Modify the `docusaurus.config.js` file: - -```js title="docusaurus.config.js" -export default { - themeConfig: { - navbar: { - items: [ - // highlight-start - { - type: 'docsVersionDropdown', - }, - // highlight-end - ], - }, - }, -}; -``` - -The docs version dropdown appears in your navbar: - -![Docs Version Dropdown](./img/docsVersionDropdown.png) - -## Update an existing version - -It is possible to edit versioned docs in their respective folder: - -- `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello` -- `docs/hello.md` updates `http://localhost:3000/docs/next/hello` diff --git a/packages/docs/docs/tutorial-extras/translate-your-site.md b/packages/docs/docs/tutorial-extras/translate-your-site.md deleted file mode 100644 index b5a644a..0000000 --- a/packages/docs/docs/tutorial-extras/translate-your-site.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -sidebar_position: 2 ---- - -# Translate your site - -Let's translate `docs/intro.md` to French. - -## Configure i18n - -Modify `docusaurus.config.js` to add support for the `fr` locale: - -```js title="docusaurus.config.js" -export default { - i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], - }, -}; -``` - -## Translate a doc - -Copy the `docs/intro.md` file to the `i18n/fr` folder: - -```bash -mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/ - -cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md -``` - -Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French. - -## Start your localized site - -Start your site on the French locale: - -```bash -npm run start -- --locale fr -``` - -Your localized site is accessible at [http://localhost:3000/fr/](http://localhost:3000/fr/) and the `Getting Started` page is translated. - -:::caution - -In development, you can only use one locale at a time. - -::: - -## Add a Locale Dropdown - -To navigate seamlessly across languages, add a locale dropdown. - -Modify the `docusaurus.config.js` file: - -```js title="docusaurus.config.js" -export default { - themeConfig: { - navbar: { - items: [ - // highlight-start - { - type: 'localeDropdown', - }, - // highlight-end - ], - }, - }, -}; -``` - -The locale dropdown now appears in your navbar: - -![Locale Dropdown](./img/localeDropdown.png) - -## Build your localized site - -Build your site for a specific locale: - -```bash -npm run build -- --locale fr -``` - -Or build your site to include all the locales at once: - -```bash -npm run build -``` diff --git a/packages/docs/docusaurus.config.ts b/packages/docs/docusaurus.config.ts index dc37f1d..90ee9f8 100644 --- a/packages/docs/docusaurus.config.ts +++ b/packages/docs/docusaurus.config.ts @@ -1,13 +1,13 @@ -import type * as Preset from '@docusaurus/preset-classic'; -import type {Config} from '@docusaurus/types'; -import {themes as prismThemes} from 'prism-react-renderer'; +import type * as Preset from "@docusaurus/preset-classic" +import type { Config } from "@docusaurus/types" +import { themes as prismThemes } from "prism-react-renderer" // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) const config: Config = { - title: 'My Site', - tagline: 'Dinosaurs are cool', - favicon: 'img/favicon.ico', + title: "Effect View", + tagline: "Write React function components with Effect", + favicon: "img/favicon.ico", // Future flags, see https://docusaurus.io/docs/api/docusaurus-config#future future: { @@ -15,54 +15,48 @@ const config: Config = { }, // Set the production url of your site here - url: 'https://your-docusaurus-site.example.com', + url: "https://thiladev.github.io", // Set the // pathname under which your site is served // For GitHub pages deployment, it is often '//' - baseUrl: '/', + baseUrl: "/effect-view/", // GitHub pages deployment config. // If you aren't using GitHub pages, you don't need these. - organizationName: 'facebook', // Usually your GitHub org/user name. - projectName: 'docusaurus', // Usually your repo name. + organizationName: "Thiladev", // Usually your GitHub org/user name. + projectName: "effect-view", // Usually your repo name. - onBrokenLinks: 'throw', + onBrokenLinks: "throw", // Even if you don't use internationalization, you can use this field to set // useful metadata like html lang. For example, if your site is Chinese, you // may want to replace "en" with "zh-Hans". i18n: { - defaultLocale: 'en', - locales: ['en'], + defaultLocale: "en", + locales: ["en"], }, presets: [ [ - 'classic', + "classic", { docs: { - sidebarPath: './sidebars.ts', - // Please change this to your repo. - // Remove this to remove the "edit this page" links. + sidebarPath: "./sidebars.ts", editUrl: - 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', - }, - blog: { - showReadingTime: true, - feedOptions: { - type: ['rss', 'atom'], - xslt: true, + "https://github.com/Thiladev/effect-view/tree/main/packages/docs/", + lastVersion: "current", + versions: { + current: { + label: "effect-view v0", + }, + "effect-fc-v0": { + label: "effect-fc v0", + path: "effect-fc/v0", + }, }, - // Please change this to your repo. - // Remove this to remove the "edit this page" links. - editUrl: - 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', - // Useful options to enforce blogging best practices - onInlineTags: 'warn', - onInlineAuthors: 'warn', - onUntruncatedBlogPosts: 'warn', }, + blog: false, theme: { - customCss: './src/css/custom.css', + customCss: "./src/css/custom.css", }, } satisfies Preset.Options, ], @@ -70,81 +64,84 @@ const config: Config = { themeConfig: { // Replace with your project's social card - image: 'img/docusaurus-social-card.jpg', colorMode: { respectPrefersColorScheme: true, }, navbar: { - title: 'My Site', + title: "Effect View", logo: { - alt: 'My Site Logo', - src: 'img/logo.svg', + alt: "Effect View logo", + src: "img/logo.svg", }, items: [ { - type: 'docSidebar', - sidebarId: 'tutorialSidebar', - position: 'left', - label: 'Tutorial', + type: "docSidebar", + sidebarId: "docsSidebar", + position: "left", + label: "Docs", }, - {to: '/blog', label: 'Blog', position: 'left'}, { - href: 'https://github.com/facebook/docusaurus', - label: 'GitHub', - position: 'right', + type: "docsVersionDropdown", + position: "right", + }, + { + href: "https://www.npmjs.com/package/effect-view", + label: "npm", + position: "right", + }, + { + href: "https://github.com/Thiladev/effect-view", + label: "GitHub", + position: "right", }, ], }, footer: { - style: 'dark', + style: "dark", links: [ { - title: 'Docs', + title: "Docs", items: [ { - label: 'Tutorial', - to: '/docs/intro', + label: "Getting Started", + to: "/docs/getting-started", }, ], }, { - title: 'Community', + title: "Project", items: [ { - label: 'Stack Overflow', - href: 'https://stackoverflow.com/questions/tagged/docusaurus', + label: "GitHub", + href: "https://github.com/Thiladev/effect-view", }, { - label: 'Discord', - href: 'https://discordapp.com/invite/docusaurus', - }, - { - label: 'X', - href: 'https://x.com/docusaurus', + label: "Example App", + href: "https://github.com/Thiladev/effect-view/tree/main/packages/example", }, ], }, { - title: 'More', + title: "Ecosystem", items: [ { - label: 'Blog', - to: '/blog', + label: "Effect", + href: "https://effect.website/", }, { - label: 'GitHub', - href: 'https://github.com/facebook/docusaurus', + label: "React", + href: "https://react.dev/", }, ], }, ], - copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, + copyright: `Copyright © ${new Date().getFullYear()} Effect View contributors. Built with Docusaurus.`, }, prism: { theme: prismThemes.github, darkTheme: prismThemes.dracula, }, } satisfies Preset.ThemeConfig, -}; +} -export default config; +export default config diff --git a/packages/docs/package.json b/packages/docs/package.json index c7a516c..726f33d 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -3,21 +3,25 @@ "version": "0.0.0", "private": true, "scripts": { + "lint:tsc": "tsc -b --noEmit", + "lint:biome": "biome lint", "docusaurus": "docusaurus", "start": "docusaurus start", - "build": "docusaurus build", + "build": "docusaurus build --out-dir dist", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", "clear": "docusaurus clear", - "serve": "docusaurus serve", + "serve": "docusaurus serve --dir dist", "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", - "typecheck": "tsc" + "clean:cache": "rm -rf .turbo *.tsbuildinfo && docusaurus clear", + "clean:dist": "rm -rf dist", + "clean:modules": "rm -rf node_modules" }, "dependencies": { - "@docusaurus/core": "3.10.1", - "@docusaurus/faster": "^3.10.1", - "@docusaurus/preset-classic": "3.10.1", + "@docusaurus/core": "^3.10.2", + "@docusaurus/faster": "^3.10.2", + "@docusaurus/preset-classic": "^3.10.2", "@mdx-js/react": "^3.1.1", "clsx": "^2.1.1", "prism-react-renderer": "^2.4.1", @@ -25,9 +29,11 @@ "react-dom": "^19.2.5" }, "devDependencies": { - "@docusaurus/module-type-aliases": "3.10.1", - "@docusaurus/tsconfig": "3.10.1", - "@docusaurus/types": "3.10.1", + "@docusaurus/module-type-aliases": "^3.10.2", + "@docusaurus/tsconfig": "^3.10.2", + "@docusaurus/types": "^3.10.2", + "@types/react": "^19.2.15", + "@types/react-dom": "^19.2.3", "typescript": "~6.0.3" }, "browserslist": { diff --git a/packages/docs/sidebars.ts b/packages/docs/sidebars.ts index 2897139..7f3da56 100644 --- a/packages/docs/sidebars.ts +++ b/packages/docs/sidebars.ts @@ -1,33 +1,15 @@ -import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; +import type { SidebarsConfig } from "@docusaurus/plugin-content-docs" // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) -/** - * Creating a sidebar enables you to: - - create an ordered group of docs - - render a sidebar for each doc of that group - - provide next/previous navigation - - The sidebars can be generated from the filesystem, or explicitly defined here. - - Create as many sidebars as you want. - */ const sidebars: SidebarsConfig = { - // By default, Docusaurus generates a sidebar from the docs folder structure - tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], - - // But you can create a sidebar manually - /* - tutorialSidebar: [ - 'intro', - 'hello', - { - type: 'category', - label: 'Tutorial', - items: ['tutorial-basics/create-a-document'], - }, + docsSidebar: [ + "getting-started", + "state-management", + "query", + "mutation", + "forms", ], - */ -}; +} -export default sidebars; +export default sidebars diff --git a/packages/docs/src/components/HomepageFeatures/index.tsx b/packages/docs/src/components/HomepageFeatures/index.tsx deleted file mode 100644 index c2551fb..0000000 --- a/packages/docs/src/components/HomepageFeatures/index.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import type {ReactNode} from 'react'; -import clsx from 'clsx'; -import Heading from '@theme/Heading'; -import styles from './styles.module.css'; - -type FeatureItem = { - title: string; - Svg: React.ComponentType>; - description: ReactNode; -}; - -const FeatureList: FeatureItem[] = [ - { - title: 'Easy to Use', - Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, - description: ( - <> - Docusaurus was designed from the ground up to be easily installed and - used to get your website up and running quickly. - - ), - }, - { - title: 'Focus on What Matters', - Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, - description: ( - <> - Docusaurus lets you focus on your docs, and we'll do the chores. Go - ahead and move your docs into the docs directory. - - ), - }, - { - title: 'Powered by React', - Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, - description: ( - <> - Extend or customize your website layout by reusing React. Docusaurus can - be extended while reusing the same header and footer. - - ), - }, -]; - -function Feature({title, Svg, description}: FeatureItem) { - return ( -
-
- -
-
- {title} -

{description}

-
-
- ); -} - -export default function HomepageFeatures(): ReactNode { - return ( -
-
-
- {FeatureList.map((props, idx) => ( - - ))} -
-
-
- ); -} diff --git a/packages/docs/src/components/HomepageFeatures/styles.module.css b/packages/docs/src/components/HomepageFeatures/styles.module.css deleted file mode 100644 index b248eb2..0000000 --- a/packages/docs/src/components/HomepageFeatures/styles.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.features { - display: flex; - align-items: center; - padding: 2rem 0; - width: 100%; -} - -.featureSvg { - height: 200px; - width: 200px; -} diff --git a/packages/docs/src/css/custom.css b/packages/docs/src/css/custom.css index 2bc6a4c..aa3946b 100644 --- a/packages/docs/src/css/custom.css +++ b/packages/docs/src/css/custom.css @@ -1,30 +1,37 @@ -/** - * Any CSS included here will be global. The classic template - * bundles Infima by default. Infima is a CSS framework designed to - * work well for content-centric websites. - */ - -/* You can override the default Infima variables here. */ :root { - --ifm-color-primary: #2e8555; - --ifm-color-primary-dark: #29784c; - --ifm-color-primary-darker: #277148; - --ifm-color-primary-darkest: #205d3b; - --ifm-color-primary-light: #33925d; - --ifm-color-primary-lighter: #359962; - --ifm-color-primary-lightest: #3cad6e; + --ifm-color-primary: #0b6f74; + --ifm-color-primary-dark: #096469; + --ifm-color-primary-darker: #085e63; + --ifm-color-primary-darkest: #074d51; + --ifm-color-primary-light: #0d7a7f; + --ifm-color-primary-lighter: #0e8085; + --ifm-color-primary-lightest: #109096; + --ifm-background-color: #fffaf1; --ifm-code-font-size: 95%; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); + --ifm-font-family-base: + "Avenir Next", "Segoe UI", "Helvetica Neue", sans-serif; + --docusaurus-highlighted-code-line-bg: rgba(11, 111, 116, 0.1); } -/* For readability concerns, you should choose a lighter palette in dark mode. */ -[data-theme='dark'] { - --ifm-color-primary: #25c2a0; - --ifm-color-primary-dark: #21af90; - --ifm-color-primary-darker: #1fa588; - --ifm-color-primary-darkest: #1a8870; - --ifm-color-primary-light: #29d5b0; - --ifm-color-primary-lighter: #32d8b4; - --ifm-color-primary-lightest: #4fddbf; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +.button--primary { + --ifm-button-background-color: #0b6f74; + --ifm-button-border-color: #0b6f74; +} + +.button--secondary { + --ifm-button-background-color: #f4a636; + --ifm-button-border-color: #f4a636; + --ifm-button-color: #1f2526; +} + +[data-theme="dark"] { + --ifm-color-primary: #7ad6d4; + --ifm-color-primary-dark: #5cccca; + --ifm-color-primary-darker: #4cc6c4; + --ifm-color-primary-darkest: #34aaa8; + --ifm-color-primary-light: #98e0de; + --ifm-color-primary-lighter: #a8e6e4; + --ifm-color-primary-lightest: #d5f4f3; + --ifm-background-color: #111c1f; + --docusaurus-highlighted-code-line-bg: rgba(122, 214, 212, 0.18); } diff --git a/packages/docs/src/pages/index.module.css b/packages/docs/src/pages/index.module.css index 9f71a5d..042c345 100644 --- a/packages/docs/src/pages/index.module.css +++ b/packages/docs/src/pages/index.module.css @@ -1,23 +1,672 @@ -/** - * CSS files with the .module.css suffix will be treated as CSS modules - * and scoped locally. - */ - -.heroBanner { - padding: 4rem 0; - text-align: center; - position: relative; +.page { + --home-ink: #102f31; + --home-muted: #506a6c; + --home-teal: #08777b; + --home-teal-bright: #16a3a1; + --home-amber: #e99526; + --home-paper: #fffdf8; + --home-card: rgba(255, 255, 255, 0.76); + --home-line: rgba(16, 47, 49, 0.12); + min-height: calc(100vh - var(--ifm-navbar-height)); overflow: hidden; + position: relative; + background: + radial-gradient(circle at 8% 5%, rgba(14, 145, 148, 0.2), transparent 28rem), + radial-gradient(circle at 92% 14%, rgba(240, 159, 48, 0.2), transparent 27rem), + linear-gradient(145deg, #f7f2e7 0%, #edf8f6 48%, #fff8ed 100%); + color: var(--home-ink); } -@media screen and (max-width: 996px) { - .heroBanner { - padding: 2rem; +.gridBackdrop { + background-image: + linear-gradient(rgba(16, 47, 49, 0.045) 1px, transparent 1px), + linear-gradient(90deg, rgba(16, 47, 49, 0.045) 1px, transparent 1px); + background-size: 48px 48px; + inset: 0; + mask-image: linear-gradient(to bottom, black, transparent 62%); + pointer-events: none; + position: absolute; +} + +.hero { + align-items: center; + display: grid; + gap: clamp(3rem, 6vw, 6rem); + grid-template-columns: minmax(0, 0.88fr) minmax(560px, 1.12fr); + min-height: min(820px, calc(100vh - var(--ifm-navbar-height))); + padding-bottom: 6rem; + padding-top: 6rem; + position: relative; + z-index: 1; +} + +.heroCopy { + max-width: 650px; +} + +.eyebrow, +.sectionKicker { + align-items: center; + color: var(--home-teal); + display: flex; + font-size: 0.76rem; + font-weight: 850; + gap: 0.65rem; + letter-spacing: 0.18em; + margin: 0 0 1.35rem; + text-transform: uppercase; +} + +.pulse { + background: var(--home-teal-bright); + border-radius: 50%; + box-shadow: 0 0 0 5px rgba(22, 163, 161, 0.14); + height: 0.55rem; + width: 0.55rem; +} + +.hero h1 { + color: var(--home-ink); + font-size: clamp(3.4rem, 6.4vw, 6.4rem); + font-weight: 780; + letter-spacing: -0.075em; + line-height: 0.92; + margin: 0; +} + +.hero h1 span { + background: linear-gradient(105deg, var(--home-teal) 5%, #1a9793 48%, var(--home-amber)); + background-clip: text; + color: transparent; + display: inline; + -webkit-background-clip: text; +} + +.lede { + color: var(--home-muted); + font-size: clamp(1.08rem, 1.55vw, 1.32rem); + line-height: 1.65; + margin: 2rem 0 0; + max-width: 630px; +} + +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.8rem; + margin-top: 2.3rem; +} + +.primaryAction, +.secondaryAction, +.ctaAction { + align-items: center; + border-radius: 999px; + display: inline-flex; + font-weight: 750; + gap: 0.8rem; + justify-content: center; + padding: 0.88rem 1.35rem; + text-decoration: none !important; + transition: transform 160ms ease, box-shadow 160ms ease, background 160ms ease; +} + +.primaryAction { + background: var(--home-ink); + box-shadow: 0 12px 28px rgba(16, 47, 49, 0.2); + color: #f6fffd; +} + +.primaryAction:hover { + box-shadow: 0 16px 36px rgba(16, 47, 49, 0.28); + color: #fff; + transform: translateY(-2px); +} + +.secondaryAction { + background: rgba(255, 255, 255, 0.58); + border: 1px solid var(--home-line); + color: var(--home-ink); +} + +.secondaryAction:hover { + background: rgba(255, 255, 255, 0.9); + color: var(--home-teal); + transform: translateY(-2px); +} + +.install { + align-items: center; + color: var(--home-muted); + display: flex; + font-size: 0.84rem; + gap: 0.7rem; + margin-top: 1.4rem; +} + +.install span { + color: var(--home-amber); + font-family: var(--ifm-font-family-monospace); + font-weight: 800; +} + +.install code { + background: transparent; + border: 0; + color: inherit; + padding: 0; +} + +.hotReload { + align-items: center; + color: var(--home-teal); + display: inline-flex; + font-size: 0.82rem; + font-weight: 750; + gap: 0.5rem; + margin-top: 0.75rem; + text-decoration: none !important; +} + +.hotReload span { + color: var(--home-amber); + font-size: 1rem; +} + +.hotReload:hover { + color: var(--home-teal-bright); +} + +.codeStage { + min-width: 0; + perspective: 1200px; + position: relative; +} + +.codeGlow { + background: linear-gradient(115deg, rgba(11, 133, 136, 0.48), rgba(238, 156, 40, 0.38)); + filter: blur(55px); + inset: 8% 5%; + opacity: 0.55; + position: absolute; +} + +.codeWindow { + background: #101b1e; + border: 1px solid rgba(166, 225, 220, 0.2); + border-radius: 1.25rem; + box-shadow: + 0 34px 90px rgba(18, 49, 52, 0.3), + 0 2px 0 rgba(255, 255, 255, 0.06) inset; + overflow: hidden; + position: relative; + transform: rotateY(-2deg) rotateX(1deg); +} + +.windowBar { + align-items: center; + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + color: #b6c9c9; + display: grid; + font-family: var(--ifm-font-family-monospace); + font-size: 0.73rem; + grid-template-columns: 1fr auto 1fr; + padding: 0.78rem 1rem; +} + +.windowDots { + display: flex; + gap: 0.38rem; +} + +.windowDots span { + background: #4f6d6e; + border-radius: 50%; + height: 0.55rem; + width: 0.55rem; +} + +.windowDots span:first-child { + background: #ef8d5b; +} + +.windowDots span:nth-child(2) { + background: #e9bc50; +} + +.windowDots span:last-child { + background: #65bd92; +} + +.windowStatus { + color: #74d2cd; + justify-self: end; +} + +.codeWindow :global(.theme-code-block) { + border-radius: 0; + box-shadow: none; + margin: 0; +} + +.codeWindow :global(.theme-code-block pre) { + background: #101b1e !important; + color: #d7e5e4 !important; + font-size: 0.78rem; + line-height: 1.62; + max-height: none; + padding: 1.45rem 1.6rem !important; +} + +.codeWindow :global(.token-line), +.codeWindow :global(.token.plain), +.codeWindow :global(.token.imports), +.codeWindow :global(.token.maybe-class-name), +.codeWindow :global(.token.punctuation), +.codeWindow :global(.token.operator), +.codeWindow :global(.token.plain-text), +.codeWindow :global(.token.property-access) { + color: #d7e5e4 !important; +} + +.codeWindow :global(.token.keyword) { + color: #c792ea !important; +} + +.codeWindow :global(.token.string) { + color: #c3e88d !important; +} + +.codeWindow :global(.token.function), +.codeWindow :global(.token.method) { + color: #82aaff !important; +} + +.codeWindow :global(.token.tag) { + color: #f07178 !important; +} + +.codeWindow :global(.token.builtin) { + color: #ffcb6b !important; +} + +.codeLegend { + border-top: 1px solid rgba(255, 255, 255, 0.08); + color: #a9bcbc; + display: grid; + font-size: 0.7rem; + grid-template-columns: repeat(3, 1fr); +} + +.codeLegend span { + padding: 0.8rem 0.9rem; + text-align: center; +} + +.codeLegend span + span { + border-left: 1px solid rgba(255, 255, 255, 0.08); +} + +.codeLegend b { + color: #e8a94b; + font-family: var(--ifm-font-family-monospace); + margin-right: 0.25rem; +} + +.featuresSection { + padding-bottom: 7rem; + padding-top: 4rem; + position: relative; + z-index: 1; +} + +.sectionHeading { + display: grid; + gap: 0 3rem; + grid-template-columns: minmax(0, 1.25fr) minmax(280px, 0.75fr); + margin-bottom: 2.8rem; +} + +.sectionHeading .sectionKicker { + grid-column: 1 / -1; +} + +.sectionHeading h2, +.cta h2 { + color: var(--home-ink); + font-size: clamp(2.25rem, 4vw, 4rem); + letter-spacing: -0.055em; + line-height: 1; + margin: 0; +} + +.sectionHeading > p:last-child { + align-self: end; + color: var(--home-muted); + font-size: 1.03rem; + line-height: 1.65; + margin: 0; +} + +.featureGrid { + display: grid; + gap: 1rem; + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.featureCard { + background: var(--home-card); + border: 1px solid var(--home-line); + border-radius: 1.35rem; + color: inherit; + display: flex; + flex-direction: column; + min-height: 310px; + overflow: hidden; + padding: 1.45rem; + position: relative; + text-decoration: none !important; + transition: border-color 180ms ease, box-shadow 180ms ease, transform 180ms ease; +} + +.featureCard::before { + background: linear-gradient(90deg, var(--home-teal-bright), var(--home-amber)); + content: ""; + height: 3px; + left: 1.45rem; + opacity: 0; + position: absolute; + right: 1.45rem; + top: 0; + transform: scaleX(0.5); + transition: opacity 180ms ease, transform 180ms ease; +} + +.featureCard:hover { + border-color: rgba(8, 119, 123, 0.35); + box-shadow: 0 24px 60px rgba(28, 65, 66, 0.12); + color: inherit; + transform: translateY(-5px); +} + +.featureCard:hover::before { + opacity: 1; + transform: scaleX(1); +} + +.cardTopline { + align-items: center; + display: flex; + justify-content: space-between; +} + +.featureIcon { + align-items: center; + background: rgba(8, 119, 123, 0.1); + border: 1px solid rgba(8, 119, 123, 0.12); + border-radius: 0.8rem; + color: var(--home-teal); + display: flex; + font-family: var(--ifm-font-family-monospace); + font-size: 1rem; + font-weight: 850; + height: 2.7rem; + justify-content: center; + width: 2.7rem; +} + +.cardIndex { + color: rgba(16, 47, 49, 0.32); + font-family: var(--ifm-font-family-monospace); + font-size: 0.72rem; +} + +.featureCard h3 { + color: var(--home-ink); + font-size: 1.25rem; + letter-spacing: -0.025em; + margin: 2rem 0 0.7rem; +} + +.featureCard > p { + color: var(--home-muted); + font-size: 0.94rem; + line-height: 1.65; + margin: 0; +} + +.cardFooter { + align-items: center; + display: flex; + justify-content: space-between; + margin-top: auto; + padding-top: 1.5rem; +} + +.cardFooter code { + background: rgba(8, 119, 123, 0.08); + border: 0; + color: var(--home-teal); + font-size: 0.7rem; + padding: 0.35rem 0.5rem; +} + +.cardFooter > span { + color: var(--home-amber); + font-size: 1.1rem; + transition: transform 180ms ease; +} + +.featureCard:hover .cardFooter > span { + transform: translate(3px, -3px); +} + +.ctaWrap { + padding-bottom: 7rem; + position: relative; + z-index: 1; +} + +.cta { + align-items: center; + background: + radial-gradient(circle at 90% 20%, rgba(233, 149, 38, 0.22), transparent 20rem), + linear-gradient(125deg, #12383a, #10292c); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 1.75rem; + box-shadow: 0 28px 80px rgba(16, 47, 49, 0.2); + display: flex; + gap: 3rem; + justify-content: space-between; + overflow: hidden; + padding: clamp(2rem, 5vw, 4rem); +} + +.cta .sectionKicker { + color: #79d5d1; +} + +.cta h2 { + color: #f7fffd; +} + +.cta p:last-child { + color: #b9cccc; + line-height: 1.65; + margin: 1rem 0 0; + max-width: 650px; +} + +.ctaAction { + background: #f0a13b; + color: #162d2e; + flex: 0 0 auto; +} + +.ctaAction:hover { + box-shadow: 0 14px 35px rgba(0, 0, 0, 0.24); + color: #102526; + transform: translateY(-2px); +} + +:global([data-theme="dark"]) .page { + --home-ink: #e9f7f5; + --home-muted: #a9bfbd; + --home-teal: #79d5d1; + --home-teal-bright: #5bc8c5; + --home-amber: #f1ad4e; + --home-card: rgba(20, 42, 45, 0.76); + --home-line: rgba(174, 221, 218, 0.14); + background: + radial-gradient(circle at 8% 5%, rgba(33, 154, 154, 0.17), transparent 28rem), + radial-gradient(circle at 92% 14%, rgba(209, 130, 31, 0.13), transparent 27rem), + linear-gradient(145deg, #0f1b1e 0%, #102426 48%, #161e1e 100%); +} + +:global([data-theme="dark"]) .gridBackdrop { + background-image: + linear-gradient(rgba(174, 221, 218, 0.04) 1px, transparent 1px), + linear-gradient(90deg, rgba(174, 221, 218, 0.04) 1px, transparent 1px); +} + +:global([data-theme="dark"]) .secondaryAction { + background: rgba(19, 43, 46, 0.75); +} + +:global([data-theme="dark"]) .secondaryAction:hover { + background: rgba(27, 57, 60, 0.95); +} + +:global([data-theme="dark"]) .primaryAction { + background: #dff8f5; + color: #123638; +} + +:global([data-theme="dark"]) .primaryAction:hover { + color: #0b282a; +} + +:global([data-theme="dark"]) .cardIndex { + color: rgba(220, 242, 239, 0.35); +} + +@media screen and (max-width: 1180px) { + .hero { + gap: 3rem; + grid-template-columns: minmax(0, 0.85fr) minmax(500px, 1.15fr); + } + + .hero h1 { + font-size: clamp(3.2rem, 6vw, 5rem); } } -.buttons { - display: flex; - align-items: center; - justify-content: center; +@media screen and (max-width: 996px) { + .hero { + grid-template-columns: minmax(0, 1fr); + padding-bottom: 4rem; + padding-top: 4.5rem; + } + + .heroCopy, + .codeStage, + .codeWindow, + .codeWindow :global(.theme-code-block) { + min-width: 0; + width: 100%; + } + + .heroCopy { + max-width: 760px; + } + + .codeStage { + margin: 0 auto; + max-width: 760px; + width: 100%; + } + + .codeWindow { + transform: none; + } + + .featureGrid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media screen and (max-width: 700px) { + .hero { + box-sizing: border-box; + margin-left: 0; + margin-right: 0; + max-width: 100vw; + padding-left: 1.15rem; + padding-right: 1.15rem; + width: 100vw; + } + + .heroCopy, + .codeStage { + max-width: calc(100vw - 2.3rem); + } + + .hero h1 { + font-size: clamp(3rem, 15vw, 4.3rem); + } + + .sectionHeading { + grid-template-columns: 1fr; + } + + .sectionHeading > p:last-child { + margin-top: 1.25rem; + } + + .featureGrid { + grid-template-columns: 1fr; + } + + .featureCard { + min-height: 275px; + } + + .codeLegend { + grid-template-columns: 1fr; + } + + .codeLegend span + span { + border-left: 0; + border-top: 1px solid rgba(255, 255, 255, 0.08); + } + + .windowStatus { + display: none; + } + + .windowBar { + grid-template-columns: 1fr auto; + } + + .codeWindow :global(.theme-code-block pre) { + font-size: 0.69rem; + overflow-x: auto; + padding: 1.1rem !important; + } + + .cta { + align-items: flex-start; + flex-direction: column; + } +} + +@media (prefers-reduced-motion: reduce) { + .featureCard, + .featureCard::before, + .cardFooter > span, + .primaryAction, + .secondaryAction, + .ctaAction { + transition: none; + } } diff --git a/packages/docs/src/pages/index.tsx b/packages/docs/src/pages/index.tsx index 0a49f5d..7119772 100644 --- a/packages/docs/src/pages/index.tsx +++ b/packages/docs/src/pages/index.tsx @@ -1,44 +1,212 @@ -import Link from '@docusaurus/Link'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import HomepageFeatures from '@site/src/components/HomepageFeatures'; -import Heading from '@theme/Heading'; -import Layout from '@theme/Layout'; -import clsx from 'clsx'; -import type {ReactNode} from 'react'; +import Link from "@docusaurus/Link" +import CodeBlock from "@theme/CodeBlock" +import Layout from "@theme/Layout" +import clsx from "clsx" +import type { ReactNode } from "react" -import styles from './index.module.css'; +import styles from "./index.module.css" -function HomepageHeader() { - const {siteConfig} = useDocusaurusContext(); - return ( -
-
- - {siteConfig.title} - -

{siteConfig.tagline}

-
- - Docusaurus Tutorial - 5min ⏱️ - -
-
-
- ); -} +const componentExample = `import { Effect } from "effect" +import { Async, Component } from "effect-view" +import { Users } from "./services" + +export const UserCard = Component.make("UserCard")( + function* ({ userId }: { userId: string }) { + const users = yield* Users + + const user = yield* Component.useOnChange( + () => users.find(userId), + [userId], + ) + + yield* Component.useReactEffect( + () => Effect.forkScoped(users.watch(userId)), + [userId], + ) + + return ( +
+

{user.name}

+

{user.email}

+
+ ) + }, +).pipe(Async.async)` + +const features = [ + { + icon: "fx", + title: "Components are Effect programs", + description: + "Yield Effects and services directly from a component body, then return ordinary JSX. Types track every dependency all the way to the runtime boundary.", + tag: "Component.make", + to: "/docs/getting-started#write-your-first-component", + }, + { + icon: "R", + title: "One typed runtime", + description: + "Build your application Layer once. Components access HTTP clients, repositories, configuration, tracing, and your own services without React context plumbing.", + tag: "ReactRuntime", + to: "/docs/getting-started#create-the-runtime", + }, + { + icon: "S", + title: "Scopes follow React", + description: + "Every component owns an Effect Scope. Resources, subscriptions, and fibers are finalized when their component or dependency lifecycle ends.", + tag: "Scope.Scope", + to: "/docs/getting-started#the-component-root-scope", + }, + { + icon: "↔", + title: "Reactive state without a new universe", + description: + "Lens and View connect Effect state to React. Focus large models into small writable values and subscribe only where rendering needs them.", + tag: "Lens + View", + to: "/docs/state-management", + }, + { + icon: "Q", + title: "TanStack-shaped server state", + description: + "Reactive keys, caching, stale times, background refresh, mutations, and invalidation—with typed Effect services, Causes, and scoped fibers underneath.", + tag: "Query + Mutation", + to: "/docs/query", + }, + { + icon: "Σ", + title: "Forms driven by Schema", + description: + "Keep input-friendly encoded values while application code receives validated, decoded types. Focus one root into reusable field-sized subforms.", + tag: "MutationForm + LensForm", + to: "/docs/forms", + }, +] as const export default function Home(): ReactNode { - const {siteConfig} = useDocusaurusContext(); return ( - -
- + title="Effect View" + description="Write React function components as typed Effect programs" + > +
+
- ); + ) } diff --git a/packages/docs/src/pages/markdown-page.md b/packages/docs/src/pages/markdown-page.md deleted file mode 100644 index 9756c5b..0000000 --- a/packages/docs/src/pages/markdown-page.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Markdown page example ---- - -# Markdown page example - -You don't need React to write simple standalone pages. diff --git a/packages/docs/static/img/docusaurus-social-card.jpg b/packages/docs/static/img/docusaurus-social-card.jpg deleted file mode 100644 index ffcb448..0000000 Binary files a/packages/docs/static/img/docusaurus-social-card.jpg and /dev/null differ diff --git a/packages/docs/static/img/docusaurus.png b/packages/docs/static/img/docusaurus.png deleted file mode 100644 index f458149..0000000 Binary files a/packages/docs/static/img/docusaurus.png and /dev/null differ diff --git a/packages/docs/static/img/logo.svg b/packages/docs/static/img/logo.svg index 9db6d0d..85294cf 100644 --- a/packages/docs/static/img/logo.svg +++ b/packages/docs/static/img/logo.svg @@ -1 +1,47 @@ - \ No newline at end of file + + Effect View + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/docs/static/img/undraw_docusaurus_mountain.svg b/packages/docs/static/img/undraw_docusaurus_mountain.svg deleted file mode 100644 index af961c4..0000000 --- a/packages/docs/static/img/undraw_docusaurus_mountain.svg +++ /dev/null @@ -1,171 +0,0 @@ - - Easy to Use - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/docs/static/img/undraw_docusaurus_react.svg b/packages/docs/static/img/undraw_docusaurus_react.svg deleted file mode 100644 index 94b5cf0..0000000 --- a/packages/docs/static/img/undraw_docusaurus_react.svg +++ /dev/null @@ -1,170 +0,0 @@ - - Powered by React - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/docs/static/img/undraw_docusaurus_tree.svg b/packages/docs/static/img/undraw_docusaurus_tree.svg deleted file mode 100644 index d9161d3..0000000 --- a/packages/docs/static/img/undraw_docusaurus_tree.svg +++ /dev/null @@ -1,40 +0,0 @@ - - Focus on What Matters - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/docs/tsconfig.json b/packages/docs/tsconfig.json index 920d7a6..ae701a6 100644 --- a/packages/docs/tsconfig.json +++ b/packages/docs/tsconfig.json @@ -2,7 +2,8 @@ // This file is not used in compilation. It is here just for a nice editor experience. "extends": "@docusaurus/tsconfig", "compilerOptions": { - "baseUrl": "." + "baseUrl": ".", + "ignoreDeprecations": "6.0" }, "exclude": [".docusaurus", "build"] } diff --git a/packages/docs/versioned_docs/version-effect-fc-v0/forms.md b/packages/docs/versioned_docs/version-effect-fc-v0/forms.md new file mode 100644 index 0000000..944234f --- /dev/null +++ b/packages/docs/versioned_docs/version-effect-fc-v0/forms.md @@ -0,0 +1,168 @@ +--- +sidebar_position: 3 +title: Forms +--- + +# Forms + +The form modules provide an Effect-first model for editable, schema-validated +state. They are not a visual component library. Instead, they give you +Lenses/Subscribables for form values, validation issues, and commit state, so +you can build the UI with whatever components your app already uses. + +The base `Form` type represents a field. A field tracks both the raw encoded +value used by inputs and the decoded value produced by an Effect `Schema`: + +- `encodedValue`: a `Lens` containing the raw input value. +- `value`: a `Subscribable` containing the decoded value as an `Option`. +- `issues`: a `Subscribable` containing schema validation issues for that field. +- `canCommit`, `isValidating`, and `isCommitting`: `Subscribable` flags for UI + state. + +There are two root form flavors: + +- `SubmittableForm`: owns local encoded form state, validates it, and submits a + decoded value through a mutation. +- `SynchronizedForm`: wraps an existing target `Lens` and writes valid changes + back to that target. + +Most apps create one of those root forms, then focus it into fields with +`Form.focusObjectOn`, `Form.focusArrayAt`, or the other focusing helpers. + +The core form model is Effect code and can technically be used outside +Effect-FC. Effect-FC adds the React-facing hooks, such as `Form.useInput`, that +make those forms convenient to bind to components. + +## Field Inputs + +Use `Form.useInput` to connect a `Form` field to a controlled input. It returns +a React-style `{ value, setValue }` pair and writes changes back to the field's +`encodedValue` Lens. + +```tsx +import { Component, Form, Subscribable } from "effect-fc" + +const TextInputView = Component.make("TextInput")( + function* (props: { + readonly form: Form.Form + readonly label: string + }) { + const input = yield* Form.useInput(props.form, { + debounce: "250 millis", + }) + const [issues] = yield* Subscribable.useAll([props.form.issues]) + + return ( + + ) + }, +) +``` + +Use `Form.useOptionalInput` for `Option` fields. It returns the same value/setter +pair plus `enabled` and `setEnabled`, which is useful for optional inputs that +can be toggled on and off. + +## Submittable Forms + +Use `SubmittableForm` when the user edits local encoded form state, validates it +with a schema, and then submits a decoded value. + +```tsx +import { Effect, Schema } from "effect" +import { Component, Form, SubmittableForm, Subscribable } from "effect-fc" +import { TextInputView } from "./TextInputView" + +const RegisterSchema = Schema.Struct({ + email: Schema.String, + password: Schema.String, +}) + +class RegisterFormState extends Effect.Service()( + "RegisterFormState", + { + scoped: Effect.gen(function* () { + const form = yield* SubmittableForm.service({ + schema: RegisterSchema, + initialEncodedValue: { + email: "", + password: "", + }, + f: ([value]) => + Effect.log(`Registering ${value.email}`), + }) + + return { + form, + email: Form.focusObjectOn(form, "email"), + password: Form.focusObjectOn(form, "password"), + } as const + }), + }, +) {} + +const RegisterFormView = Component.make("RegisterForm")( + function* () { + const state = yield* RegisterFormState + const [canCommit, isCommitting] = yield* Subscribable.useAll([ + state.form.canCommit, + state.form.isCommitting, + ]) + const runPromise = yield* Component.useRunPromise() + const TextInput = yield* TextInputView.use + + return ( +
{ + event.preventDefault() + void runPromise(state.form.submit) + }} + > + + + + + ) + }, +) +``` + +`SubmittableForm.service` starts validation in the form's scope. The form keeps +its encoded input state, decoded value, validation issues, submit mutation, and +commit flags available as Lenses/Subscribables. + +## Synchronized Forms + +Use `SynchronizedForm` when a form should edit an existing target `Lens`. +Instead of submitting a final value, valid encoded changes are synchronized back +to the target Lens. + +This is useful for edit screens where the form is a validated view over existing +state. Use `SubmittableForm` for "submit this draft" flows, and +`SynchronizedForm` for "keep this target state synchronized when valid" flows. + +## Focusing Fields + +Forms can be focused just like Lenses: + +```tsx +const emailField = Form.focusObjectOn(form, "email") +const firstItemField = Form.focusArrayAt(form, 0) +``` + +Focused fields keep the parent form's validation and commit state, but narrow +`encodedValue`, `value`, and `issues` to the field path. This lets each input +component receive only the field it needs. diff --git a/packages/docs/versioned_docs/version-effect-fc-v0/getting-started.md b/packages/docs/versioned_docs/version-effect-fc-v0/getting-started.md new file mode 100644 index 0000000..2c4141c --- /dev/null +++ b/packages/docs/versioned_docs/version-effect-fc-v0/getting-started.md @@ -0,0 +1,415 @@ +--- +sidebar_position: 1 +title: Getting Started +--- + +# Getting Started + +`effect-fc` lets React components be written as Effect programs. Inside a +component body you can yield services, run Effects, subscribe to Effect-powered +state, and still export a normal React function component at the edge of your +app. + +## Install + +Install `effect-fc` alongside `effect` and React 19.2 or newer: + +```bash npm2yarn +npm install effect-fc effect react +``` +```bash npm2yarn +npm install --save-dev @types/react +``` + +`effect-fc` is not opinionated about the React platform. Use it with web, +native, custom renderers, or any environment where React components can run. +Then install the platform-specific React packages for your target. + +For web apps, install React DOM: + +```bash npm2yarn +npm install react-dom +``` +```bash npm2yarn +npm install --save-dev @types/react-dom +``` + +## Create A Runtime + +An Effect-FC app needs an Effect runtime. Build one from the services your UI +needs, then share it with React through `ReactRuntime.Provider`. + +For an empty app, `Layer.empty` is enough: + +```tsx title="src/runtime.ts" +import { Layer } from "effect" +import { ReactRuntime } from "effect-fc" + +export const runtime = ReactRuntime.make(Layer.empty) +``` + +As your app grows, add services to the layer: + +```tsx title="src/runtime.ts" +import { FetchHttpClient } from "@effect/platform" +import { Layer } from "effect" +import { ReactRuntime } from "effect-fc" + +const AppLive = Layer.empty.pipe( + Layer.provideMerge(FetchHttpClient.layer), +) + +export const runtime = ReactRuntime.make(AppLive) +``` + +## Provide The Runtime + +At the React root, wrap your app with `ReactRuntime.Provider`: + +```tsx title="src/main.tsx" +import { StrictMode } from "react" +import { createRoot } from "react-dom/client" +import { ReactRuntime } from "effect-fc" +import { App } from "./App" +import { runtime } from "./runtime" + +createRoot(document.getElementById("root")!).render( + + + + + , +) +``` + +`ReactRuntime.Provider` also works with routers. Keep it above your router +provider so route components can be converted with the same runtime context. + +## Write Your First Component + +Use `Component.make` when you want automatic tracing spans, or +`Component.makeUntraced` when you only want the component behavior. This creates +an Effect-FC component, not a plain React component yet. + +The Effect run during render must be synchronous. Effect-FC follows React's +render model, so component bodies should produce JSX without waiting on async +work. Use lifecycle hooks, callbacks, queries, or other Effect-FC helpers for +async work that happens outside render. + +```tsx title="src/HelloView.tsx" +import { Effect } from "effect" +import { Component } from "effect-fc" + +export const HelloView = Component.make("HelloView")(function* (props: { + readonly name: string +}) { + const message = yield* Effect.succeed(`Hello, ${props.name}`) + + return

{message}

+}) +``` + +At this point `HelloView` can yield Effects, services, and scoped lifecycle +work, but React cannot render it directly. + +## Apply A Runtime + +Use `Component.withRuntime` at the boundary where an Effect-FC component needs +to become a regular React function component. + +```tsx title="src/Hello.tsx" +import { Component } from "effect-fc" +import { HelloView } from "./HelloView" +import { runtime } from "./runtime" + +export const Hello = HelloView.pipe( + Component.withRuntime(runtime.context), +) +``` + +`Hello` is now a normal React component: + +```tsx title="src/App.tsx" +import { Hello } from "./Hello" + +export function App() { + return +} +``` + +## Use Effect-FC Components Together + +Inside an Effect-FC component, other Effect-FC components are available through +their `.use` effect. Yield `.use` to get a React component for the current +runtime context, then render it like JSX. + +```tsx title="src/GreetingCardView.tsx" +import { Component } from "effect-fc" +import { HelloView } from "./HelloView" + +export const GreetingCardView = Component.make("GreetingCard")( + function* () { + const Hello = yield* HelloView.use + + return ( +
+ +

This component is still running inside Effect-FC.

+
+ ) + }, +) +``` + +Use `Component.withRuntime` only when you leave the Effect-FC tree and need a +normal React component again: + +```tsx title="src/GreetingCard.tsx" +import { Component } from "effect-fc" +import { GreetingCardView } from "./GreetingCardView" +import { runtime } from "./runtime" + +export const GreetingCard = GreetingCardView.pipe( + Component.withRuntime(runtime.context), +) +``` + +## Component Lifecycle + +Every Effect-FC component instance exposes an Effect `Scope`. Effects that need +`Scope.Scope` can use that component scope to register finalizers, fork scoped +work, or acquire scoped resources. + +The component scope is created when React mounts the component and closes when +React unmounts it. When the scope closes, Effect runs the finalizers registered +inside that scope. + +Finalizers are forked when the scope closes, so cleanup logic can run +asynchronous Effects even though the component body itself must stay +synchronous. + +```tsx title="src/MountedMessageView.tsx" +import { Console, Effect } from "effect" +import { Component } from "effect-fc" + +export const MountedMessageView = Component.make("MountedMessage")( + function* () { + const message = yield* Component.useOnMount(() => + Effect.gen(function* () { + yield* Console.log("MountedMessage mounted") + yield* Effect.addFinalizer(() => + Console.log("MountedMessage unmounted"), + ) + + return "This value was loaded on mount." + }), + ) + + return

{message}

+ }, +) +``` + +Use `Component.useOnMount` when the component needs a value produced by an +Effect during its first render. The value is then cached for the component +instance. You can also use it to set up scoped component logic, subscriptions, +or resources that should live for the lifetime of that component instance. + +Use `Component.useOnChange` when render needs the value computed by +scoped work that depends on changing inputs. When a dependency changes, React +re-renders the component and the hook computes the next value during that +render. + +```tsx +import { Console, Effect } from "effect" +import { Component } from "effect-fc" + +const UserPanelView = Component.make("UserPanel")( + function* (props: { readonly userId: string }) { + const label = yield* Component.useOnChange( + () => + Effect.gen(function* () { + yield* Console.log(`Preparing view for ${props.userId}`) + yield* Effect.addFinalizer(() => + Console.log(`Cleaning up ${props.userId}`), + ) + + return `Viewing user ${props.userId}` + }), + [props.userId], + ) + + return

{label}

+ }, +) +``` + +In this example, each `userId` gets its own scope. When `userId` changes, +Effect-FC closes the previous scope, runs its finalizers, and creates a new +scope for the next load. Unlike `useOnMount`, `useOnChange` does not expose the +component's root scope directly. It creates and provides its own scope for that +dependency window. Some other Effect-FC hooks follow the same pattern when they +need a lifecycle that is narrower than the whole component instance. + +## Useful Effect-FC Hooks + +Unlike plain React hooks, Effect-FC hooks return Effects. Use `yield*` to run +them inside the component body. + +The most common Effect-FC hooks are: + +- `Component.useOnMount`: run an Effect once during the component's first render + after mount, and return its value. The Effect must be synchronous. + +```tsx +const initialData = yield* Component.useOnMount(() => loadInitialData) +``` + +- `Component.useOnChange`: when a dependency changes, React re-renders the + component and the Effect is run again inside the component body. It returns + the latest value, so the Effect must be synchronous too. + +```tsx +const label = yield* Component.useOnChange(() => formatUserLabel(id), [id]) +``` + +- `Component.useReactEffect`: Effect-powered `React.useEffect` for side effects + that do not need to compute render output or trigger a re-render. The Effect + must be synchronous and can register scoped finalizers. + +```tsx +yield* Component.useReactEffect( + () => Effect.forkScoped(subscribeToUser(id)), + [id], +) +``` + +- `Component.useReactLayoutEffect`: Effect-powered `React.useLayoutEffect` with scoped + finalizers. + +```tsx +yield* Component.useReactLayoutEffect(() => measure(ref), []) +``` + +- `Component.useRunSync` and `Component.useRunPromise`: run Effects from React + event handlers. + +```tsx +const runPromise = yield* Component.useRunPromise() + +return ( + +) +``` + +- `Component.useCallbackSync` and `Component.useCallbackPromise`: create stable + React callbacks. + +```tsx +const save = yield* Component.useCallbackPromise( + (user: User) => saveUser(user), + [], +) + +return +``` + +## Use React Normally + +An Effect-FC component is still a React function component. Anything you can do +in a regular React component can also be done in an Effect-FC component, +including React hooks, refs, event handlers, context, and JSX composition. + +```tsx +import { Component } from "effect-fc" +import * as React from "react" + +const CounterView = Component.make("Counter")(function* () { + const [count, setCount] = React.useState(0) + const buttonRef = React.useRef(null) + + return ( + + ) +}) +``` + +Use regular React hooks for local UI concerns, and reach for Effect-FC helpers +when the component needs Effect services, scopes, resources, or Effect-powered +callbacks. + +## Use Tags + +Components can yield Effect tags directly in the component body. There is no +need to memoize the service yourself; just yield the tag wherever the component +needs it. + +```tsx title="src/Greeting.tsx" +const GreetingView = Component.make("Greeting")(function* (props: { + readonly name: string +}) { + const greeting = yield* GreetingService + + return

{greeting.greet(props.name)}

+}) +``` + +Service values in the runtime context are reactive by default. If a provided +service instance changes, Effect-FC unmounts and mounts again the components +that depend on that context, so they read the new service and restart their +scoped lifecycle with the new environment. For services that should not trigger +that behavior, pass their tags with `Component.withOptions({ nonReactiveTags: +[...] })`. + +## Provide Services To A Subtree + +Use `Component.useContextFromLayer` when an Effect-FC component should provide +extra services to another Effect-FC component. It turns a `Layer` into a runtime +context that can be provided to `.use`. + +```tsx title="src/GreetingPageView.tsx" +import { Effect } from "effect" +import { Component } from "effect-fc" +import { GreetingView } from "./Greeting" +import { GreetingService } from "./services" + +const GreetingLive = GreetingService.Default({ + greet: (name: string) => `Welcome, ${name}`, +}) + +export const GreetingPageView = Component.make("GreetingPage")(function* () { + const context = yield* Component.useContextFromLayer(GreetingLive) + const Greeting = yield* Effect.provide(GreetingView.use, context) + + return +}) +``` + +The layer passed to `useContextFromLayer` should be stable. If a new layer value +is created on every render, Effect-FC has to build a new context, which can +cause unnecessary re-renders and scoped lifecycle restarts. Define static layers +outside the component, or memoize layers that depend on React props or state. + +Layers built with `useContextFromLayer` are scoped to the component that builds +them. That means service construction can register scoped logic, acquire +resources, fork scoped fibers, and add finalizers that are tied to that +component's lifecycle. + +## Where To Go Next + +Once the runtime and component boundary are in place, the rest of the library +builds on the same idea: + +- `Subscribable.useAll` reads Effect subscribables and rerenders when they + change. +- `Lens` connects React state and Effect `SubscriptionRef` values. +- `Query` and `Mutation` model async data and user-triggered operations. +- `Form`, `SubmittableForm`, and `SynchronizedForm` help build Effect-backed + forms. + +The important pattern is small and repeatable: write Effect-FC components inside +the runtime, then use `Component.withRuntime` at React boundaries. diff --git a/packages/docs/versioned_docs/version-effect-fc-v0/state-management.md b/packages/docs/versioned_docs/version-effect-fc-v0/state-management.md new file mode 100644 index 0000000..160bf96 --- /dev/null +++ b/packages/docs/versioned_docs/version-effect-fc-v0/state-management.md @@ -0,0 +1,245 @@ +--- +sidebar_position: 2 +title: State Management +--- + +# State Management + +`Lens` is the main type used for state management in `effect-fc`. + +A Lens is an effectful handle to a piece of state. It can read the current value, +subscribe to changes, and write updates back to the underlying source. A Lens +can point at a whole state object or focus on one nested field inside it. + +The usual pattern is to create state with Effect primitives such as +`SubscriptionRef`, turn that primitive into a Lens with a matching constructor +such as `Lens.fromSubscriptionRef`, and bind Lens values into components with +`Subscribable.useAll`. + +`Subscribable` is the read-only side of this model. Every Lens is also a +Subscribable. + +`effect-fc` re-exports the `Lens` and `Subscribable` modules from +[`effect-lens`](https://github.com/Thiladev/effect-lens) for convenience. The +core data model and transformation APIs belong to `effect-lens`, so check the +[`effect-lens` documentation](https://github.com/Thiladev/effect-lens/tree/master/packages/effect-lens) for the full Lens/Subscribable API. + +## Where To Store State + +State can live pretty much anywhere as a `Lens` or `Subscribable`: in a +service, in a layer, in a component scope, or alongside plain React state. Pick +the owner based on who needs the state. Once you have a Lens/Subscribable +handle, pass it around however you like, including through React props. + +If state is shared by multiple components or belongs to application logic, store +it in an Effect service: + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, Subscribable } from "effect-fc" + +class CounterState extends Effect.Service()("CounterState", { + effect: Effect.gen(function* () { + const count = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(0)) + + return { count } as const + }), +}) {} + +const CounterValueView = Component.make("CounterValue")(function* () { + const state = yield* CounterState + const [count] = yield* Subscribable.useAll([state.count]) + + return

Count: {count}

+}) +``` + +If state belongs to a single Effect-FC component instance, or to a shallow +hierarchy of subcomponents that receive it through props, create it with +`Component.useOnMount`: + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, Subscribable } from "effect-fc" + +const LocalCounterView = Component.make("LocalCounter")(function* () { + const state = yield* Component.useOnMount(() => + Effect.gen(function* () { + const count = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(0)) + + return { count } as const + }), + ) + const [count] = yield* Subscribable.useAll([state.count]) + + return

Count: {count}

+}) +``` + +For simple UI state that is not shared and does not need Effect integration, +prefer regular React state. A local "show details" toggle is usually better as +`React.useState(false)` than as a Lens. + +## Subscribable.useAll + +A `Subscribable
` is reactive state with a current value and a stream of +changes. Use `Subscribable.useAll` whenever a component needs to bind +subscribable values into render output. + +`Lens` is a `Subscribable`, so this is also the default way to read Lens values +from a component. + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, Subscribable } from "effect-fc" + +class CounterState extends Effect.Service()("CounterState", { + effect: Effect.gen(function* () { + const count = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(0)) + const doubled = Subscribable.map(count, (n) => n * 2) + + return { count, doubled } as const + }), +}) {} + +const CounterReadOnlyView = Component.make("CounterReadOnly")( + function* () { + const state = yield* CounterState + const [count, doubled] = yield* Subscribable.useAll([ + state.count, + state.doubled, + ]) + + return

Count: {count}, doubled: {doubled}

+ }, +) +``` + +`Subscribable.useAll` reads the current values during render and uses scoped subscriptions to update React state when changes arrive. + +When you need to modify state, write to the Lens with `Lens.set` or `Lens.update`: + +```tsx +const CounterControlsView = Component.make("CounterControls")( + function* () { + const state = yield* CounterState + const [count] = yield* Subscribable.useAll([state.count]) + + const increment = yield* Component.useCallbackSync( + () => Lens.update(state.count, (n) => n + 1), + [], + ) + const reset = yield* Component.useCallbackSync( + () => Lens.set(state.count, 0), + [], + ) + + return ( +
+

Count: {count}

+ + +
+ ) + }, +) +``` + +## Lens.useState + +`Lens.useState` is useful when React needs the familiar `[value, setValue]` +tuple, backed by a Lens. Reach for it when the JSX API expects a synchronous +setter, especially controlled inputs such as text fields, checkboxes, selects, +or third-party components with `value` / `onChange` props. + +If a component only needs to display the value, prefer `Subscribable.useAll`. +`Lens.useState` is for places where reading and writing need to be wired +together in React's local-state shape. + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens } from "effect-fc" + +class FormState extends Effect.Service()("FormState", { + effect: Effect.gen(function* () { + const name = Lens.fromSubscriptionRef(yield* SubscriptionRef.make("")) + + return { name } as const + }), +}) {} + +const NameInputView = Component.make("NameInput")(function* () { + const state = yield* FormState + const [name, setName] = yield* Lens.useState(state.name) + + return ( + setName(event.currentTarget.value)} + /> + ) +}) +``` + +`Lens.useState` returns the current value and a React-compatible setter. Calling +the setter writes through the Lens, so every other component subscribed to the +same Lens sees the update. + +## Focused Lenses + +Use focused Lenses when a component should work with one part of a larger state +object. A focused Lens is still a Lens, so it can be read with +`Subscribable.useAll` or used with `Lens.useState` when React needs a +read/write tuple. + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, Subscribable } from "effect-fc" + +interface UserProfile { + readonly name: string + readonly email: string + readonly role: string +} + +class ProfileState extends Effect.Service()("ProfileState", { + effect: Effect.gen(function* () { + const profile = Lens.fromSubscriptionRef( + yield* SubscriptionRef.make({ + name: "", + email: "", + role: "reader", + }), + ) + const name = Lens.focusObjectOn(profile, "name") + const role = Lens.focusObjectOn(profile, "role") + + return { profile, name, role } as const + }), +}) {} + +const ProfileNameView = Component.make("ProfileName")(function* () { + const state = yield* ProfileState + const [name, setName] = yield* Lens.useState(state.name) + const [role] = yield* Subscribable.useAll([state.role]) + + return ( + + ) +}) +``` + +Updating the focused `name` Lens through `Lens.useState` updates the parent +`profile` Lens. The focused `role` Lens is only read, so it stays on the simpler +`Subscribable.useAll` path. + +For focusing into nested state, deriving lenses, custom write behavior, and the +complete API, refer to the +[`effect-lens` documentation](https://github.com/Thiladev/effect-lens/tree/master/packages/effect-lens). diff --git a/packages/docs/versioned_sidebars/version-effect-fc-v0-sidebars.json b/packages/docs/versioned_sidebars/version-effect-fc-v0-sidebars.json new file mode 100644 index 0000000..068a564 --- /dev/null +++ b/packages/docs/versioned_sidebars/version-effect-fc-v0-sidebars.json @@ -0,0 +1,7 @@ +{ + "docsSidebar": [ + "getting-started", + "state-management", + "forms" + ] +} diff --git a/packages/docs/versions.json b/packages/docs/versions.json new file mode 100644 index 0000000..d4333ff --- /dev/null +++ b/packages/docs/versions.json @@ -0,0 +1,3 @@ +[ + "effect-fc-v0" +] diff --git a/packages/effect-fc-next/README.md b/packages/effect-fc-next/README.md new file mode 100644 index 0000000..7fc8b85 --- /dev/null +++ b/packages/effect-fc-next/README.md @@ -0,0 +1,145 @@ +

+ + Effect View logo + +

+ +

Effect View

+ +

+ Write React components as typed Effect programs. +

+ +

+ npm version + Effect View documentation + MIT license +

+ +

+ Read the documentation → +

+ +Effect View brings Effect's typed services, resource safety, concurrency, and +data modeling into React 19 without replacing React's component model. Yield +Effects and services from a component body, let scopes follow the React +lifecycle, and return ordinary JSX. + +> **Effect v4 beta:** Effect View is built for the Effect v4 beta release. If +> your application uses Effect v3, use the legacy +> [`effect-fc` package](https://www.npmjs.com/package/effect-fc) instead. + +```bash +npm install effect-view effect@beta react +``` + +Effect View does not depend on `react-dom`. Install the renderer used by your +application—for example, `react-dom` for the web: + +```bash +npm install react-dom +``` + +You can use Effect View with React Native or any other React renderer instead. + +## What it looks like + +An Effect View component is an Effect program that produces JSX. It can create +scoped state, access services, and use React-facing hooks without leaving the +generator model: + +```tsx +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens } from "effect-view" +import { runtime } from "./runtime" + +const CounterValueView = Component.make("CounterValue")( + function* ({ count }: { readonly count: Lens.Lens }) { + yield* Component.useOnMount(() => + Effect.addFinalizer(() => + Effect.log("CounterValue unmounted"), + ), + ) + + const [value, setValue] = yield* Lens.useState(count) + + return ( + + ) + }, +) + +const CounterView = Component.make("Counter")(function* () { + const count = yield* Component.useOnMount(() => + Effect.map( + SubscriptionRef.make(0), + Lens.fromSubscriptionRef, + ), + ) + + const CounterValue = yield* CounterValueView.use + + return +}) + +export const Counter = CounterView.pipe( + Component.withContext(runtime.context), +) +``` + +`CounterView` composes another Effect View component by yielding its `.use` +Effect, then renders the resulting component as ordinary JSX. The child can +access the current Effect context and receives its own component scope. + +`Effect.addFinalizer` uses the scope already provided to the component body, so +the finalizer above runs when `CounterValue` unmounts. + +At the outer boundary, `Counter` is still a normal React component and its Effect requirements remain +typed until they reach the runtime. + +[Build the runtime and render your first component →](https://thila.dev/effect-view/docs/getting-started) + +## Why Effect View + +| | Capability | What it gives you | +| --- | --- | --- | +| **Effect components** | `Component.make` | Yield Effects and typed services directly, then return JSX. | +| **Managed lifecycles** | `Scope.Scope` | Finalizers, fibers, subscriptions, and resources close with their component or dependency lifecycle. | +| **One application runtime** | `ReactRuntime` | Build your Layer once and make its services available throughout the UI. | +| **Reactive state** | `Lens` and `View` | Focus large state models into small writable values and subscribe only where React needs them. | +| **Server state** | `Query` and `Mutation` | TanStack Query-style caching, invalidation, staleness, and mutations with typed Effects underneath. | +| **Schema-driven forms** | `MutationForm` and `LensForm` | Keep input-friendly encoded values while application code receives validated, decoded types. | +| **Async rendering** | `Async` and `Memoized` | Integrate asynchronous Effects with Suspense while retaining Effect errors and cancellation. | + +## Designed for both ecosystems + +Effect View does not hide Effect behind callbacks or recreate React around a +new rendering model. React still owns rendering, JSX, hooks, Suspense, and +events. Effect owns services, errors, resource safety, concurrency, streams, +and schemas. Effect View provides the lifecycle-aware boundary between them. + +## Documentation + +The complete documentation is available at **[thila.dev/effect-view](https://thila.dev/effect-view)**. + +## Requirements + +- React 19.2 or newer +- **Effect v4 beta** (`effect@beta`) +- TypeScript and `@types/react` for TypeScript projects + +Effect View is renderer-independent and does not require `react-dom`. + +## Project status + +Effect View is currently beta software. The main APIs are available, but +breaking changes and rough edges are still possible before a stable release. + +Issues, ideas, and contributions are welcome on +[GitHub](https://github.com/Thiladev/effect-view). + +## License + +[MIT](https://github.com/Thiladev/effect-view/blob/main/LICENSE) diff --git a/packages/effect-fc-next/biome.json b/packages/effect-fc-next/biome.json new file mode 100644 index 0000000..41d707b --- /dev/null +++ b/packages/effect-fc-next/biome.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://biomejs.dev/schemas/latest/schema.json", + "root": false, + "extends": "//", + "files": { + "includes": ["./src/**"] + } +} diff --git a/packages/effect-fc-next/package.json b/packages/effect-fc-next/package.json new file mode 100644 index 0000000..c6f0226 --- /dev/null +++ b/packages/effect-fc-next/package.json @@ -0,0 +1,115 @@ +{ + "name": "effect-fc-next", + "description": "Write React function components with Effect", + "version": "0.1.0-beta.0", + "type": "module", + "files": [ + "./README.md", + "./dist" + ], + "license": "MIT", + "repository": { + "url": "git+https://github.com/Thiladev/effect-fc.git" + }, + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./Async": { + "types": "./dist/Async.d.ts", + "default": "./dist/Async.js" + }, + "./Component": { + "types": "./dist/Component.d.ts", + "default": "./dist/Component.js" + }, + "./Form": { + "types": "./dist/Form.d.ts", + "default": "./dist/Form.js" + }, + "./Lens": { + "types": "./dist/Lens.d.ts", + "default": "./dist/Lens.js" + }, + "./LensForm": { + "types": "./dist/LensForm.d.ts", + "default": "./dist/LensForm.js" + }, + "./Memoized": { + "types": "./dist/Memoized.d.ts", + "default": "./dist/Memoized.js" + }, + "./Mutation": { + "types": "./dist/Mutation.d.ts", + "default": "./dist/Mutation.js" + }, + "./MutationForm": { + "types": "./dist/MutationForm.d.ts", + "default": "./dist/MutationForm.js" + }, + "./PubSub": { + "types": "./dist/PubSub.d.ts", + "default": "./dist/PubSub.js" + }, + "./Query": { + "types": "./dist/Query.d.ts", + "default": "./dist/Query.js" + }, + "./QueryClient": { + "types": "./dist/QueryClient.d.ts", + "default": "./dist/QueryClient.js" + }, + "./ReactRuntime": { + "types": "./dist/ReactRuntime.d.ts", + "default": "./dist/ReactRuntime.js" + }, + "./Refreshable": { + "types": "./dist/Refreshable.d.ts", + "default": "./dist/Refreshable.js" + }, + "./ScopeRegistry": { + "types": "./dist/ScopeRegistry.d.ts", + "default": "./dist/ScopeRegistry.js" + }, + "./SetStateAction": { + "types": "./dist/SetStateAction.d.ts", + "default": "./dist/SetStateAction.js" + }, + "./Stream": { + "types": "./dist/Stream.d.ts", + "default": "./dist/Stream.js" + }, + "./View": { + "types": "./dist/View.d.ts", + "default": "./dist/View.js" + } + }, + "scripts": { + "lint:tsc": "tsc -b --noEmit", + "lint:biome": "biome lint", + "test": "vitest run", + "build": "tsc -b tsconfig.build.json", + "pack": "npm pack", + "clean:cache": "rm -rf .turbo *.tsbuildinfo", + "clean:dist": "rm -rf dist", + "clean:modules": "rm -rf node_modules" + }, + "devDependencies": { + "@effect/platform-browser": "4.0.0-beta.98", + "@testing-library/react": "^16.3.0", + "effect": "4.0.0-beta.98", + "jsdom": "^26.1.0", + "vitest": "^3.2.4" + }, + "peerDependencies": { + "@types/react": "^19.2.0", + "effect": "4.0.0-beta.98", + "react": "^19.2.0" + }, + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "effect-lens": "^2.0.0-beta.1" + } +} diff --git a/packages/effect-fc-next/src/Async.test.tsx b/packages/effect-fc-next/src/Async.test.tsx new file mode 100644 index 0000000..eb41758 --- /dev/null +++ b/packages/effect-fc-next/src/Async.test.tsx @@ -0,0 +1,63 @@ +import { act, fireEvent, render, screen } from "@testing-library/react" +import { Effect, Layer } from "effect" +import * as React from "react" +import { describe, expect, it, vi } from "vitest" +import * as Async from "./Async.js" +import * as Component from "./Component.js" +import * as Memoized from "./Memoized.js" +import * as ReactRuntime from "./ReactRuntime.js" + +describe("Async", () => { + it("does not rerun for an unrelated parent state update", async () => { + const load = vi.fn((_id: number) => Effect.never) + const renderPost = vi.fn() + const runtime = ReactRuntime.make(Layer.empty) + const context = await runtime.runtime.context() + + const Post = Component.make("Post")(function*(props: { readonly id: number }) { + renderPost() + const value = yield* Component.useOnChange(() => load(props.id), [props.id]) + return
{value}
+ }).pipe( + Async.async, + Memoized.memoized, + ) + + const Parent = Component.make("Parent")(function*() { + const [text, setText] = React.useState("") + const AsyncPost = yield* Post.use + + return <> + setText(event.currentTarget.value)} + /> + loading} /> + + }).pipe(Component.withContext(runtime.context)) + + let view!: ReturnType + await act(async () => { + view = render( + + + , + ) + }) + + expect(screen.getByText("loading")).toBeTruthy() + expect(load).toHaveBeenCalledTimes(2) + const callsAfterLoad = load.mock.calls.length + const rendersAfterLoad = renderPost.mock.calls.length + + await act(async () => { + fireEvent.change(screen.getByLabelText("text"), { target: { value: "a" } }) + }) + expect(load).toHaveBeenCalledTimes(callsAfterLoad) + expect(renderPost).toHaveBeenCalledTimes(rendersAfterLoad) + + view.unmount() + await runtime.runtime.dispose() + }) +}) diff --git a/packages/effect-fc-next/src/Async.ts b/packages/effect-fc-next/src/Async.ts new file mode 100644 index 0000000..bf4661f --- /dev/null +++ b/packages/effect-fc-next/src/Async.ts @@ -0,0 +1,171 @@ +/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ +import { type Context, Effect, type Equivalence, Function, Predicate, Scope } from "effect" +import * as React from "react" +import * as Component from "./Component.js" + + +export const AsyncTypeId: unique symbol = Symbol.for("@effect-fc/Async/Async") +export type AsyncTypeId = typeof AsyncTypeId + + +/** + * A trait for `Component`'s that allows them running asynchronous effects. + */ +export interface Async extends AsyncPrototype, AsyncOptions {} + +export interface AsyncPrototype { + readonly [AsyncTypeId]: AsyncTypeId +} + +/** + * Configuration options for `Async` components. + */ +export interface AsyncOptions { + /** + * The default fallback React node to display while the async operation is pending. + * Used if no fallback is provided to the component when rendering. + */ + readonly defaultFallback?: React.ReactNode +} + +/** + * Props for `Async` components. + */ +export type AsyncProps = Omit + + +export const AsyncPrototype: AsyncPrototype = Object.freeze({ + [AsyncTypeId]: AsyncTypeId, + + makeFunctionComponent

( + this: Component.Component & Async, + contextRef: React.RefObject>>, + ) { + const Inner = (props: { readonly promise: Promise }) => React.use(props.promise) + + return ({ fallback, name, ...props }: AsyncProps) => { + const promise = Effect.runPromiseWith(contextRef.current)( + Effect.flatMap( + Component.useScope([], this), + scope => Effect.provideService(this.body(props as P), Scope.Scope, scope), + ) + ) + + return React.createElement( + React.Suspense, + { fallback: fallback ?? this.defaultFallback, name }, + React.createElement(Inner, { promise }), + ) + } + }, +} as const) + +/** + * An equivalence function for comparing `AsyncProps` that ignores the `fallback` property. + * Used by default by async components with `Memoized.memoized` applied. + */ +export const defaultPropsEquivalence: Equivalence.Equivalence = ( + self: Record, + that: Record, +) => { + if (self === that) + return true + + for (const key in self) { + if (key === "fallback") + continue + if (!(key in that) || !Object.is(self[key], that[key])) + return false + } + + for (const key in that) { + if (key === "fallback") + continue + if (!(key in self)) + return false + } + + return true +} + + +export const isAsync = (u: unknown): u is Async => Predicate.hasProperty(u, AsyncTypeId) + +/** + * Converts a Component into an `Async` component that supports running asynchronous effects. + * + * Note: The component cannot have a prop named "promise" as it's reserved for internal use. + * + * @param self - The component to convert to an Async component + * @returns A new `Async` component with the same body, error, and context types as the input + * + * @example + * ```ts + * const MyAsyncComponent = MyComponent.pipe( + * Async.async, + * ) + * ``` + */ +export const async = ( + self: T & ( + "promise" extends keyof Component.Component.Props + ? "The 'promise' prop name is restricted for Async components. Please rename the 'promise' prop to something else." + : T + ) +): ( + & Omit> + & Component.Component< + Component.Component.Props & AsyncProps, + Component.Component.Success, + Component.Component.Error, + Component.Component.Context, + Component.Component.DefaultSignature & AsyncProps, Component.Component.Success> + > + & Async +) => Object.setPrototypeOf( + Object.assign(function() {}, self, { propsEquivalence: defaultPropsEquivalence }), + Object.freeze(Object.setPrototypeOf( + Object.assign({}, AsyncPrototype), + Object.getPrototypeOf(self), + )), +) + +/** + * Applies options to an Async component, returning a new Async component with the updated configuration. + * + * Supports both curried and uncurried application styles. + * + * @param self - The Async component to apply options to (in uncurried form) + * @param options - The options to apply to the component + * @returns An Async component with the applied options + * + * @example + * ```ts + * // Curried + * const MyAsyncComponent = MyComponent.pipe( + * Async.async, + * Async.withOptions({ defaultFallback:

Loading...

}), + * ) + * + * // Uncurried + * const MyAsyncComponent = Async.withOptions( + * Async.async(MyComponent), + * { defaultFallback:

Loading...

}, + * ) + * ``` + */ +export const withOptions: { + ( + options: Partial + ): (self: T) => T + ( + self: T, + options: Partial, + ): T +} = Function.dual(2, ( + self: T, + options: Partial, +): T => Object.setPrototypeOf( + Object.assign(function() {}, self, options), + Object.getPrototypeOf(self), +)) diff --git a/packages/effect-fc-next/src/Component.test.tsx b/packages/effect-fc-next/src/Component.test.tsx new file mode 100644 index 0000000..69d0063 --- /dev/null +++ b/packages/effect-fc-next/src/Component.test.tsx @@ -0,0 +1,571 @@ +import { act, fireEvent, render, screen, waitFor } from "@testing-library/react" +import { Context, Effect, HashMap, Layer, SubscriptionRef } from "effect" +import * as React from "react" +import { afterEach, describe, expect, it, vi } from "vitest" +import * as Component from "./Component.js" +import * as ReactRuntime from "./ReactRuntime.js" +import * as Refreshable from "./Refreshable.js" +import * as ScopeRegistry from "./ScopeRegistry.js" + + +class ValueService extends Context.Service()("ValueService") {} + +afterEach(() => { + vi.useRealTimers() +}) + +describe("Component", () => { + it("does not rerun useOnMount across rerenders after Strict Mode initialization", async () => { + const onMount = vi.fn(() => Effect.succeed("mounted")) + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + + const Probe = Component.makeUntraced("UseOnMountProbe")(function*() { + const value = yield* Component.useOnMount(onMount) + return
{value}
+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("mounted") + expect(onMount).toHaveBeenCalledTimes(2) + + view.rerender( + + + + ) + expect(await screen.findByText("mounted")).toBeTruthy() + expect(onMount).toHaveBeenCalledTimes(2) + + view.unmount() + await runtime.runtime.dispose() + }) + + it("recomputes useOnChange only when dependencies change", async () => { + const onChange = vi.fn((value: number) => Effect.succeed(`value:${value}`)) + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + + const Probe = Component.makeUntraced("UseOnChangeProbe")(function*(props: { readonly value: number }) { + const result = yield* Component.useOnChange(() => onChange(props.value), [props.value], { + finalizerExecutionDebounce: 0, + }) + + return
{result}
+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("value:1") + expect(onChange).toHaveBeenCalledTimes(2) + + view.rerender( + + + + ) + + expect(await screen.findByText("value:1")).toBeTruthy() + expect(onChange).toHaveBeenCalledTimes(2) + + view.rerender( + + + + ) + + await screen.findByText("value:2") + expect(onChange).toHaveBeenCalledTimes(4) + + view.unmount() + await runtime.runtime.dispose() + }) + + it("closes the previous scope on dependency changes and unmount", async () => { + const cleanup = vi.fn() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + + const Probe = Component.makeUntraced("ScopeCleanupProbe")(function*(props: { readonly value: string }) { + const result = yield* Component.useOnChange( + () => Effect.gen(function*() { + yield* Effect.addFinalizer(() => Effect.sync(() => cleanup(props.value))) + return props.value + }), + [props.value], + { finalizerExecutionDebounce: 0 }, + ) + + return
{result}
+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + expect(cleanup).not.toHaveBeenCalled() + + view.rerender( + + + + ) + + await screen.findByText("second") + await waitFor(() => expect(cleanup).toHaveBeenCalledWith("first")) + expect(cleanup).toHaveBeenCalledTimes(1) + + view.unmount() + + await waitFor(() => expect(cleanup).toHaveBeenCalledWith("second")) + expect(cleanup).toHaveBeenCalledTimes(2) + await runtime.runtime.dispose() + }) + + it("runs useReactEffect setup and cleanup when dependencies change", async () => { + const lifecycle = vi.fn<(message: string) => void>() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + + const Probe = Component.makeUntraced("UseReactEffectProbe")(function*(props: { readonly value: string }) { + yield* Component.useReactEffect(() => + Effect.gen(function*() { + yield* Effect.sync(() => lifecycle(`mount:${props.value}`)) + yield* Effect.addFinalizer(() => Effect.sync(() => lifecycle(`cleanup:${props.value}`))) + }), + [props.value]) + + return
{props.value}
+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + await waitFor(() => expect(lifecycle).toHaveBeenCalledWith("mount:first")) + + view.rerender( + + + + ) + + await screen.findByText("second") + await waitFor(() => expect(lifecycle).toHaveBeenCalledWith("cleanup:first")) + await waitFor(() => expect(lifecycle).toHaveBeenCalledWith("mount:second")) + + view.unmount() + + await waitFor(() => expect(lifecycle).toHaveBeenCalledWith("cleanup:second")) + expect(lifecycle.mock.calls.map(([message]) => message)).toEqual([ + "mount:first", + "cleanup:first", + "mount:first", + "cleanup:first", + "mount:second", + "cleanup:second", + ]) + await runtime.runtime.dispose() + }) + + it("keeps useCallbackSync stable until dependencies change", async () => { + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + const seenCallbacks: Array<(value: number) => string> = [] + + const Probe = Component.makeUntraced("UseCallbackSyncProbe")(function*(props: { readonly prefix: string }) { + const callback = yield* Component.useCallbackSync( + (value: number) => Effect.succeed(`${props.prefix}:${value}`), + [props.prefix], + ) + + yield* Component.useOnMount(() => Effect.sync(() => { + seenCallbacks.push(callback) + })) + + React.useEffect(() => { + seenCallbacks.push(callback) + }, [callback]) + + return
{callback(1)}
+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("a:1") + const initialLength = seenCallbacks.length + const initialCallback = seenCallbacks.at(-1) + expect(initialCallback?.(2)).toBe("a:2") + + view.rerender( + + + + ) + + await screen.findByText("a:1") + expect(seenCallbacks).toHaveLength(initialLength) + + view.rerender( + + + + ) + + await screen.findByText("b:1") + await waitFor(() => expect(seenCallbacks.length).toBeGreaterThan(initialLength)) + expect(seenCallbacks.at(-1)).not.toBe(initialCallback) + expect(seenCallbacks.at(-1)?.(2)).toBe("b:2") + + view.unmount() + await runtime.runtime.dispose() + }) + + it("delays cleanup according to finalizerExecutionDebounce", async () => { + const cleanup = vi.fn() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + + const Probe = Component.makeUntraced("DebouncedCleanupProbe")(function*(props: { readonly value: string }) { + const result = yield* Component.useOnChange( + () => Effect.gen(function*() { + yield* Effect.addFinalizer(() => Effect.sync(() => cleanup(props.value))) + return props.value + }), + [props.value], + { finalizerExecutionDebounce: "20 millis" }, + ) + + return
{result}
+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + + view.rerender( + + + + ) + + await screen.findByText("second") + expect(cleanup).not.toHaveBeenCalled() + + await new Promise(resolve => setTimeout(resolve, 5)) + expect(cleanup).not.toHaveBeenCalled() + + await waitFor(() => expect(cleanup).toHaveBeenCalledWith("first"), { timeout: 100 }) + + view.unmount() + await waitFor(() => expect(cleanup).toHaveBeenCalledWith("second"), { timeout: 100 }) + await runtime.runtime.dispose() + }) + + it("does not remount a component when only nonReactiveTags change", async () => { + const mounts = vi.fn() + const unmounts = vi.fn() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + + const SubComponent = Component.makeUntraced("NonReactiveSubComponent")(function*() { + const service = yield* ValueService + const [count, setCount] = React.useState(0) + + yield* Component.useOnMount(() => Effect.gen(function*() { + yield* Effect.sync(() => mounts()) + yield* Effect.addFinalizer(() => Effect.sync(() => unmounts())) + })) + + return + }).pipe( + Component.withOptions({ + nonReactiveTags: [...Component.defaultOptions.nonReactiveTags, ValueService], + }) + ) + + const Parent = Component.makeUntraced("NonReactiveParent")(function*(props: { readonly value: string }) { + const serviceLayer = React.useMemo( + () => Layer.succeed(ValueService, { value: props.value }), + [props.value], + ) + const context = yield* Component.useLayer(serviceLayer, { + finalizerExecutionDebounce: 0, + }) + const Child = yield* Effect.provide(SubComponent.use, context) + + return + }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first:0") + const initialMounts = mounts.mock.calls.length + expect(initialMounts).toBeGreaterThan(0) + expect(unmounts).not.toHaveBeenCalled() + + fireEvent.click(screen.getByRole("button", { name: "first:0" })) + await screen.findByText("first:1") + + view.rerender( + + + + ) + + await screen.findByText("second:1") + expect(mounts).toHaveBeenCalledTimes(initialMounts) + expect(unmounts).not.toHaveBeenCalled() + + view.unmount() + await waitFor(() => expect(unmounts).toHaveBeenCalledTimes(1)) + await runtime.runtime.dispose() + }) + + it("does not commit effects or retain registered scopes for a discarded Suspense render", async () => { + const setup = vi.fn() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + const scopeRegistry = Context.get(effectRuntime, ScopeRegistry.ScopeRegistry) + const pending = new Promise(() => {}) + + const Probe = Component.makeUntraced("DiscardedSuspenseProbe")(function*() { + yield* Component.useReactEffect(() => Effect.sync(setup), []) + React.use(pending) + return
committed
+ }).pipe( + Component.withOptions({ scopeCommitTimeout: "10 millis" }), + Component.withContext(runtime.context) + ) + + let view!: ReturnType + await act(async () => { + view = render( + fallback}> + + + + + ) + }) + + try { + await screen.findByText("fallback") + expect(setup).not.toHaveBeenCalled() + await waitFor(() => expect(HashMap.size(Effect.runSync(SubscriptionRef.get(scopeRegistry.ref)))).toBe(0)) + } + finally { + view.unmount() + await runtime.runtime.dispose() + } + }) + + it("keeps committed scopes alive without heartbeats", async () => { + const acquisitions = vi.fn() + const releases = vi.fn() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + const scopeRegistry = Context.get(effectRuntime, ScopeRegistry.ScopeRegistry) + + const Probe = Component.makeUntraced("CommittedScopeProbe")(function*() { + yield* Component.useOnMount(() => Effect.gen(function*() { + yield* Effect.sync(acquisitions) + yield* Effect.addFinalizer(() => Effect.sync(releases)) + })) + + return
committed
+ }).pipe( + Component.withOptions({ + finalizerExecutionDebounce: "10 millis", + scopeCommitTimeout: "10 millis", + }), + Component.withContext(runtime.context), + ) + + const view = render( + + + + ) + + await screen.findByText("committed") + await waitFor(() => expect(releases).toHaveBeenCalledTimes(acquisitions.mock.calls.length - 1)) + await new Promise(resolve => setTimeout(resolve, 30)) + + expect(HashMap.size(Effect.runSync(SubscriptionRef.get(scopeRegistry.ref)))).toBe(1) + expect(releases).toHaveBeenCalledTimes(acquisitions.mock.calls.length - 1) + + view.unmount() + await waitFor(() => expect(releases).toHaveBeenCalledTimes(acquisitions.mock.calls.length)) + await waitFor(() => expect(HashMap.size(Effect.runSync(SubscriptionRef.get(scopeRegistry.ref)))).toBe(0)) + await runtime.runtime.dispose() + }) + + it("does not expire a scope while a descendant is suspended past the finalizer debounce", async () => { + const runtime = ReactRuntime.make(Layer.empty) + let resolve!: () => void + const pending = new Promise(complete => { + resolve = complete + }) + + const Suspended = () => { + React.use(pending) + return
committed
+ } + + let view!: ReturnType + await act(async () => { + view = render( + fallback}> + + + ) + }) + + try { + await screen.findByText("fallback") + await new Promise(resolve => setTimeout(resolve, 150)) + await act(async () => { + resolve() + await pending + }) + await screen.findByText("committed") + } + finally { + view.unmount() + await runtime.runtime.dispose() + } + }) + + it("clears ScopeRegistry after a suspended render retries, commits, and unmounts", async () => { + const lifecycle = vi.fn<(message: string) => void>() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + const scopeRegistry = Context.get(effectRuntime, ScopeRegistry.ScopeRegistry) + let resolve!: () => void + const pending = new Promise(complete => { + resolve = complete + }) + + const Probe = Component.makeUntraced("RetriedSuspenseProbe")(function*() { + React.use(pending) + yield* Component.useReactEffect(() => Effect.gen(function*() { + yield* Effect.sync(() => lifecycle("mount")) + yield* Effect.addFinalizer(() => Effect.sync(() => lifecycle("cleanup"))) + }), []) + return
committed
+ }).pipe( + Component.withOptions({ scopeCommitTimeout: "10 millis" }), + Component.withContext(runtime.context) + ) + + let view!: ReturnType + await act(async () => { + view = render( + fallback}> + + + + + ) + }) + + try { + await screen.findByText("fallback") + await act(async () => { + resolve() + await pending + }) + await screen.findByText("committed") + await waitFor(() => expect(lifecycle).toHaveBeenCalledWith("mount")) + + view.unmount() + await waitFor(() => expect(HashMap.size(Effect.runSync(SubscriptionRef.get(scopeRegistry.ref)))).toBe(0)) + expect(lifecycle.mock.calls.filter(([message]) => message === "mount")).toHaveLength(2) + expect(lifecycle.mock.calls.filter(([message]) => message === "cleanup")).toHaveLength(2) + } + finally { + view.unmount() + await runtime.runtime.dispose() + } + }) + + it("refreshes a registered body while preserving or resetting local state", async () => { + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + + const makeProbe = (label: string) => Component.makeUntraced("RefreshProbe")(function*() { + const [count, setCount] = React.useState(0) + return + }) + const original = makeProbe("old") + const cell = Refreshable.makeCell(original, "hooks", false) + Refreshable.attach(original, cell) + + const Probe = Component.withContext(original, runtime.context) + const view = render( + + + + ) + + fireEvent.click(await screen.findByRole("button")) + expect(screen.getByRole("button").textContent).toBe("old:1") + + await act(async () => { + cell.update(makeProbe("compatible"), "hooks", false) + await Promise.resolve() + }) + expect(screen.getByRole("button").textContent).toBe("compatible:1") + + await act(async () => { + cell.update(makeProbe("reset"), "changed-hooks", false) + await Promise.resolve() + }) + expect(screen.getByRole("button").textContent).toBe("reset:0") + + view.unmount() + await runtime.runtime.dispose() + }) +}) diff --git a/packages/effect-fc-next/src/Component.ts b/packages/effect-fc-next/src/Component.ts new file mode 100644 index 0000000..6325f16 --- /dev/null +++ b/packages/effect-fc-next/src/Component.ts @@ -0,0 +1,1119 @@ +/** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */ +/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ +import { Context, type Duration, Effect, Equivalence, Exit, Function, identity, Layer, Pipeable, Predicate, References, Scheduler, Scope, Tracer } from "effect" +import * as React from "react" +import * as ScopeRegistry from "./ScopeRegistry.js" + + +export const ComponentTypeId: unique symbol = Symbol.for("@effect-fc/Component/Component") +export type ComponentTypeId = typeof ComponentTypeId + +/** + * Represents an Effect-based React Component that integrates the Effect system with React. + */ +export interface Component

+extends ComponentPrototype, ComponentOptions { + new(_: never): Record + readonly [ComponentTypeId]: ComponentTypeId + readonly "~Props": P + readonly "~Success": A + readonly "~Error": E + readonly "~Context": R + readonly "~Function": F + + readonly body: (props: P) => Effect.Effect +} + +export declare namespace Component { + export type Default

= Component> + export type Any = Component + + export type Signature = (props: any) => React.ReactNode + export type DefaultSignature

= (props: P) => A + + export type Props = [T] extends [Component] ? P : never + export type Success = [T] extends [Component] ? A : never + export type Error = [T] extends [Component] ? E : never + export type Context = [T] extends [Component] ? R : never + export type Function = [T] extends [Component] ? F : never + + export type AsComponent = Component, Success, Error, Context, Function> +} + + +export interface ComponentImpl

+extends Component, ComponentImplPrototype {} + +export declare namespace ComponentImpl { + export type Any = ComponentImpl +} + +export interface ComponentImplPrototype { + readonly use: Effect.Effect> + + asFunctionComponent(contextRef: React.Ref>>): F + makeFunctionComponent(contextRef: React.Ref>>): F + setFunctionComponentName(f: F): void + transformFunctionComponent(f: F): F +} + +export const ComponentImplPrototype: ComponentImplPrototype = Object.freeze({ + get use() { return use(this) }, + + makeFunctionComponent

( + this: ComponentImpl, + contextRef: React.RefObject>>, + ) { + return (props: P) => Effect.runSyncWith(contextRef.current)( + Effect.flatMap( + useScope([], this), + scope => Effect.provideService(this.body(props), Scope.Scope, scope), + ) + ) + }, + + asFunctionComponent

( + this: ComponentImpl, + contextRef: React.RefObject>>, + ) { + return this.makeFunctionComponent(contextRef) + }, + + setFunctionComponentName

( + this: ComponentImpl, + f: React.FC

, + ) { + f.displayName = this.displayName ?? "Anonymous" + }, + + transformFunctionComponent: identity, +} as const) + +const use = Effect.fnUntraced(function*

( + self: ComponentImpl +) { + // biome-ignore lint/style/noNonNullAssertion: React ref initialization + const contextRef = React.useRef>>(null!) + contextRef.current = yield* Effect.context>() + + const componentRef = React.useRef(null) + const previousServicesRef = React.useRef(null) + + const services = Array.from( + Context.omit(...self.nonReactiveTags)(contextRef.current).mapUnsafe.values() + ) + + if ( + !componentRef.current || + !previousServicesRef.current || + services.length !== previousServicesRef.current.length || + !Equivalence.Array(Equivalence.strictEqual())(services, previousServicesRef.current) + ) { + previousServicesRef.current = services + const f = self.asFunctionComponent(contextRef) + self.setFunctionComponentName(f) + componentRef.current = self.transformFunctionComponent(f) + } + + return componentRef.current +}) + + +export interface ComponentPrototype +extends Pipeable.Pipeable { + readonly [ComponentTypeId]: ComponentTypeId + readonly use: Effect.Effect> +} + +export const ComponentPrototype: ComponentPrototype = Object.freeze( + Object.defineProperties( + { + [ComponentTypeId]: ComponentTypeId, + ...Pipeable.Prototype, + }, + Object.getOwnPropertyDescriptors(ComponentImplPrototype), + ) as ComponentPrototype +) + + +export interface ComponentOptions { + /** + * Custom display name for the component in React DevTools and debugging utilities. + */ + readonly displayName?: string + + /** + * Context tags that should not trigger component remount when their values change. + * + * @default [Tracer.ParentSpan, References.CurrentStackFrame, Scheduler.Scheduler, Layer.CurrentMemoMap, Scope.Scope] + */ + readonly nonReactiveTags: readonly Context.Key[] + + /** + * Specifies the execution strategy for finalizers when the component unmounts or its scope closes. + * Determines whether finalizers execute sequentially or in parallel. + * + * @default "sequential" + */ + readonly finalizerExecutionStrategy: "sequential" | "parallel" + + /** + * Debounce duration before executing finalizers after component unmount. + * Prevents unnecessary cleanup work during rapid remount/unmount cycles, + * which is common in development and certain UI patterns. + * + * @default "100 millis" + */ + readonly finalizerExecutionDebounce: Duration.Input + + /** + * Maximum duration an uncommitted scope may remain registered before it is considered abandoned. + * + * @default "30 seconds" + */ + readonly scopeCommitTimeout: Duration.Input +} + +export const defaultOptions: ComponentOptions = { + nonReactiveTags: [ + Tracer.ParentSpan, + References.CurrentStackFrame, + Scheduler.Scheduler, + Layer.CurrentMemoMap, + Scope.Scope, + ], + finalizerExecutionStrategy: "sequential", + finalizerExecutionDebounce: "100 millis", + scopeCommitTimeout: "1 minute", +} + + +export const isComponent = (u: unknown): u is Component.Default<{}, React.ReactNode, unknown, unknown> => Predicate.hasProperty(u, ComponentTypeId) + +export declare namespace make { + export type Gen = { + , A extends React.ReactNode, P extends {} = {}>( + body: (props: P) => Generator + ): Component.Default< + P, A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + > + , A, B extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + >, + props: NoInfer

, + ) => B, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, F extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, F, G extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, F, G, H extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, F, G, H, I extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + h: (_: H, props: NoInfer

) => I, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, F, G, H, I, J extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Effect.Effect] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + h: (_: H, props: NoInfer

) => I, + i: (_: I, props: NoInfer

) => J, + ): Component.Default, Effect.Error, Effect.Services> + } + + export type NonGen = { + , P extends {} = {}>( + body: (props: P) => Eff + ): Component.Default, Effect.Error, Effect.Services> + , A, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => Eff, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => Eff, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => Eff, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => Eff, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => Eff, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, F, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => Eff, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, F, G, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => Eff, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, F, G, H, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + h: (_: H, props: NoInfer

) => Eff, + ): Component.Default, Effect.Error, Effect.Services> + , A, B, C, D, E, F, G, H, I, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + h: (_: H, props: NoInfer

) => I, + i: (_: I, props: NoInfer

) => Eff, + ): Component.Default, Effect.Error, Effect.Services> + } +} + +/** + * Creates an Effect-FC Component using the same overloads and pipeline composition style as `Effect.fn`. + * + * This is the **recommended** approach for defining Effect-FC components. It provides comprehensive + * support for multiple component definition patterns: + * + * - **Generator syntax** (yield* style): Most ergonomic and readable approach for sequential operations + * - **Direct Effect return**: For simple components that return an Effect directly + * - **Chained transformation functions**: Enables Effect.fn-style pipelines for composable transformations + * - **Automatic tracing**: Optional tracing span creation with automatic `displayName` assignment + * + * When a `spanName` string is provided, the following occurs automatically: + * 1. A distributed tracing span is created with the specified name + * 2. The resulting React component receives `displayName = spanName` for DevTools visibility + * + * @example + * ```tsx + * const MyComponent = Component.make("MyComponent")(function* (props: { count: number }) { + * const value = yield* someEffect + * return

{value}
+ * }) + * ``` + * + * @example As an opaque type using class syntax + * ```tsx + * class MyComponent extends Component.make("MyComponent")(function* (props: { count: number }) { + * const value = yield* someEffect + * return
{value}
+ * }) {} + * ``` + * + * @example Without name + * ```tsx + * class MyComponent extends Component.make(function* (props: { count: number }) { + * const value = yield* someEffect + * return
{value}
+ * }) {} + * ``` + * + * @example Using pipeline + * ```tsx + * class MyComponent extends Component.make("MyComponent")( + * (props: { count: number }) => someEffect, + * Effect.map(value =>
{value}
), + * ) {} + * ``` + */ +export const make: ( + & make.Gen + & make.NonGen + & (( + spanName: string, + spanOptions?: Tracer.SpanOptions, + ) => make.Gen & make.NonGen) +) = (spanNameOrBody: Function | string, ...pipeables: any[]): any => { + if (typeof spanNameOrBody !== "string") { + return Object.setPrototypeOf( + Object.assign(function() {}, defaultOptions, { + body: Effect.fn(spanNameOrBody as any, ...pipeables), + }), + ComponentPrototype, + ) + } + else { + const spanOptions = pipeables[0] + return (body: any, ...pipeables: any[]) => Object.setPrototypeOf( + Object.assign(function() {}, defaultOptions, { + body: Effect.fn(spanNameOrBody, spanOptions)(body, ...pipeables as []), + displayName: spanNameOrBody, + }), + ComponentPrototype, + ) + } +} + +/** + * Creates an Effect-FC Component without automatic distributed tracing. + * + * This function provides the same API surface as `make`, but does not create automatic tracing spans. + * It follows the exact same overload structure as `Effect.fnUntraced`. + * + * Use this variant when you need: + * - Full manual control over tracing instrumentation + * - To reduce tracing overhead in deeply nested component hierarchies + * - To avoid span noise in performance-sensitive applications + * + * When a `spanName` string is provided, it is used **exclusively** as the React component's + * `displayName` for DevTools identification. No tracing span is created. + * + * @example + * ```tsx + * const MyComponent = Component.makeUntraced("MyComponent")(function* (props: { count: number }) { + * const value = yield* someEffect + * return
{value}
+ * }) + * ``` + * + * @example As an opaque type using class syntax + * ```tsx + * class MyComponent extends Component.makeUntraced("MyComponent")(function* (props: { count: number }) { + * const value = yield* someEffect + * return
{value}
+ * }) {} + * ``` + * + * @example Without name + * ```tsx + * class MyComponent extends Component.makeUntraced(function* (props: { count: number }) { + * const value = yield* someEffect + * return
{value}
+ * }) {} + * ``` + * + * @example Using pipeline + * ```tsx + * class MyComponent extends Component.makeUntraced("MyComponent")( + * (props: { count: number }) => someEffect, + * Effect.map(value =>
{value}
), + * ) {} + * ``` + */ +export const makeUntraced: ( + & make.Gen + & make.NonGen + & ((name: string) => make.Gen & make.NonGen) +) = (spanNameOrBody: Function | string, ...pipeables: any[]): any => ( + typeof spanNameOrBody !== "string" + ? Object.setPrototypeOf( + Object.assign(function() {}, defaultOptions, { + body: Effect.fnUntraced(spanNameOrBody as any, ...pipeables as []), + }), + ComponentPrototype, + ) + : (body: any, ...pipeables: any[]) => Object.setPrototypeOf( + Object.assign(function() {}, defaultOptions, { + body: Effect.fnUntraced(body, ...pipeables as []), + displayName: spanNameOrBody, + }), + ComponentPrototype, + ) +) + +export declare namespace withSignature { + export type Result = ( + & Omit> + & Component, Component.Success, Component.Error, Component.Context, F> + ) +} + +export const withSignature: { + (): ( + self: T + ) => withSignature.Result + ( + self: T + ): withSignature.Result +} = (self?: Component.Any): any => self === undefined + ? identity + : self + +/** + * Creates a new component with modified configuration options while preserving all original behavior. + * + * This function allows you to customize component-level options such as finalizer execution strategy + * and debounce timing. + * + * @example + * ```tsx + * const MyComponentWithCustomOptions = MyComponent.pipe( + * Component.withOptions({ + * finalizerExecutionStrategy: ExecutionStrategy.parallel, + * finalizerExecutionDebounce: "50 millis", + * }) + * ) + * ``` + */ +export const withOptions: { + ( + options: Partial + ): (self: T) => T + ( + self: T, + options: Partial, + ): T +} = Function.dual(2, ( + self: T, + options: Partial, +): T => Object.setPrototypeOf( + Object.assign(function() {}, self, options), + Object.getPrototypeOf(self), +)) + +/** + * Wraps an Effect-FC Component and converts it into a standard React function component, + * serving as an **entrypoint** into an Effect-FC component hierarchy. + * + * This is how Effect-FC components are integrated with the broader React ecosystem, + * particularly when: + * - Using client-side routers (TanStack Router, React Router, etc.) + * - Implementing lazy-loaded or code-split routes + * - Connecting to third-party libraries expecting standard React components + * - Creating component boundaries between Effect-FC and non-Effect-FC code + * + * The Effect runtime is obtained from the provided React Context. + * + * @param self - The Effect-FC Component to be rendered as a standard React component + * @param context - React Context providing the Effect Runtime for this component tree. + * Create this using the `ReactRuntime` module. + * + * @example Integration with TanStack Router + * ```tsx + * // Application root + * export const runtime = ReactRuntime.make(Layer.empty) + * + * function App() { + * return ( + * + * + * + * ) + * } + * + * // Route definition + * export const Route = createFileRoute("/")({ + * component: Component.withContext(HomePage, runtime.context) + * }) + * ``` + * + */ +export const withContext: { +

( + context: React.Context>, + ): (self: Component, F>) => F +

( + self: Component, F>, + context: React.Context>, + ): F +} = Function.dual(2,

( + self: Component, + context: React.Context>, +) => function WithContext(props: P) { + return React.createElement( + Effect.runSyncWith(React.useContext(context))(self.use), + props, + ) +}) + + +export declare namespace useScope { + export interface Options { + readonly finalizerExecutionStrategy?: "sequential" | "parallel" + readonly finalizerExecutionDebounce?: Duration.Input + readonly scopeCommitTimeout?: Duration.Input + } +} + +/** + * Effect hook that creates and manages a `Scope` for the current component instance. + * + * This hook establishes a new scope that is automatically closed when: + * - The component unmounts + * - The dependency array `deps` changes + * + * The scope provides a resource management boundary for any Effects executed within the component, + * ensuring proper cleanup of resources and execution of finalizers. + * + * @param deps - Dependency array following React.useEffect semantics. The scope is recreated + * whenever any dependency changes. + * @param options - Configuration for finalizer execution behavior, including execution strategy + * and debounce timing. + * + * @returns An Effect that produces a `Scope` for resource management +*/ +export const useScope = Effect.fnUntraced(function*( + deps: React.DependencyList, + options?: useScope.Options, +): Effect.fn.Return { + // biome-ignore lint/style/noNonNullAssertion: context initialization + const contextRef = React.useRef>(null!) + contextRef.current = yield* Effect.context() + const registry = yield* ScopeRegistry.ScopeRegistry as unknown as Effect.Effect + + const [key, scope] = React.useMemo(() => Effect.runSyncWith(contextRef.current)(Effect.gen(function*() { + const key = ScopeRegistry.makeKey() + const entry = yield* registry.register(key, { + finalizerExecutionStrategy: options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy, + finalizerExecutionDebounce: options?.finalizerExecutionDebounce ?? defaultOptions.finalizerExecutionDebounce, + scopeCommitTimeout: options?.scopeCommitTimeout ?? defaultOptions.scopeCommitTimeout, + }) + + return [key, entry.scope] + // biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList + })), deps) + + // biome-ignore lint/correctness/useExhaustiveDependencies: only reactive on "key" + React.useEffect(() => { + Effect.runSyncWith(contextRef.current)(registry.commit(key)) + return () => { + Effect.runSyncWith(contextRef.current)(registry.release(key)) + } + }, [key]) + + return scope +}) + +/** + * Effect hook that executes an Effect once when the component mounts and caches the result. + * + * This hook is useful for one-time initialization logic that should not be re-executed + * when the component re-renders. The Effect is executed exactly once during the component's + * initial mount, and the cached result is returned on all subsequent renders. + * + * @param f - A function that returns the Effect to execute on mount + * + * @returns An Effect that produces the cached result of the Effect + * + * @example + * ```tsx + * const MyComponent = Component.make(function*() { + * const initialData = yield* Component.useOnMount(() => getData) + * return

{initialData}
+ * }) + * ``` + */ +export const useOnMount = Effect.fnUntraced(function* ( + f: () => Effect.Effect +): Effect.fn.Return { + const context = yield* Effect.context() + return yield* React.useState(() => Effect.runSyncWith(context)(Effect.cached(f())))[0] +}) + +export declare namespace useOnChange { + export interface Options extends useScope.Options {} +} + +/** + * Effect hook that executes an Effect whenever dependencies change and caches the result. + * + * This hook combines the dependency-tracking behavior of React.useEffect with Effect caching. + * The Effect is re-executed whenever any dependency in the `deps` array changes, and the result + * is cached until the next dependency change. + * + * A dedicated scope is created for each dependency change, ensuring proper resource cleanup: + * - The scope closes when dependencies change + * - The scope closes when the component unmounts + * - All finalizers are executed according to the configured execution strategy + * + * @param f - A function that returns the Effect to execute + * @param deps - Dependency array following React.useEffect semantics + * @param options - Configuration for scope and finalizer behavior + * + * @returns An Effect that produces the cached result of the Effect + * + * @example + * ```tsx + * const MyComponent = Component.make(function* (props: { userId: string }) { + * const userData = yield* Component.useOnChange( + * getUser(props.userId), + * [props.userId], + * ) + * return
{userData.name}
+ * }) + * ``` + */ +export const useOnChange = Effect.fnUntraced(function* ( + f: () => Effect.Effect, + deps: React.DependencyList, + options?: useOnChange.Options, +): Effect.fn.Return> { + const context = yield* Effect.context>() + const scope = yield* useScope(deps, options) + + // biome-ignore lint/correctness/useExhaustiveDependencies: only reactive on "scope" + return yield* React.useMemo(() => Effect.runSyncWith(context)( + Effect.cached(Effect.provideService(f(), Scope.Scope, scope)) + ), [scope]) +}) + +export declare namespace useReactEffect { + export interface Options { + readonly finalizerExecutionMode?: "sync" | "fork" + readonly finalizerExecutionStrategy?: "sequential" | "parallel" + } +} + +/** + * Effect hook that provides Effect-based semantics for React.useEffect. + * + * This hook bridges React's useEffect with the Effect system, allowing you to use Effects + * for React side effects while maintaining React's dependency tracking and lifecycle semantics. + * + * Unlike React.useEffect which uses imperative cleanup functions, this hook leverages the + * Effect Scope API for resource management. Cleanup logic is expressed declaratively through + * finalizers registered with the scope, providing better composability and error handling. + * + * @param f - A function that returns an Effect to execute as a side effect + * @param deps - Optional dependency array following React.useEffect semantics. + * If omitted, the effect runs after every render. + * @param options - Configuration for finalizer execution mode (sync or fork) and strategy + * + * @returns An Effect that produces void + * + * @example + * ```tsx + * const MyComponent = Component.make(function* (props: { id: string }) { + * yield* Component.useReactEffect( + * () => getNotificationStreamForUser(props.id).pipe( + * Stream.unwrap, + * Stream.runForEach(notification => Console.log(`Notification received: ${ notification }`), + * Effect.forkScoped, + * ), + * [props.id], + * ) + * return
Subscribed to notifications for {props.id}
+ * }) + * ``` + */ +export const useReactEffect = Effect.fnUntraced(function* ( + f: () => Effect.Effect, + deps?: React.DependencyList, + options?: useReactEffect.Options, +): Effect.fn.Return> { + const context = yield* Effect.context>() + // biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList + React.useEffect(() => runReactEffect(context, f, options), deps) +}) + +const runReactEffect = ( + context: Context.Context>, + f: () => Effect.Effect, + 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": + Effect.runSyncWith(context)(Scope.close(scope, Exit.void)) + break + case "fork": + Effect.runForkWith(context)(Scope.close(scope, Exit.void)) + break + } + } + ), + Effect.runSyncWith(context), +) + +export declare namespace useReactLayoutEffect { + export interface Options extends useReactEffect.Options {} +} + +/** + * Effect hook that provides Effect-based semantics for React.useLayoutEffect. + * + * This hook is identical to `useReactEffect` but executes synchronously after DOM mutations + * but before the browser paints, following React.useLayoutEffect semantics. + * + * Use this hook when you need to: + * - Measure DOM elements (e.g., for layout calculations) + * - Synchronously update state based on DOM measurements + * - Avoid visual flicker from asynchronous updates + * + * Like `useReactEffect`, cleanup logic is handled through the Effect Scope API rather than + * imperative cleanup functions, providing declarative and composable resource management. + * + * @param f - A function that returns an Effect to execute as a layout side effect + * @param deps - Optional dependency array following React.useLayoutEffect semantics. + * If omitted, the effect runs after every render. + * @param options - Configuration for finalizer execution mode (sync or fork) and strategy + * + * @returns An Effect that produces void + * + * @example + * ```tsx + * const MyComponent = Component.make(function*() { + * const ref = React.useRef(null) + * yield* Component.useReactLayoutEffect( + * () => Effect.gen(function* () { + * const element = ref.current + * if (element) { + * const rect = element.getBoundingClientRect() + * yield* Console.log(`Element dimensions: ${ rect.width }x${ rect.height }`) + * } + * }), + * [], + * ) + * return
Content
+ * }) + * ``` + */ +export const useReactLayoutEffect = Effect.fnUntraced(function* ( + f: () => Effect.Effect, + deps?: React.DependencyList, + options?: useReactLayoutEffect.Options, +): Effect.fn.Return> { + const context = yield* Effect.context>() + // biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList + React.useLayoutEffect(() => runReactEffect(context, f, options), deps) +}) + +/** + * Effect hook that provides a synchronous function to execute Effects within the current runtime context. + * + * This hook returns a function that can execute Effects synchronously, blocking until completion. + * Use this when you need to run Effects from non-Effect code (e.g., event handlers, callbacks) + * within a component. + * + * @returns An Effect that produces a function capable of synchronously executing Effects + * + * @example + * ```tsx + * const MyComponent = Component.make(function*() { + * const runSync = yield* Component.useRunSync() // Specify required services + * const runSync = yield* Component.useRunSync() // Or no service requirements + * + * return + * }) + * ``` + */ +export const useRunSync = (): Effect.Effect< + (effect: Effect.Effect) => A, + never, + Scope.Scope | R +> => Effect.map(Effect.context(), Effect.runSyncWith) + +/** + * Effect hook that provides an asynchronous function to execute Effects within the current runtime context. + * + * This hook returns a function that executes Effects asynchronously, returning a Promise that resolves + * with the Effect's result. Use this when you need to run Effects from non-Effect code (e.g., event handlers, + * async callbacks) and want to handle the result asynchronously. + * + * @returns An Effect that produces a function capable of asynchronously executing Effects + * + * @example + * ```tsx + * const MyComponent = Component.make(function*() { + * const runPromise = yield* Component.useRunPromise() // Specify required services + * const runPromise = yield* Component.useRunPromise() // Or no service requirements + * + * return + * }) + * ``` + */ +export const useRunPromise = (): Effect.Effect< + (effect: Effect.Effect) => Promise, + never, + Scope.Scope | R +> => Effect.map(Effect.context(), Effect.runPromiseWith) + +/** + * Effect hook that memoizes a function that returns an Effect, providing synchronous execution. + * + * This hook wraps a function that returns an Effect and returns a memoized version that: + * - Executes the Effect synchronously when called + * - Is memoized based on the provided dependency array + * - Maintains referential equality across renders when dependencies don't change + * + * Use this to create stable callback references for event handlers and other scenarios + * where you need to execute Effects synchronously from non-Effect code. + * + * @param f - A function that accepts arguments and returns an Effect + * @param deps - Dependency array. The memoized function is recreated when dependencies change. + * + * @returns An Effect that produces a memoized function with the same signature as `f` + * + * @example + * ```tsx + * const MyComponent = Component.make(function* (props: { onSave: (data: Data) => void }) { + * const handleSave = yield* Component.useCallbackSync( + * (data: Data) => Effect.sync(() => props.onSave(data)), + * [props.onSave], + * ) + * + * return + * }) + * ``` + */ +export const useCallbackSync = Effect.fnUntraced(function* ( + f: (...args: Args) => Effect.Effect, + deps: React.DependencyList, +): Effect.fn.Return<(...args: Args) => A, never, R> { + // biome-ignore lint/style/noNonNullAssertion: context initialization + const contextRef = React.useRef>(null!) + contextRef.current = yield* Effect.context() + + // biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList + return React.useCallback((...args: Args) => Effect.runSyncWith(contextRef.current)(f(...args)), deps) +}) + +/** + * Effect hook that memoizes a function that returns an Effect, providing asynchronous execution. + * + * This hook wraps a function that returns an Effect and returns a memoized version that: + * - Executes the Effect asynchronously when called, returning a Promise + * - Is memoized based on the provided dependency array + * - Maintains referential equality across renders when dependencies don't change + * + * Use this to create stable callback references for async event handlers and other scenarios + * where you need to execute Effects asynchronously from non-Effect code. + * + * @param f - A function that accepts arguments and returns an Effect + * @param deps - Dependency array. The memoized function is recreated when dependencies change. + * + * @returns An Effect that produces a memoized function that returns a Promise + * + * @example + * ```tsx + * const MyComponent = Component.make(function* (props: { onSave: (data: Data) => void }) { + * const handleSave = yield* Component.useCallbackPromise( + * (data: Data) => Effect.promise(() => props.onSave(data)), + * [props.onSave], + * ) + * + * return + * }) + * ``` + */ +export const useCallbackPromise = Effect.fnUntraced(function* ( + f: (...args: Args) => Effect.Effect, + deps: React.DependencyList, +): Effect.fn.Return<(...args: Args) => Promise, never, R> { + // biome-ignore lint/style/noNonNullAssertion: context initialization + const contextRef = React.useRef>(null!) + contextRef.current = yield* Effect.context() + + // biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList + return React.useCallback((...args: Args) => Effect.runPromiseWith(contextRef.current)(f(...args)), deps) +}) + +export declare namespace useContext { + export interface Options extends useOnChange.Options {} +} + +/** + * Effect hook that constructs an Effect Layer and returns the resulting context. + * + * This hook creates a managed runtime from the provided layer and returns the context it produces. + * The layer is reconstructed whenever its value changes, so ensure the layer reference is stable + * (typically by memoizing it or defining it outside the component). + * + * The hook automatically manages the layer's lifecycle: + * - The layer is built when the component mounts or when the layer reference changes + * - Resources are properly released when the component unmounts or dependencies change + * - Finalizers are executed according to the configured execution strategy + * + * @param layer - The Effect Layer to construct. Should be a stable reference to avoid unnecessary + * reconstruction. Consider memoizing with React.useMemo if defined inline. + * @param options - Configuration for scope and finalizer behavior + * + * @returns An Effect that produces the context created by the layer + * + * @throws If the layer contains asynchronous effects, the component must be wrapped with `Async.async` + * + * @example + * ```tsx + * const MyLayer = Layer.succeed(MyService, new MyServiceImpl()) + * const MyComponent = Component.make(function*() { + * const context = yield* Component.useLayer(MyLayer) + * const Sub = yield* SubComponent.use.pipe( + * Effect.provide(context) + * ) + * + * return + * }) + * ``` + * + * @example With memoized layer + * ```tsx + * const MyComponent = Component.make(function*(props: { id: string })) { + * const context = yield* Component.useLayer( + * React.useMemo(() => Layer.succeed(MyService, new MyServiceImpl(props.id)), [props.id]) + * ) + * const Sub = yield* SubComponent.use.pipe( + * Effect.provide(context) + * ) + * + * return + * }) + * ``` + * + * @example With async layer + * ```tsx + * const MyAsyncLayer = Layer.effect(MyService, someAsyncEffect) + * const MyComponent = Component.make(function*() { + * const context = yield* Component.useLayer(MyAsyncLayer) + * const Sub = yield* Effect.provide(SubComponent, context) + * + * return + * }).pipe( + * Async.async // Required to handle async layer effects + * ) + */ +export const useLayer = ( + layer: Layer.Layer, + options?: useContext.Options, +): Effect.Effect, E, RIn | Scope.Scope> => useOnChange(() => Effect.flatMap( + Effect.context(), + context => Layer.build(Layer.provide(layer, Layer.succeedContext(context))), +), [layer], options) diff --git a/packages/effect-fc-next/src/Form.ts b/packages/effect-fc-next/src/Form.ts new file mode 100644 index 0000000..ce404eb --- /dev/null +++ b/packages/effect-fc-next/src/Form.ts @@ -0,0 +1,276 @@ +import type { StandardSchemaV1 } from "@standard-schema/spec" +import { Array, type Cause, Chunk, type Duration, Effect, Equal, Function, identity, Option, Pipeable, Predicate, type Scope, Stream, SubscriptionRef } from "effect" +import type * as React from "react" +import * as Component from "./Component.js" +import * as Lens from "./Lens.js" +import * as View from "./View.js" + + +export const FormTypeId: unique symbol = Symbol.for("@effect-fc/Form/Form") +export type FormTypeId = typeof FormTypeId + +export interface Form +extends Pipeable.Pipeable { + readonly [FormTypeId]: FormTypeId + + readonly path: P + readonly value: View.View, ER, never> + readonly encodedValue: Lens.Lens + readonly issues: View.View + readonly isValidating: View.View + readonly canCommit: View.View + readonly isCommitting: View.View +} + +export class FormImpl +extends Pipeable.Class implements Form { + readonly [FormTypeId]: FormTypeId = FormTypeId + + constructor( + readonly path: P, + readonly value: View.View, ER, never>, + readonly encodedValue: Lens.Lens, + readonly issues: View.View, + readonly isValidating: View.View, + readonly canCommit: View.View, + readonly isCommitting: View.View, + ) { + super() + } +} + +export const isForm = (u: unknown): u is Form => Predicate.hasProperty(u, FormTypeId) + + +const filterIssuesByPath = ( + issues: readonly StandardSchemaV1.Issue[], + path: readonly PropertyKey[], +): readonly StandardSchemaV1.Issue[] => Array.filter(issues, issue => { + const issuePath = issue.path + if (!issuePath) return false + return issuePath.length >= path.length && Array.every(path, (p, i) => p === issuePath[i]) +}) + +export const focusObjectOn: { +

( + self: Form, + key: K, + ): Form +

( + key: K, + ): (self: Form) => Form +} = Function.dual(2,

( + self: Form, + key: K, +): Form => { + const form = self as FormImpl + const path = [...form.path, key] as const + + return new FormImpl( + path, + View.mapOption(form.value, a => a[key]), + Lens.focusObjectOn(form.encodedValue, key), + View.map(form.issues, issues => filterIssuesByPath(issues, path)), + form.isValidating, + form.canCommit, + form.isCommitting, + ) +}) + +export const focusArrayAt: { +

( + self: Form, + index: number, + ): Form +

( + index: number, + ): (self: Form) => Form +} = Function.dual(2,

( + self: Form, + index: number, +): Form => { + const form = self as FormImpl + const path = [...form.path, index] as const + + return new FormImpl( + path, + View.mapOptionEffect(form.value, value => Effect.fromOption(Array.get(value, index))), + Lens.focusArrayAt(form.encodedValue, index), + View.map(form.issues, issues => filterIssuesByPath(issues, path)), + form.isValidating, + form.canCommit, + form.isCommitting, + ) +}) + +export const focusTupleAt: { +

( + self: Form, + index: K, + ): Form +

( + index: K, + ): (self: Form) => Form +} = Function.dual(2,

( + self: Form, + index: K, +): Form => { + const form = self as FormImpl + const path = [...form.path, index] as const + + return new FormImpl( + path, + View.mapOption(form.value, Array.getUnsafe(index)), + Lens.focusTupleAt(form.encodedValue, index), + View.map(form.issues, issues => filterIssuesByPath(issues, path)), + form.isValidating, + form.canCommit, + form.isCommitting, + ) +}) + +export const focusChunkAt: { +

( + self: Form, Chunk.Chunk, ER, EW>, + index: number, + ): Form +

( + index: number, + ): (self: Form, Chunk.Chunk, ER, EW>) => Form +} = Function.dual(2,

( + self: Form, Chunk.Chunk, ER, EW>, + index: number, +): Form => { + const form = self as FormImpl, Chunk.Chunk, ER, EW> + const path = [...form.path, index] as const + + return new FormImpl( + path, + View.mapOptionEffect(form.value, value => Effect.fromOption(Chunk.get(value, index))), + Lens.focusChunkAt(form.encodedValue, index), + View.map(form.issues, issues => filterIssuesByPath(issues, path)), + form.isValidating, + form.canCommit, + form.isCommitting, + ) +}) + + +export namespace useInput { + export interface Options { + readonly debounce?: Duration.Input + } + + export interface Success { + readonly value: T + readonly setValue: React.Dispatch> + } +} + +export const useInput = Effect.fnUntraced(function*

( + form: Form, + options?: useInput.Options, +): Effect.fn.Return, ER, Scope.Scope> { + const internalValueLens = yield* Component.useOnChange(() => Effect.gen(function*() { + const internalValueLens = yield* Lens.get(form.encodedValue).pipe( + Effect.flatMap(SubscriptionRef.make), + Effect.map(Lens.fromSubscriptionRef), + ) + + yield* Effect.forkScoped(Effect.all([ + Stream.runForEach( + Stream.drop(Lens.changes(form.encodedValue), 1), + upstreamEncodedValue => Effect.when( + Lens.set(internalValueLens, upstreamEncodedValue), + Effect.map(Lens.get(internalValueLens), internalValue => !Equal.equals(upstreamEncodedValue, internalValue)), + ), + ), + + Stream.runForEach( + Lens.changes(internalValueLens).pipe( + Stream.drop(1), + Stream.changesWith(Equal.asEquivalence()), + options?.debounce ? Stream.debounce(options.debounce) : identity, + ), + internalValue => Lens.set(form.encodedValue, internalValue), + ), + ], { concurrency: "unbounded", discard: true })) + + return internalValueLens + }), [form, options?.debounce]) + + const [value, setValue] = yield* Lens.useState(internalValueLens) + return { value, setValue } +}) + +export namespace useOptionalInput { + export interface Options extends useInput.Options { + readonly defaultValue: T + } + + export interface Success extends useInput.Success { + readonly enabled: boolean + readonly setEnabled: React.Dispatch> + } +} + +export const useOptionalInput = Effect.fnUntraced(function*

( + field: Form, ER, EW>, + options: useOptionalInput.Options, +): Effect.fn.Return, ER, Scope.Scope> { + const [enabledLens, internalValueLens] = yield* Component.useOnChange(() => Effect.gen(function*() { + const [enabledLens, internalValueLens] = yield* Effect.flatMap( + Lens.get(field.encodedValue), + Option.match({ + onSome: v => Effect.all([ + Effect.map(SubscriptionRef.make(true), Lens.fromSubscriptionRef), + Effect.map(SubscriptionRef.make(v), Lens.fromSubscriptionRef), + ]), + onNone: () => Effect.all([ + Effect.map(SubscriptionRef.make(false), Lens.fromSubscriptionRef), + Effect.map(SubscriptionRef.make(options.defaultValue), Lens.fromSubscriptionRef), + ]), + }), + ) + + yield* Effect.forkScoped(Effect.all([ + Stream.runForEach( + Stream.drop(Lens.changes(field.encodedValue), 1), + + upstreamEncodedValue => Effect.when( + Option.match(upstreamEncodedValue, { + onSome: v => Effect.andThen( + Lens.set(enabledLens, true), + Lens.set(internalValueLens, v), + ), + onNone: () => Effect.andThen( + Lens.set(enabledLens, false), + Lens.set(internalValueLens, options.defaultValue), + ), + }), + + Effect.map( + Effect.all([Lens.get(enabledLens), Lens.get(internalValueLens)]), + ([enabled, internalValue]) => !Equal.equals(upstreamEncodedValue, enabled ? Option.some(internalValue) : Option.none()), + ), + ), + ), + + Stream.runForEach( + Lens.changes(enabledLens).pipe( + Stream.zipLatest(internalValueLens.changes), + Stream.drop(1), + Stream.changesWith(Equal.asEquivalence()), + options?.debounce ? Stream.debounce(options.debounce) : identity, + ), + ([enabled, internalValue]) => Lens.set(field.encodedValue, enabled ? Option.some(internalValue) : Option.none()), + ), + ], { concurrency: "unbounded" })) + + return [enabledLens, internalValueLens] as const + }), [field, options.debounce]) + + const [enabled, setEnabled] = yield* Lens.useState(enabledLens) + const [value, setValue] = yield* Lens.useState(internalValueLens) + return { enabled, setEnabled, value, setValue } +}) diff --git a/packages/effect-fc-next/src/Lens.test.tsx b/packages/effect-fc-next/src/Lens.test.tsx new file mode 100644 index 0000000..c59c686 --- /dev/null +++ b/packages/effect-fc-next/src/Lens.test.tsx @@ -0,0 +1,171 @@ +import { fireEvent, render, screen, waitFor } from "@testing-library/react" +import { Effect, Layer, SubscriptionRef } from "effect" +import * as React from "react" +import { describe, expect, it } from "vitest" +import * as Component from "./Component.js" +import * as Lens from "./Lens.js" +import * as ReactRuntime from "./ReactRuntime.js" + + +const makeRuntime = async () => { + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + + return { + runtime, + effectRuntime, + dispose: () => runtime.runtime.dispose(), + } +} + +const expectDefined = (value: A | undefined): A => { + if (value === undefined) + throw new Error("Expected value to be defined") + return value +} + +describe("Lens", () => { + it("useState stays in sync with lens updates in both directions", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + const ref = await Effect.runPromise(SubscriptionRef.make(0)) + const lens = Lens.fromSubscriptionRef(ref) + + const Probe = Component.makeUntraced("LensUseStateProbe")(function*() { + const [value, setValue] = yield* Lens.useState(lens) + + return ( + <> +

{value}
+ + + ) + }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("0") + + await Effect.runPromise(Lens.set(lens, 5)) + await screen.findByText("5") + + fireEvent.click(screen.getByRole("button", { name: "increment" })) + await screen.findByText("6") + expect(await Effect.runPromise(Lens.get(lens))).toBe(6) + + view.unmount() + await dispose() + }) + + it("useState respects the provided equivalence when subscribing to lens changes", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + const ref = await Effect.runPromise(SubscriptionRef.make({ id: 1, label: "first" })) + const lens = Lens.fromSubscriptionRef(ref) + + const Probe = Component.makeUntraced("LensUseStateEquivalenceProbe")(function*() { + const [value] = yield* Lens.useState(lens, { + equivalence: (self, that) => self.id === that.id, + }) + + return
{value.label}
+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + + await Effect.runPromise(Lens.set(lens, { id: 1, label: "ignored" })) + await waitFor(() => expect(screen.getByText("first")).toBeTruthy()) + expect(screen.queryByText("ignored")).toBeNull() + + await Effect.runPromise(Lens.set(lens, { id: 2, label: "updated" })) + await screen.findByText("updated") + + view.unmount() + await dispose() + }) + + it("useFromReactState writes React state changes into the returned lens", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + let lens: Lens.Lens | undefined + + const Probe = Component.makeUntraced("LensUseFromReactStateProbe")(function*() { + const [value, setValue] = React.useState("hello") + const reactLens = yield* Lens.useFromReactState([value, setValue]) + + yield* Component.useOnMount(() => Effect.sync(() => { + lens = reactLens + })) + + return + }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("hello") + await waitFor(() => expect(lens).toBeDefined()) + + fireEvent.click(screen.getByRole("button", { name: "hello" })) + await screen.findByText("hello!") + await waitFor(async () => expect(await Effect.runPromise(Lens.get(expectDefined(lens)))).toBe("hello!")) + + view.unmount() + await dispose() + }) + + it("useFromReactState respects equivalence when lens updates flow back into React state", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + let lens: Lens.Lens<{ readonly id: number; readonly label: string }, never, never, never, never> | undefined + + const Probe = Component.makeUntraced("LensUseFromReactStateEquivalenceProbe")(function*() { + const [value, setValue] = React.useState({ id: 1, label: "first" }) + const reactLens = yield* Lens.useFromReactState([value, setValue], { + equivalence: (self, that) => self.id === that.id, + }) + + yield* Component.useOnMount(() => Effect.sync(() => { + lens = reactLens + })) + + return
{value.label}
+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + await waitFor(() => expect(lens).toBeDefined()) + + await Effect.runPromise(Lens.set(expectDefined(lens), { id: 1, label: "ignored" })) + await waitFor(() => expect(screen.getByText("first")).toBeTruthy()) + expect(screen.queryByText("ignored")).toBeNull() + + await Effect.runPromise(Lens.set(expectDefined(lens), { id: 2, label: "updated" })) + await screen.findByText("updated") + + view.unmount() + await dispose() + }) +}) diff --git a/packages/effect-fc-next/src/Lens.ts b/packages/effect-fc-next/src/Lens.ts new file mode 100644 index 0000000..4941dea --- /dev/null +++ b/packages/effect-fc-next/src/Lens.ts @@ -0,0 +1,62 @@ +import { Effect, Equivalence, Stream, SubscriptionRef } from "effect" +import { Lens } from "effect-lens" +import * as React from "react" +import * as Component from "./Component.js" +import * as SetStateAction from "./SetStateAction.js" + + +export * from "effect-lens/Lens" + +export declare namespace useState { + export interface Options
{ + readonly equivalence?: Equivalence.Equivalence + } +} + +export const useState = Effect.fnUntraced(function* ( + lens: Lens.Lens, + options?: useState.Options>, +): Effect.fn.Return>], ER | EW, RR | RW> { + const [reactStateValue, setReactStateValue] = React.useState(yield* Component.useOnMount(() => Lens.get(lens))) + + yield* Component.useReactEffect(() => Effect.forkScoped( + Stream.runForEach( + Stream.changesWith(lens.changes, options?.equivalence ?? Equivalence.strictEqual()), + v => Effect.sync(() => setReactStateValue(v)), + ) + ), [lens]) + + const setValue = yield* Component.useCallbackSync( + (setStateAction: React.SetStateAction) => Effect.tap( + Lens.updateAndGet(lens, prevState => SetStateAction.value(setStateAction, prevState)), + v => Effect.sync(() => setReactStateValue(v)), + ), + [lens], + ) + + return [reactStateValue, setValue] +}) + +export declare namespace useFromReactState { + export interface Options { + readonly equivalence?: Equivalence.Equivalence + } +} + +export const useFromReactState = Effect.fnUntraced(function* ( + [value, setValue]: readonly [A, React.Dispatch>], + options?: useFromReactState.Options>, +): Effect.fn.Return> { + const lens = yield* Component.useOnMount(() => Effect.map( + SubscriptionRef.make(value), + Lens.fromSubscriptionRef, + )) + + yield* Component.useReactEffect(() => Effect.forkScoped(Stream.runForEach( + Stream.changesWith(lens.changes, options?.equivalence ?? Equivalence.strictEqual()), + v => Effect.sync(() => setValue(v)), + )), [setValue]) + yield* Component.useReactEffect(() => Lens.set(lens, value), [value]) + + return lens +}) diff --git a/packages/effect-fc-next/src/LensForm.ts b/packages/effect-fc-next/src/LensForm.ts new file mode 100644 index 0000000..576b486 --- /dev/null +++ b/packages/effect-fc-next/src/LensForm.ts @@ -0,0 +1,206 @@ +import type { StandardSchemaV1 } from "@standard-schema/spec" +import { Array, type Context, Effect, Equal, Fiber, Option, Pipeable, Predicate, Schema, SchemaIssue, type Scope, Semaphore, Stream, SubscriptionRef } from "effect" +import * as Form from "./Form.js" +import * as Lens from "./Lens.js" +import * as View from "./View.js" + + +export const LensFormTypeId: unique symbol = Symbol.for("@effect-fc/Form/LensForm") +export type LensFormTypeId = typeof LensFormTypeId + +export interface LensForm +extends Form.Form { + readonly [LensFormTypeId]: LensFormTypeId + + readonly schema: Schema.ConstraintCodec + readonly context: Context.Context + readonly target: Lens.Lens + readonly validationFiber: View.View>, never, never> + + readonly run: Effect.Effect +} + +export class LensFormImpl +extends Pipeable.Class implements LensForm { + readonly [Form.FormTypeId]: Form.FormTypeId = Form.FormTypeId + readonly [LensFormTypeId]: LensFormTypeId = LensFormTypeId + + readonly path = [] as const + + readonly value: View.View, never, never> + readonly encodedValue: Lens.Lens + readonly isValidating: View.View + readonly canCommit: View.View + + constructor( + readonly schema: Schema.ConstraintCodec, + readonly context: Context.Context, + readonly target: Lens.Lens, + + readonly internalEncodedValue: Lens.Lens, + readonly issues: Lens.Lens, + readonly validationFiber: Lens.Lens>, never, never, never, never>, + readonly isCommitting: Lens.Lens, + + readonly runSemaphore: Semaphore.Semaphore, + ) { + super() + + this.value = Effect.succeed(this).pipe( + Effect.map(self => View.make({ + get: Effect.provide(Effect.option(self.target.get), self.context), + get changes() { + return Stream.provideContext( + self.target.changes.pipe( + Stream.map(Option.some), + Stream.catch(() => Stream.make(Option.none())), + ), + self.context, + ) + }, + })), + View.unwrap, + ) + this.encodedValue = Effect.all([ + Effect.succeed(this), + Effect.succeed(Lens.asLensImpl(this.internalEncodedValue)), + ]).pipe( + Effect.map(([self, parent]) => Lens.make({ + get: parent.get, + get changes() { return parent.changes }, + commit: a => Effect.andThen( + Effect.flatMap( + parent.resolve, + resolved => resolved.commit(Effect.succeed(a)), + ), + self.synchronizeEncodedValue(a), + ), + lock: parent.lock, + })), + Lens.unwrap, + ) + this.isValidating = Effect.succeed(this).pipe( + Effect.map(self => View.map(self.validationFiber, Option.isSome)), + View.unwrap, + ) + this.canCommit = Effect.succeed(this).pipe( + Effect.map(self => View.map( + View.zipLatestAll(self.issues, self.validationFiber, self.isCommitting), + ([issues, validationFiber, isCommitting]) => ( + Array.isReadonlyArrayEmpty(issues) && + Option.isNone(validationFiber) && + !isCommitting + ), + )), + View.unwrap, + ) + } + + synchronizeEncodedValue(encodedValue: I): Effect.Effect { + return Lens.get(this.validationFiber).pipe( + Effect.andThen(Option.match({ + onSome: Fiber.interrupt, + onNone: () => Effect.void, + })), + Effect.andThen(Effect.forkScoped( + Effect.ensuring( + Schema.decodeEffect(this.schema, { errors: "all" })(encodedValue), + Lens.set(this.validationFiber, Option.none()), + ) + )), + Effect.tap(fiber => Lens.set(this.validationFiber, Option.some(fiber))), + Effect.flatMap(Fiber.join), + + Effect.flatMap(value => Effect.ensuring( + Lens.set(this.isCommitting, true).pipe( + Effect.andThen(Lens.set(this.issues, Array.empty())), + Effect.andThen(Lens.set(this.target, value)), + ), + Lens.set(this.isCommitting, false), + )), + Effect.catchIf( + Schema.isSchemaError, + error => Lens.set(this.issues, SchemaIssue.makeFormatterStandardSchemaV1()(error.issue).issues), + ), + + Effect.provide(this.context), + ) + } + + get run(): Effect.Effect { + return this.runSemaphore.withPermits(1)(Effect.provide( + Stream.runForEach( + Stream.drop(Lens.changes(this.target), 1), + targetValue => Schema.encodeEffect(this.schema, { errors: "all" })(targetValue).pipe( + Effect.flatMap(encodedValue => Effect.when( + Effect.andThen( + Lens.set(this.issues, Array.empty()), + Lens.set(this.internalEncodedValue, encodedValue), + ), + Effect.map( + Lens.get(this.internalEncodedValue), + currentEncodedValue => !Equal.equals(encodedValue, currentEncodedValue), + ), + )), + Effect.ignore, + ), + ), + this.context, + )) + } +} + +export const isLensForm = (u: unknown): u is LensForm => Predicate.hasProperty(u, LensFormTypeId) + + +export declare namespace make { + export interface Options { + readonly schema: Schema.ConstraintCodec + readonly target: Lens.Lens + readonly initialEncodedValue?: NoInfer + } +} + +export const make = Effect.fnUntraced(function* ( + options: make.Options +): Effect.fn.Return< + LensForm, + Schema.SchemaError | TER, + Scope.Scope | RD | RE | TRR | TRW +> { + const initialEncodedValue = options.initialEncodedValue !== undefined + ? options.initialEncodedValue + : yield* Effect.flatMap( + Lens.get(options.target), + Schema.encodeEffect(options.schema), + ) + + return new LensFormImpl( + options.schema, + yield* Effect.context(), + options.target, + + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(initialEncodedValue)), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Array.empty())), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none>())), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(false)), + + yield* Semaphore.make(1), + ) +}) + +export declare namespace service { + export interface Options + extends make.Options {} +} + +export const service = ( + options: service.Options +): Effect.Effect< + LensForm, + Schema.SchemaError | TER, + Scope.Scope | RD | RE | TRR | TRW +> => Effect.tap( + make(options), + form => Effect.forkScoped(form.run), +) diff --git a/packages/effect-fc-next/src/Memoized.ts b/packages/effect-fc-next/src/Memoized.ts new file mode 100644 index 0000000..0c981c8 --- /dev/null +++ b/packages/effect-fc-next/src/Memoized.ts @@ -0,0 +1,112 @@ +/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ +import { type Equivalence, Function, Predicate } from "effect" +import * as React from "react" +import type * as Component from "./Component.js" + + +export const MemoizedTypeId: unique symbol = Symbol.for("@effect-fc/Memoized/Memoized") +export type MemoizedTypeId = typeof MemoizedTypeId + + +/** + * A trait for `Component`'s that uses `React.memo` to optimize re-renders based on prop equality. + * + * @template P The props type of the component + */ +export interface Memoized

extends MemoizedPrototype, MemoizedOptions

{} + +export interface MemoizedPrototype { + readonly [MemoizedTypeId]: MemoizedTypeId +} + +/** + * Configuration options for Memoized components. + * + * @template P The props type of the component + */ +export interface MemoizedOptions

{ + /** + * An optional equivalence function for comparing component props. + * If provided, this function is used by React.memo to determine if props have changed. + * Returns `true` if props are equivalent (no re-render), `false` if they differ (re-render). + */ + readonly propsEquivalence?: Equivalence.Equivalence

+} + + +export const MemoizedPrototype: MemoizedPrototype = Object.freeze({ + [MemoizedTypeId]: MemoizedTypeId, + + transformFunctionComponent

( + this: Memoized

, + f: React.FC

( + this: Component.ComponentImpl & Refreshable, + contextRef: React.RefObject>>, + ) { + const cell = this[RefreshableTypeId] + let current = cell.current + let functionComponent = current.makeFunctionComponent(contextRef) + + // Calling the current renderer inside this stable component deliberately + // keeps its hooks on the same fiber until resetRevision changes. + const Implementation = (props: P) => { + if (current !== cell.current) { + current = cell.current + functionComponent = current.makeFunctionComponent(contextRef) + } + return functionComponent(props) + } + + const RefreshableComponent = (props: P) => { + const snapshot = React.useSyncExternalStore( + cell.subscribe, + cell.getSnapshot, + cell.getSnapshot, + ) + return React.createElement(Implementation, { + ...props, + key: snapshot.resetRevision, + }) + } + + return RefreshableComponent as F + }, +} as const) + +export type RefreshablePrototype = typeof RefreshablePrototype + +/** + * A descriptor that can be connected to a development refresh cell. + */ +export interface Refreshable extends RefreshablePrototype { + readonly [RefreshableTypeId]: Cell +} + +/** + * Checks whether a descriptor has been connected to a development refresh + * cell. + */ +export const isRefreshable = ( + value: A, +): value is A & Refreshable => Object.hasOwn(value, RefreshableTypeId) + +/** + * Creates a refresh cell for an Effect View descriptor. + * + * This low-level API is intended for development-server integrations. + */ +export const makeCell = ( + component: Component.Component.Any, + signature: string, + forceReset: boolean, +): Cell => { + const listeners = new Set<() => void>() + let notificationPending = false + + const cell: Cell = { + current: component as Component.ComponentImpl.Any, + signature, + forceReset, + snapshot: { + revision: 0, + resetRevision: 0, + }, + subscribe(listener) { + listeners.add(listener) + return () => { + listeners.delete(listener) + } + }, + getSnapshot() { + return cell.snapshot + }, + update(nextComponent, nextSignature, nextForceReset) { + const shouldReset = cell.forceReset + || nextForceReset + || cell.signature !== nextSignature + + cell.current = nextComponent as Component.ComponentImpl.Any + cell.signature = nextSignature + cell.forceReset = nextForceReset + cell.snapshot = { + revision: cell.snapshot.revision + 1, + resetRevision: cell.snapshot.resetRevision + (shouldReset ? 1 : 0), + } + + if (!notificationPending) { + notificationPending = true + queueMicrotask(() => { + notificationPending = false + for (const listener of listeners) + listener() + }) + } + }, + } + + return cell +} + +/** + * Associates a descriptor with a refresh cell and returns the descriptor. + * + * This low-level API is intended for development-server integrations. + */ +export const attach = ( + component: A, + cell: Cell, +): A & Refreshable => { + if (!isRefreshable(component)) { + Object.setPrototypeOf( + component, + Object.freeze(Object.setPrototypeOf( + Object.assign({}, RefreshablePrototype), + Object.getPrototypeOf(component), + )), + ) + } + + Object.defineProperty(component, RefreshableTypeId, { + configurable: true, + enumerable: true, + value: cell, + }) + return component as A & Refreshable +} diff --git a/packages/effect-fc-next/src/ScopeRegistry.ts b/packages/effect-fc-next/src/ScopeRegistry.ts new file mode 100644 index 0000000..cdd2035 --- /dev/null +++ b/packages/effect-fc-next/src/ScopeRegistry.ts @@ -0,0 +1,186 @@ +import { type Cause, Chunk, Context, DateTime, type Duration, Effect, Equal, Exit, HashMap, Layer, Option, Order, Predicate, Scope, Semaphore, Stream, SubscriptionRef } from "effect" + + +export const ScopeRegistryServiceTypeId: unique symbol = Symbol.for("@effect-view/ScopeRegistryService/ScopeRegistryService") +export type ScopeRegistryServiceTypeId = typeof ScopeRegistryServiceTypeId + +export interface ScopeRegistryService { + readonly [ScopeRegistryServiceTypeId]: ScopeRegistryServiceTypeId + readonly ref: SubscriptionRef.SubscriptionRef> + + register( + key: ScopeRegistryService.Key, + options: ScopeRegistryService.RegisterOptions, + ): Effect.Effect + commit(key: ScopeRegistryService.Key): Effect.Effect + release(key: ScopeRegistryService.Key): Effect.Effect + + readonly run: Effect.Effect +} + +export declare namespace ScopeRegistryService { + export type Key = object + + export interface RegisterOptions { + readonly finalizerExecutionStrategy: "sequential" | "parallel" + readonly finalizerExecutionDebounce: Duration.Input + readonly scopeCommitTimeout: Duration.Input + } + + export interface Entry { + readonly scope: Scope.Closeable + readonly expiresAt: Option.Option + readonly finalizerExecutionDebounce: Duration.Input + } +} + +export const isScopeRegistryService = (u: unknown): u is ScopeRegistryService => Predicate.hasProperty(u, ScopeRegistryServiceTypeId) +export const makeKey = (): ScopeRegistryService.Key => Equal.byReference({}) + + +export class ScopeRegistryServiceImpl implements ScopeRegistryService { + readonly [ScopeRegistryServiceTypeId]: ScopeRegistryServiceTypeId = ScopeRegistryServiceTypeId + + constructor( + readonly ref: SubscriptionRef.SubscriptionRef>, + readonly runSemaphore: Semaphore.Semaphore, + ) {} + + register( + key: ScopeRegistryService.Key, + options: ScopeRegistryService.RegisterOptions, + ): Effect.Effect { + return Effect.gen({ self: this }, function*() { + const entry = Equal.byReference({ + scope: yield* Scope.make(options.finalizerExecutionStrategy), + expiresAt: Option.some(DateTime.addDuration(yield* DateTime.now, options.scopeCommitTimeout)), + finalizerExecutionDebounce: options.finalizerExecutionDebounce, + }) + + yield* SubscriptionRef.update(this.ref, HashMap.set(key, entry)) + return entry + }) + } + + commit(key: ScopeRegistryService.Key): Effect.Effect { + return SubscriptionRef.get(this.ref).pipe( + Effect.map(HashMap.get(key)), + Effect.flatMap(Effect.fromOption), + Effect.map(entry => Equal.byReference({ + ...entry, + expiresAt: Option.none(), + })), + Effect.tap(entry => SubscriptionRef.update(this.ref, HashMap.set(key, entry))), + ) + } + + release(key: ScopeRegistryService.Key): Effect.Effect { + return SubscriptionRef.get(this.ref).pipe( + Effect.map(HashMap.get(key)), + Effect.flatMap(option => Effect.all([ + DateTime.now, + Effect.fromOption(option), + ])), + Effect.map(([now, entry]) => Equal.byReference({ + ...entry, + expiresAt: Option.some(DateTime.addDuration(now, entry.finalizerExecutionDebounce)), + })), + Effect.tap(entry => SubscriptionRef.update(this.ref, HashMap.set(key, entry))), + ) + } + + get run(): Effect.Effect { + return Effect.addFinalizer(() => this.dispose).pipe( + Effect.andThen(SubscriptionRef.changes(this.ref).pipe( + Stream.switchMap(entries => Option.match(this.getNextExpiration(entries), { + onNone: () => Stream.never, + onSome: expiresAt => Stream.fromEffect(DateTime.now.pipe( + Effect.flatMap(now => DateTime.isLessThan(now, expiresAt) + ? Effect.sleep(DateTime.distance(now, expiresAt)) + : Effect.void), + Effect.andThen(Effect.uninterruptible(this.closeExpired)), + )), + })), + Stream.runDrain, + )), + this.runSemaphore.withPermit, + ) + } + + get dispose(): Effect.Effect { + return SubscriptionRef.getAndSet( + this.ref, + HashMap.empty(), + ).pipe( + Effect.flatMap(entries => Effect.forEach( + HashMap.values(entries), + entry => Scope.close(entry.scope, Exit.void), + )), + Effect.asVoid, + ) + } + + get closeExpired(): Effect.Effect { + return Effect.flatMap(DateTime.now, now => SubscriptionRef.modify( + this.ref, + HashMap.reduce( + [ + Chunk.empty(), + HashMap.empty(), + ] as const, + + ([expired, remaining], entry, key) => Option.exists( + entry.expiresAt, + expiresAt => DateTime.isLessThanOrEqualTo(expiresAt, now), + ) + ? [Chunk.append(expired, entry), remaining] as const + : [expired, HashMap.set(remaining, key, entry)] as const, + ), + )).pipe( + Effect.flatMap(entries => Effect.forEach( + entries, + entry => Scope.close(entry.scope, Exit.void), + )), + Effect.asVoid, + ) + } + + getNextExpiration( + entries: HashMap.HashMap, + ): Option.Option { + return HashMap.reduce( + entries, + Option.none(), + (earliest, entry) => Option.match(entry.expiresAt, { + onNone: () => earliest, + onSome: expiresAt => Option.some(Option.match(earliest, { + onNone: () => expiresAt, + onSome: Order.min(DateTime.Order)(expiresAt), + })), + }), + ) + } +} + +export const make: Effect.Effect = Effect.gen(function*() { + return new ScopeRegistryServiceImpl( + yield* SubscriptionRef.make(HashMap.empty()), + yield* Semaphore.make(1), + ) +}) + + +/** + * Internal Effect service that maintains a registry of scopes associated with React component instances. + * + * This service is used internally by the `Component.useScope` hook to manage the lifecycle of component scopes, + * including tracking active scopes and coordinating their cleanup when components unmount or dependencies change. + */ +export class ScopeRegistry extends Context.Service()( + "@effect-view/ScopeRegistry/ScopeRegistry" +) {} + +export const layer = Layer.effect(ScopeRegistry, Effect.tap( + make, + registry => Effect.forkScoped(registry.run), +)) diff --git a/packages/effect-fc-next/src/SetStateAction.ts b/packages/effect-fc-next/src/SetStateAction.ts new file mode 100644 index 0000000..ee5db34 --- /dev/null +++ b/packages/effect-fc-next/src/SetStateAction.ts @@ -0,0 +1,12 @@ +import { Function } from "effect" +import type * as React from "react" + + +export const value: { + (self: React.SetStateAction, prevState: S): S + (prevState: S): (self: React.SetStateAction) => S +} = Function.dual(2, (self: React.SetStateAction, prevState: S): S => + typeof self === "function" + ? (self as (prevState: S) => S)(prevState) + : self +) diff --git a/packages/effect-fc-next/src/Stream.ts b/packages/effect-fc-next/src/Stream.ts new file mode 100644 index 0000000..35af3f4 --- /dev/null +++ b/packages/effect-fc-next/src/Stream.ts @@ -0,0 +1,33 @@ +import { Effect, Equivalence, Option, Stream } from "effect" +import * as React from "react" +import * as Component from "./Component.js" + + +export * from "effect/Stream" + +export const use: { + ( + stream: Stream.Stream + ): Effect.Effect, never, R> + , E, R>( + stream: Stream.Stream, + initialValue: A, + ): Effect.Effect, never, R> +} = Effect.fnUntraced(function* , E, R>( + stream: Stream.Stream, + initialValue?: A, +) { + const [reactStateValue, setReactStateValue] = React.useState(() => initialValue + ? Option.some(initialValue) + : Option.none() + ) + + yield* Component.useReactEffect(() => Effect.forkScoped( + Stream.runForEach( + Stream.changesWith(stream, Equivalence.strictEqual()), + v => Effect.sync(() => setReactStateValue(Option.some(v))), + ) + ), [stream]) + + return reactStateValue as Option.Some +}) diff --git a/packages/effect-fc-next/src/View.test.tsx b/packages/effect-fc-next/src/View.test.tsx new file mode 100644 index 0000000..4dbd72b --- /dev/null +++ b/packages/effect-fc-next/src/View.test.tsx @@ -0,0 +1,94 @@ +import { render, screen, waitFor } from "@testing-library/react" +import { Effect, Layer, SubscriptionRef } from "effect" +import { Lens } from "effect-lens" +import { describe, expect, it } from "vitest" +import * as Component from "./Component.js" +import * as ReactRuntime from "./ReactRuntime.js" +import * as View from "./View.js" + + +const makeRuntime = async () => { + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await runtime.runtime.context() + + return { + runtime, + effectRuntime, + dispose: () => runtime.runtime.dispose(), + } +} + +describe("View", () => { + it("useAll returns the latest values and rerenders when any input changes", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + const countRef = await Effect.runPromise(SubscriptionRef.make(1)) + const labelRef = await Effect.runPromise(SubscriptionRef.make("a")) + const count = Lens.fromSubscriptionRef(countRef) + const label = Lens.fromSubscriptionRef(labelRef) + + const Probe = Component.makeUntraced("ViewUseAllProbe")(function*() { + const [currentCount, currentLabel] = yield* View.useAll([count, label]) + + return

+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("1:a") + + await Effect.runPromise(Lens.set(count, 2)) + await screen.findByText("2:a") + + await Effect.runPromise(Lens.set(label, "b")) + await screen.findByText("2:b") + + view.unmount() + await dispose() + }) + + it("useAll respects the provided equivalence when processing updates", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + const itemRef = await Effect.runPromise(SubscriptionRef.make({ id: 1, label: "first" })) + const flagRef = await Effect.runPromise(SubscriptionRef.make(true)) + const item = Lens.fromSubscriptionRef(itemRef) + const flag = Lens.fromSubscriptionRef(flagRef) + + const Probe = Component.makeUntraced("ViewUseAllEquivalenceProbe")(function*() { + const [currentItem, currentFlag] = yield* View.useAll([item, flag], { + equivalence: ([selfItem, selfFlag], [thatItem, thatFlag]) => + selfItem.id === thatItem.id && selfFlag === thatFlag, + }) + + return
{`${currentItem.label}:${currentFlag ? "on" : "off"}`}
+ }).pipe( + Component.withContext(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first:on") + + await Effect.runPromise(Lens.set(item, { id: 1, label: "ignored" })) + await waitFor(() => expect(screen.getByText("first:on")).toBeTruthy()) + expect(screen.queryByText("ignored:on")).toBeNull() + + await Effect.runPromise(Lens.set(flag, false)) + await screen.findByText("ignored:off") + + await Effect.runPromise(Lens.set(item, { id: 2, label: "updated" })) + await screen.findByText("updated:off") + + view.unmount() + await dispose() + }) +}) diff --git a/packages/effect-fc-next/src/View.ts b/packages/effect-fc-next/src/View.ts new file mode 100644 index 0000000..e44d62a --- /dev/null +++ b/packages/effect-fc-next/src/View.ts @@ -0,0 +1,42 @@ +import { Effect, Equivalence, Stream } from "effect" +import { View } from "effect-lens" +import * as React from "react" +import * as Component from "./Component.js" + + +export * from "effect-lens/View" + +export declare namespace useAll { + export type Success[]> = [T[number]] extends [never] + ? never + : { [K in keyof T]: T[K] extends View.View ? A : never } + + export interface Options
{ + readonly equivalence?: Equivalence.Equivalence + } +} + +export const useAll = Effect.fnUntraced(function* []>( + elements: T, + options?: useAll.Options>>, +): Effect.fn.Return< + useAll.Success, + [T[number]] extends [never] ? never : T[number] extends View.View ? E : never, + [T[number]] extends [never] ? never : T[number] extends View.View ? R : never +> { + const [reactStateValue, setReactStateValue] = React.useState( + yield* Component.useOnMount(() => Effect.all(elements.map(View.get))) + ) + + yield* Component.useReactEffect(() => Stream.make(reactStateValue).pipe( + Stream.concat(View.changes(View.zipLatestAll(...elements))), + Stream.changesWith((options?.equivalence as Equivalence.Equivalence | undefined) ?? Equivalence.Array(Equivalence.strictEqual())), + Stream.drop(1), + Stream.runForEach(v => + Effect.sync(() => setReactStateValue(v)) + ), + Effect.forkScoped, + ), elements) + + return reactStateValue as any +}) diff --git a/packages/effect-fc-next/src/index.ts b/packages/effect-fc-next/src/index.ts new file mode 100644 index 0000000..a2d3bda --- /dev/null +++ b/packages/effect-fc-next/src/index.ts @@ -0,0 +1,17 @@ +export * as Async from "./Async.js" +export * as Component from "./Component.js" +export * as Form from "./Form.js" +export * as Lens from "./Lens.js" +export * as LensForm from "./LensForm.js" +export * as Memoized from "./Memoized.js" +export * as Mutation from "./Mutation.js" +export * as MutationForm from "./MutationForm.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 Refreshable from "./Refreshable.js" +export * as ScopeRegistry from "./ScopeRegistry.js" +export * as SetStateAction from "./SetStateAction.js" +export * as Stream from "./Stream.js" +export * as View from "./View.js" diff --git a/packages/effect-fc-next/src/setup-tests.ts b/packages/effect-fc-next/src/setup-tests.ts new file mode 100644 index 0000000..839583d --- /dev/null +++ b/packages/effect-fc-next/src/setup-tests.ts @@ -0,0 +1,4 @@ +import { configure } from "@testing-library/react" + + +configure({ reactStrictMode: true }) diff --git a/packages/effect-fc-next/tsconfig.build.json b/packages/effect-fc-next/tsconfig.build.json new file mode 100644 index 0000000..a79c9cd --- /dev/null +++ b/packages/effect-fc-next/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["**/setup-tests.ts", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"] +} diff --git a/packages/effect-fc-next/tsconfig.json b/packages/effect-fc-next/tsconfig.json new file mode 100644 index 0000000..f5ac024 --- /dev/null +++ b/packages/effect-fc-next/tsconfig.json @@ -0,0 +1,39 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "NodeNext", + "moduleDetection": "force", + "jsx": "react-jsx", + // "allowJs": true, + + // Bundler mode + "moduleResolution": "NodeNext", + // "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + // "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false, + + // Build + "rootDir": "./src", + "outDir": "./dist", + "declaration": true, + "sourceMap": true, + + "plugins": [ + { "name": "@effect/language-service" } + ] + }, + + "include": ["./src"], +} diff --git a/packages/effect-fc-next/vitest.config.ts b/packages/effect-fc-next/vitest.config.ts new file mode 100644 index 0000000..b59fb83 --- /dev/null +++ b/packages/effect-fc-next/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config" + + +export default defineConfig({ + test: { + environment: "jsdom", + include: ["./src/**/*.test.ts?(x)"], + setupFiles: ["./src/setup-tests.ts"], + }, +}) diff --git a/packages/effect-fc/README.md b/packages/effect-fc/README.md index d35c93d..4a9e717 100644 --- a/packages/effect-fc/README.md +++ b/packages/effect-fc/README.md @@ -42,7 +42,7 @@ export class TodosView extends Component.make("TodosView")(function*() { }) {} const Index = Component.make("IndexView")(function*() { - const context = yield* Component.useContextFromLayer(TodosState.Default) + const context = yield* Component.useLayer(TodosState.Default) const Todos = yield* Effect.provide(TodosView.use, context) return diff --git a/packages/effect-fc/package.json b/packages/effect-fc/package.json index 27d6a09..881729d 100644 --- a/packages/effect-fc/package.json +++ b/packages/effect-fc/package.json @@ -29,16 +29,20 @@ ] }, "scripts": { - "build": "tsc", - "lint:tsc": "tsc --noEmit", + "lint:tsc": "tsc -b --noEmit", "lint:biome": "biome lint", + "test": "vitest run", + "build": "tsc -b tsconfig.build.json", "pack": "npm pack", - "clean:cache": "rm -rf .turbo tsconfig.tsbuildinfo", + "clean:cache": "rm -rf .turbo *.tsbuildinfo", "clean:dist": "rm -rf dist", "clean:modules": "rm -rf node_modules" }, "devDependencies": { - "@effect/platform-browser": "^0.76.0" + "@effect/platform-browser": "^0.76.0", + "@testing-library/react": "^16.3.0", + "jsdom": "^26.1.0", + "vitest": "^3.2.4" }, "peerDependencies": { "@types/react": "^19.2.0", diff --git a/packages/effect-fc/src/Component.test.tsx b/packages/effect-fc/src/Component.test.tsx new file mode 100644 index 0000000..8ab9af1 --- /dev/null +++ b/packages/effect-fc/src/Component.test.tsx @@ -0,0 +1,354 @@ +import { render, screen, waitFor } from "@testing-library/react" +import { Context, Effect, Layer } from "effect" +import * as React from "react" +import { afterEach, describe, expect, it, vi } from "vitest" +import * as Component from "./Component.js" +import * as ReactRuntime from "./ReactRuntime.js" + + +class ValueService extends Context.Tag("ValueService")() {} + +afterEach(() => { + vi.useRealTimers() +}) + +describe("Component", () => { + it("runs useOnMount only once across rerenders", async () => { + const onMount = vi.fn(() => Effect.succeed("mounted")) + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await Effect.runPromise(runtime.runtime.runtimeEffect) + + const Probe = Component.makeUntraced("UseOnMountProbe")(function*() { + const value = yield* Component.useOnMount(onMount) + return
{value}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("mounted") + expect(onMount).toHaveBeenCalledTimes(1) + + view.rerender( + + + + ) + expect(await screen.findByText("mounted")).toBeTruthy() + expect(onMount).toHaveBeenCalledTimes(1) + + view.unmount() + await Effect.runPromise(runtime.runtime.disposeEffect) + }) + + it("recomputes useOnChange only when dependencies change", async () => { + const onChange = vi.fn((value: number) => Effect.succeed(`value:${value}`)) + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await Effect.runPromise(runtime.runtime.runtimeEffect) + + const Probe = Component.makeUntraced("UseOnChangeProbe")(function*(props: { readonly value: number }) { + const result = yield* Component.useOnChange(() => onChange(props.value), [props.value], { + finalizerExecutionDebounce: 0, + }) + + return
{result}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("value:1") + expect(onChange).toHaveBeenCalledTimes(1) + + view.rerender( + + + + ) + + expect(await screen.findByText("value:1")).toBeTruthy() + expect(onChange).toHaveBeenCalledTimes(1) + + view.rerender( + + + + ) + + await screen.findByText("value:2") + expect(onChange).toHaveBeenCalledTimes(2) + + view.unmount() + await Effect.runPromise(runtime.runtime.disposeEffect) + }) + + it("closes the previous scope on dependency changes and unmount", async () => { + const cleanup = vi.fn() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await Effect.runPromise(runtime.runtime.runtimeEffect) + + const Probe = Component.makeUntraced("ScopeCleanupProbe")(function*(props: { readonly value: string }) { + const result = yield* Component.useOnChange( + () => Effect.gen(function*() { + yield* Effect.addFinalizer(() => Effect.sync(() => cleanup(props.value))) + return props.value + }), + [props.value], + { finalizerExecutionDebounce: 0 }, + ) + + return
{result}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + expect(cleanup).not.toHaveBeenCalled() + + view.rerender( + + + + ) + + await screen.findByText("second") + await waitFor(() => expect(cleanup).toHaveBeenCalledWith("first")) + expect(cleanup).toHaveBeenCalledTimes(1) + + view.unmount() + + await waitFor(() => expect(cleanup).toHaveBeenCalledWith("second")) + expect(cleanup).toHaveBeenCalledTimes(2) + await Effect.runPromise(runtime.runtime.disposeEffect) + }) + + it("runs useReactEffect setup and cleanup when dependencies change", async () => { + const lifecycle = vi.fn<(message: string) => void>() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await Effect.runPromise(runtime.runtime.runtimeEffect) + + const Probe = Component.makeUntraced("UseReactEffectProbe")(function*(props: { readonly value: string }) { + yield* Component.useReactEffect(() => + Effect.gen(function*() { + yield* Effect.sync(() => lifecycle(`mount:${props.value}`)) + yield* Effect.addFinalizer(() => Effect.sync(() => lifecycle(`cleanup:${props.value}`))) + }), + [props.value]) + + return
{props.value}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + await waitFor(() => expect(lifecycle).toHaveBeenCalledWith("mount:first")) + + view.rerender( + + + + ) + + await screen.findByText("second") + await waitFor(() => expect(lifecycle).toHaveBeenCalledWith("cleanup:first")) + await waitFor(() => expect(lifecycle).toHaveBeenCalledWith("mount:second")) + + view.unmount() + + await waitFor(() => expect(lifecycle).toHaveBeenCalledWith("cleanup:second")) + expect(lifecycle.mock.calls.map(([message]) => message)).toEqual([ + "mount:first", + "cleanup:first", + "mount:second", + "cleanup:second", + ]) + await Effect.runPromise(runtime.runtime.disposeEffect) + }) + + it("keeps useCallbackSync stable until dependencies change", async () => { + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await Effect.runPromise(runtime.runtime.runtimeEffect) + const seenCallbacks: Array<(value: number) => string> = [] + + const Probe = Component.makeUntraced("UseCallbackSyncProbe")(function*(props: { readonly prefix: string }) { + const callback = yield* Component.useCallbackSync( + (value: number) => Effect.succeed(`${props.prefix}:${value}`), + [props.prefix], + ) + + yield* Component.useOnMount(() => Effect.sync(() => { + seenCallbacks.push(callback) + })) + + React.useEffect(() => { + seenCallbacks.push(callback) + }, [callback]) + + return
{callback(1)}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("a:1") + expect(seenCallbacks).toHaveLength(2) + expect(seenCallbacks[0]).toBe(seenCallbacks[1]) + expect(seenCallbacks[0]?.(2)).toBe("a:2") + + view.rerender( + + + + ) + + await screen.findByText("a:1") + expect(seenCallbacks).toHaveLength(2) + + view.rerender( + + + + ) + + await screen.findByText("b:1") + await waitFor(() => expect(seenCallbacks).toHaveLength(3)) + expect(seenCallbacks[2]).not.toBe(seenCallbacks[1]) + expect(seenCallbacks[2]?.(2)).toBe("b:2") + + view.unmount() + await Effect.runPromise(runtime.runtime.disposeEffect) + }) + + it("delays cleanup according to finalizerExecutionDebounce", async () => { + const cleanup = vi.fn() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await Effect.runPromise(runtime.runtime.runtimeEffect) + + const Probe = Component.makeUntraced("DebouncedCleanupProbe")(function*(props: { readonly value: string }) { + const result = yield* Component.useOnChange( + () => Effect.gen(function*() { + yield* Effect.addFinalizer(() => Effect.sync(() => cleanup(props.value))) + return props.value + }), + [props.value], + { finalizerExecutionDebounce: "20 millis" }, + ) + + return
{result}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + + view.rerender( + + + + ) + + await screen.findByText("second") + expect(cleanup).not.toHaveBeenCalled() + + await new Promise(resolve => setTimeout(resolve, 5)) + expect(cleanup).not.toHaveBeenCalled() + + await waitFor(() => expect(cleanup).toHaveBeenCalledWith("first"), { timeout: 100 }) + + view.unmount() + await waitFor(() => expect(cleanup).toHaveBeenCalledWith("second"), { timeout: 100 }) + await Effect.runPromise(runtime.runtime.disposeEffect) + }) + + it("does not remount a component when only nonReactiveTags change", async () => { + const mounts = vi.fn() + const unmounts = vi.fn() + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await Effect.runPromise(runtime.runtime.runtimeEffect) + + const SubComponent = Component.makeUntraced("NonReactiveSubComponent")(function*() { + const service = yield* ValueService + + yield* Component.useOnMount(() => Effect.gen(function*() { + yield* Effect.sync(() => mounts()) + yield* Effect.addFinalizer(() => Effect.sync(() => unmounts())) + })) + + return
{service.value}
+ }).pipe( + Component.withOptions({ nonReactiveTags: [ValueService] }) + ) + + const Parent = Component.makeUntraced("NonReactiveParent")(function*(props: { readonly value: string }) { + const serviceLayer = React.useMemo( + () => Layer.succeed(ValueService, { value: props.value }), + [props.value], + ) + const context = yield* Component.useLayer(serviceLayer, { + finalizerExecutionDebounce: 0, + }) + const Child = yield* Effect.provide(SubComponent.use, context) + + return + }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + expect(mounts).toHaveBeenCalledTimes(1) + expect(unmounts).not.toHaveBeenCalled() + + view.rerender( + + + + ) + + await screen.findByText("second") + expect(mounts).toHaveBeenCalledTimes(1) + expect(unmounts).not.toHaveBeenCalled() + + view.unmount() + await waitFor(() => expect(unmounts).toHaveBeenCalledTimes(1)) + await Effect.runPromise(runtime.runtime.disposeEffect) + }) +}) diff --git a/packages/effect-fc/src/Component.ts b/packages/effect-fc/src/Component.ts index ef54a5b..91df15e 100644 --- a/packages/effect-fc/src/Component.ts +++ b/packages/effect-fc/src/Component.ts @@ -1075,10 +1075,8 @@ export declare namespace useContext { * ```tsx * const MyLayer = Layer.succeed(MyService, new MyServiceImpl()) * const MyComponent = Component.make(function*() { - * const context = yield* Component.useContextFromLayer(MyLayer) - * const Sub = yield* SubComponent.use.pipe( - * Effect.provide(context) - * ) + * const context = yield* Component.useLayer(MyLayer) + * const Sub = yield* Effect.provide(SubComponent.use, context) * * return * }) @@ -1087,12 +1085,10 @@ export declare namespace useContext { * @example With memoized layer * ```tsx * const MyComponent = Component.make(function*(props: { id: string })) { - * const context = yield* Component.useContextFromLayer( + * const context = yield* Component.useLayer( * React.useMemo(() => Layer.succeed(MyService, new MyServiceImpl(props.id)), [props.id]) * ) - * const Sub = yield* SubComponent.use.pipe( - * Effect.provide(context) - * ) + * const Sub = yield* Effect.provide(SubComponent.use, context) * * return * }) @@ -1102,17 +1098,15 @@ export declare namespace useContext { * ```tsx * const MyAsyncLayer = Layer.effect(MyService, someAsyncEffect) * const MyComponent = Component.make(function*() { - * const context = yield* Component.useContextFromLayer(MyAsyncLayer) - * const Sub = yield* SubComponent.use.pipe( - * Effect.provide(context) - * ) + * const context = yield* Component.useLayer(MyAsyncLayer) + * const Sub = yield* Effect.provide(SubComponent.use, context) * * return * }).pipe( * Async.async // Required to handle async layer effects * ) */ -export const useContextFromLayer = ( +export const useLayer = ( layer: Layer.Layer, options?: useContext.Options, ): Effect.Effect, E, RIn | Scope.Scope> => useOnChange(() => Effect.context().pipe( diff --git a/packages/effect-fc/src/Lens.test.tsx b/packages/effect-fc/src/Lens.test.tsx new file mode 100644 index 0000000..e3cff38 --- /dev/null +++ b/packages/effect-fc/src/Lens.test.tsx @@ -0,0 +1,171 @@ +import { fireEvent, render, screen, waitFor } from "@testing-library/react" +import { Effect, Layer, SubscriptionRef } from "effect" +import * as React from "react" +import { describe, expect, it } from "vitest" +import * as Component from "./Component.js" +import * as Lens from "./Lens.js" +import * as ReactRuntime from "./ReactRuntime.js" + + +const makeRuntime = async () => { + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await Effect.runPromise(runtime.runtime.runtimeEffect) + + return { + runtime, + effectRuntime, + dispose: () => Effect.runPromise(runtime.runtime.disposeEffect), + } +} + +const expectDefined = (value: A | undefined): A => { + if (value === undefined) + throw new Error("Expected value to be defined") + return value +} + +describe("Lens", () => { + it("useState stays in sync with lens updates in both directions", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + const ref = await Effect.runPromise(SubscriptionRef.make(0)) + const lens = Lens.fromSubscriptionRef(ref) + + const Probe = Component.makeUntraced("LensUseStateProbe")(function*() { + const [value, setValue] = yield* Lens.useState(lens) + + return ( + <> +
{value}
+ + + ) + }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("0") + + await Effect.runPromise(Lens.set(lens, 5)) + await screen.findByText("5") + + fireEvent.click(screen.getByRole("button", { name: "increment" })) + await screen.findByText("6") + expect(await Effect.runPromise(Lens.get(lens))).toBe(6) + + view.unmount() + await dispose() + }) + + it("useState respects the provided equivalence when subscribing to lens changes", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + const ref = await Effect.runPromise(SubscriptionRef.make({ id: 1, label: "first" })) + const lens = Lens.fromSubscriptionRef(ref) + + const Probe = Component.makeUntraced("LensUseStateEquivalenceProbe")(function*() { + const [value] = yield* Lens.useState(lens, { + equivalence: (self, that) => self.id === that.id, + }) + + return
{value.label}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + + await Effect.runPromise(Lens.set(lens, { id: 1, label: "ignored" })) + await waitFor(() => expect(screen.getByText("first")).toBeTruthy()) + expect(screen.queryByText("ignored")).toBeNull() + + await Effect.runPromise(Lens.set(lens, { id: 2, label: "updated" })) + await screen.findByText("updated") + + view.unmount() + await dispose() + }) + + it("useFromReactState writes React state changes into the returned lens", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + let lens: Lens.Lens | undefined + + const Probe = Component.makeUntraced("LensUseFromReactStateProbe")(function*() { + const [value, setValue] = React.useState("hello") + const reactLens = yield* Lens.useFromReactState([value, setValue]) + + yield* Component.useOnMount(() => Effect.sync(() => { + lens = reactLens + })) + + return + }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("hello") + await waitFor(() => expect(lens).toBeDefined()) + + fireEvent.click(screen.getByRole("button", { name: "hello" })) + await screen.findByText("hello!") + await waitFor(async () => expect(await Effect.runPromise(Lens.get(expectDefined(lens)))).toBe("hello!")) + + view.unmount() + await dispose() + }) + + it("useFromReactState respects equivalence when lens updates flow back into React state", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + let lens: Lens.Lens<{ readonly id: number; readonly label: string }, never, never, never, never> | undefined + + const Probe = Component.makeUntraced("LensUseFromReactStateEquivalenceProbe")(function*() { + const [value, setValue] = React.useState({ id: 1, label: "first" }) + const reactLens = yield* Lens.useFromReactState([value, setValue], { + equivalence: (self, that) => self.id === that.id, + }) + + yield* Component.useOnMount(() => Effect.sync(() => { + lens = reactLens + })) + + return
{value.label}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first") + await waitFor(() => expect(lens).toBeDefined()) + + await Effect.runPromise(Lens.set(expectDefined(lens), { id: 1, label: "ignored" })) + await waitFor(() => expect(screen.getByText("first")).toBeTruthy()) + expect(screen.queryByText("ignored")).toBeNull() + + await Effect.runPromise(Lens.set(expectDefined(lens), { id: 2, label: "updated" })) + await screen.findByText("updated") + + view.unmount() + await dispose() + }) +}) diff --git a/packages/effect-fc/src/Query.test.ts b/packages/effect-fc/src/Query.test.ts new file mode 100644 index 0000000..c5d37be --- /dev/null +++ b/packages/effect-fc/src/Query.test.ts @@ -0,0 +1,169 @@ +import { Effect, Option, type Scope, Stream } from "effect" +import { describe, expect, it } from "vitest" +import * as Query from "./Query.js" +import * as QueryClient from "./QueryClient.js" +import * as Result from "./Result.js" + + +const runQueryTest = (effect: Effect.Effect) => + Effect.runPromise(Effect.scoped(effect.pipe( + Effect.provide(QueryClient.QueryClient.Default), + ))) + +const expectSuccessValue = ( + result: Result.Result, +): A => { + expect(Result.isSuccess(result)).toBe(true) + + if (!Result.isSuccess(result)) + throw new Error(`Expected Success result, received ${result._tag}`) + + return result.value +} + +const expectSomeValue =
(option: Option.Option): A => { + expect(Option.isSome(option)).toBe(true) + + if (!Option.isSome(option)) + throw new Error("Expected Some option, received None") + + return option.value +} + +describe("Query", () => { + it("fetch caches successful results until they are invalidated or stale", async () => { + let calls = 0 + const key = Stream.empty as Stream.Stream + + const result = await runQueryTest(Effect.gen(function*() { + const query = yield* Query.make({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "1 minute", + }) + + const first = yield* query.fetch([1]) + const second = yield* query.fetch([1]) + + return [first, second] as const + })) + + expect(calls).toBe(1) + expect(result[0]._tag).toBe("Success") + expect(result[1]._tag).toBe("Success") + expect(expectSuccessValue(result[0])).toBe("value:1:1") + expect(expectSuccessValue(result[1])).toBe("value:1:1") + }) + + it("refresh reruns the latest query key", async () => { + let calls = 0 + const key = Stream.empty as Stream.Stream + + const result = await runQueryTest(Effect.gen(function*() { + const query = yield* Query.make({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "0 millis", + }) + + const first = yield* query.fetch([1]) + yield* Effect.sleep("1 millis") + const refreshed = yield* query.refresh + + return [first, refreshed] as const + })) + + expect(calls).toBe(2) + expect(expectSuccessValue(result[0])).toBe("value:1:1") + expect(expectSuccessValue(result[1])).toBe("value:1:2") + }) + + it("invalidateCacheEntry forces the next fetch for that key to rerun", async () => { + let calls = 0 + const key = Stream.empty as Stream.Stream + + const result = await runQueryTest(Effect.gen(function*() { + const query = yield* Query.make({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "1 minute", + }) + + const first = yield* query.fetch([1]) + yield* query.invalidateCacheEntry([1]) + const second = yield* query.fetch([1]) + + return [first, second] as const + })) + + expect(calls).toBe(2) + expect(expectSuccessValue(result[0])).toBe("value:1:1") + expect(expectSuccessValue(result[1])).toBe("value:1:2") + }) + + it("invalidateCache clears cached entries for the query function", async () => { + let calls = 0 + const key = Stream.empty as Stream.Stream + + const result = await runQueryTest(Effect.gen(function*() { + const query = yield* Query.make({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "1 minute", + }) + + const first = yield* query.fetch([1]) + yield* query.invalidateCache + const second = yield* query.fetch([1]) + + return [first, second] as const + })) + + expect(calls).toBe(2) + expect(expectSuccessValue(result[0])).toBe("value:1:1") + expect(expectSuccessValue(result[1])).toBe("value:1:2") + }) + + it("service starts the key stream automatically and updates latest state", async () => { + let calls = 0 + const key = Stream.make([1] as const) as Stream.Stream + + const effect = Effect.gen(function*() { + const query = yield* Query.service({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "1 minute", + }) + + yield* Effect.sleep("10 millis") + + return { + final: yield* query.result.get, + latestKey: yield* query.latestKey.get, + latestFinalResult: yield* query.latestFinalResult.get, + } + }) + + const result = await runQueryTest(effect) + + expect(calls).toBe(1) + expect(expectSuccessValue(result.final)).toBe("value:1:1") + expect(expectSomeValue(result.latestKey)).toEqual([1]) + expect(expectSuccessValue(expectSomeValue(result.latestFinalResult))).toBe("value:1:1") + }) +}) diff --git a/packages/effect-fc/src/Subscribable.test.tsx b/packages/effect-fc/src/Subscribable.test.tsx new file mode 100644 index 0000000..c76132a --- /dev/null +++ b/packages/effect-fc/src/Subscribable.test.tsx @@ -0,0 +1,129 @@ +import { render, screen, waitFor } from "@testing-library/react" +import { Effect, Fiber, Layer, Stream, SubscriptionRef } from "effect" +import { Lens } from "effect-lens" +import { describe, expect, it } from "vitest" +import * as Component from "./Component.js" +import * as ReactRuntime from "./ReactRuntime.js" +import * as Subscribable from "./Subscribable.js" + + +const makeRuntime = async () => { + const runtime = ReactRuntime.make(Layer.empty) + const effectRuntime = await Effect.runPromise(runtime.runtime.runtimeEffect) + + return { + runtime, + effectRuntime, + dispose: () => Effect.runPromise(runtime.runtime.disposeEffect), + } +} + +describe("Subscribable", () => { + it("zipLatestAll reads current values from all inputs", async () => { + const leftRef = await Effect.runPromise(SubscriptionRef.make(1)) + const rightRef = await Effect.runPromise(SubscriptionRef.make("a")) + const left = Lens.fromSubscriptionRef(leftRef) + const right = Lens.fromSubscriptionRef(rightRef) + + const zipped = Subscribable.zipLatestAll(left, right) + + expect(await Effect.runPromise(zipped.get)).toEqual([1, "a"]) + }) + + it("zipLatestAll emits updates when any input changes", async () => { + const leftRef = await Effect.runPromise(SubscriptionRef.make(1)) + const rightRef = await Effect.runPromise(SubscriptionRef.make("a")) + const left = Lens.fromSubscriptionRef(leftRef) + const right = Lens.fromSubscriptionRef(rightRef) + + const zipped = Subscribable.zipLatestAll(left, right) + const values: Array = [] + + const collector = Effect.runFork(Effect.scoped(zipped.changes.pipe( + Stream.runForEach(value => Effect.sync(() => { + values.push(value as readonly [number, string]) + })), + ))) + + await Effect.runPromise(Lens.set(left, 2)) + await waitFor(() => expect(values).toContainEqual([2, "a"])) + + await Effect.runPromise(Lens.set(right, "b")) + await waitFor(() => expect(values).toContainEqual([2, "b"])) + + Fiber.interruptFork(collector) + }) + + it("useAll returns the latest values and rerenders when any input changes", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + const countRef = await Effect.runPromise(SubscriptionRef.make(1)) + const labelRef = await Effect.runPromise(SubscriptionRef.make("a")) + const count = Lens.fromSubscriptionRef(countRef) + const label = Lens.fromSubscriptionRef(labelRef) + + const Probe = Component.makeUntraced("SubscribableUseAllProbe")(function*() { + const [currentCount, currentLabel] = yield* Subscribable.useAll([count, label]) + + return
{`${currentCount}:${currentLabel}`}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("1:a") + + await Effect.runPromise(Lens.set(count, 2)) + await screen.findByText("2:a") + + await Effect.runPromise(Lens.set(label, "b")) + await screen.findByText("2:b") + + view.unmount() + await dispose() + }) + + it("useAll respects the provided equivalence when processing updates", async () => { + const { runtime, effectRuntime, dispose } = await makeRuntime() + const itemRef = await Effect.runPromise(SubscriptionRef.make({ id: 1, label: "first" })) + const flagRef = await Effect.runPromise(SubscriptionRef.make(true)) + const item = Lens.fromSubscriptionRef(itemRef) + const flag = Lens.fromSubscriptionRef(flagRef) + + const Probe = Component.makeUntraced("SubscribableUseAllEquivalenceProbe")(function*() { + const [currentItem, currentFlag] = yield* Subscribable.useAll([item, flag], { + equivalence: ([selfItem, selfFlag], [thatItem, thatFlag]) => + selfItem.id === thatItem.id && selfFlag === thatFlag, + }) + + return
{`${currentItem.label}:${currentFlag ? "on" : "off"}`}
+ }).pipe( + Component.withRuntime(runtime.context) + ) + + const view = render( + + + + ) + + await screen.findByText("first:on") + + await Effect.runPromise(Lens.set(item, { id: 1, label: "ignored" })) + await waitFor(() => expect(screen.getByText("first:on")).toBeTruthy()) + expect(screen.queryByText("ignored:on")).toBeNull() + + await Effect.runPromise(Lens.set(flag, false)) + await screen.findByText("ignored:off") + + await Effect.runPromise(Lens.set(item, { id: 2, label: "updated" })) + await screen.findByText("updated:off") + + view.unmount() + await dispose() + }) +}) diff --git a/packages/effect-fc/tsconfig.build.json b/packages/effect-fc/tsconfig.build.json new file mode 100644 index 0000000..a79c9cd --- /dev/null +++ b/packages/effect-fc/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["**/setup-tests.ts", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"] +} diff --git a/packages/effect-fc/tsconfig.json b/packages/effect-fc/tsconfig.json index 6ad0810..f5ac024 100644 --- a/packages/effect-fc/tsconfig.json +++ b/packages/effect-fc/tsconfig.json @@ -36,5 +36,4 @@ }, "include": ["./src"], - "exclude": ["**/*.test.ts", "**/*.spec.ts"] } diff --git a/packages/effect-fc/vitest.config.ts b/packages/effect-fc/vitest.config.ts new file mode 100644 index 0000000..75476d8 --- /dev/null +++ b/packages/effect-fc/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "vitest/config" + + +export default defineConfig({ + test: { + environment: "jsdom", + include: ["./src/**/*.test.ts?(x)"], + }, +}) diff --git a/packages/example-next/.gitignore b/packages/example-next/.gitignore new file mode 100644 index 0000000..a014dba --- /dev/null +++ b/packages/example-next/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +.tanstack diff --git a/packages/example-next/README.md b/packages/example-next/README.md new file mode 100644 index 0000000..aef5174 --- /dev/null +++ b/packages/example-next/README.md @@ -0,0 +1,10 @@ +# Effect FC Next Example + +Minimal React example for `effect-fc-next`, Effect V4, and `effect-lens@2`. + +```bash +bun run dev +``` + +The counter demonstrates a V4 `SubscriptionRef` exposed as an Effect Lens and +rendered through an Effect-FC component. diff --git a/packages/example-next/biome.json b/packages/example-next/biome.json new file mode 100644 index 0000000..77ba81c --- /dev/null +++ b/packages/example-next/biome.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://biomejs.dev/schemas/latest/schema.json", + "root": false, + "extends": "//", + "files": { + "includes": ["./src/**", "!src/routeTree.gen.ts"] + } +} diff --git a/packages/example-next/index.html b/packages/example-next/index.html new file mode 100644 index 0000000..e4b78ea --- /dev/null +++ b/packages/example-next/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/packages/example-next/package.json b/packages/example-next/package.json new file mode 100644 index 0000000..5e96b7a --- /dev/null +++ b/packages/example-next/package.json @@ -0,0 +1,41 @@ +{ + "name": "@effect-fc/example-next", + "version": "0.0.0", + "type": "module", + "private": true, + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "lint:tsc": "tsc -b --noEmit", + "lint:biome": "biome lint", + "preview": "vite preview", + "clean:cache": "rm -rf .turbo node_modules/.tmp node_modules/.vite* .tanstack", + "clean:dist": "rm -rf dist", + "clean:modules": "rm -rf node_modules" + }, + "devDependencies": { + "@effect-view/vite-plugin": "workspace:*", + "@tanstack/react-router": "^1.170.10", + "@tanstack/react-router-devtools": "^1.167.0", + "@tanstack/router-plugin": "^1.168.13", + "@types/react": "^19.2.15", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.2", + "globals": "^17.6.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "vite": "^8.0.16" + }, + "dependencies": { + "@effect/platform-browser": "4.0.0-beta.98", + "@radix-ui/themes": "^3.3.0", + "effect": "4.0.0-beta.98", + "effect-fc-next": "workspace:*", + "react-icons": "^5.6.0" + }, + "overrides": { + "@types/react": "^19.2.15", + "effect": "4.0.0-beta.98", + "react": "^19.2.6" + } +} diff --git a/.codex b/packages/example-next/src/index.css similarity index 100% rename from .codex rename to packages/example-next/src/index.css diff --git a/packages/example-next/src/lib/form/TextFieldFormInputView.tsx b/packages/example-next/src/lib/form/TextFieldFormInputView.tsx new file mode 100644 index 0000000..48241a9 --- /dev/null +++ b/packages/example-next/src/lib/form/TextFieldFormInputView.tsx @@ -0,0 +1,56 @@ +import { Callout, Flex, Spinner, TextField } from "@radix-ui/themes" +import { Array, Option, Struct } from "effect" +import { Component, Form, View } from "effect-fc-next" +import type * as React from "react" + + +export declare namespace TextFieldFormInputView { + export interface Props + extends Omit, Form.useInput.Options { + readonly form: Form.Form + } + + export type Signature =

(props: Props) => React.ReactNode +} + +export const TextFieldFormInputView = Component.make("TextFieldFormInputView")(function*( + props: TextFieldFormInputView.Props +) { + const input = yield* Form.useInput(props.form, props) + const [issues, isValidating, isCommitting] = yield* View.useAll([ + props.form.issues, + props.form.isValidating, + props.form.isCommitting, + ]) + + return ( + + input.setValue(e.target.value)} + disabled={isCommitting} + {...Struct.omit(props, ["form"])} + > + {isValidating && + + + + } + + {props.children} + + + {Option.match(Array.head(issues), { + onSome: issue => ( + + {issue.message} + + ), + + onNone: () => <>, + })} + + ) +}).pipe( + Component.withSignature() +) diff --git a/packages/example-next/src/lib/form/TextFieldOptionalFormInputView.tsx b/packages/example-next/src/lib/form/TextFieldOptionalFormInputView.tsx new file mode 100644 index 0000000..cd2bea4 --- /dev/null +++ b/packages/example-next/src/lib/form/TextFieldOptionalFormInputView.tsx @@ -0,0 +1,64 @@ +import { Callout, Flex, Spinner, Switch, TextField } from "@radix-ui/themes" +import { Array, Option, Struct } from "effect" +import { Component, Form, View } from "effect-fc-next" +import type * as React from "react" + + +export declare namespace TextFieldOptionalFormInputView { + export interface Props + extends Omit, Form.useOptionalInput.Options { + readonly form: Form.Form, ER, EW> + } + + export type Signature =

(props: Props) => React.ReactNode +} + +export const TextFieldOptionalFormInputView = Component.make("TextFieldOptionalFormInputView")(function*( + props: TextFieldOptionalFormInputView.Props +) { + const input = yield* Form.useOptionalInput(props.form, props) + const [issues, isValidating, isCommitting] = yield* View.useAll([ + props.form.issues, + props.form.isValidating, + props.form.isCommitting, + ]) + + return ( + + input.setValue(e.target.value)} + disabled={!input.enabled || isCommitting} + {...Struct.omit(props, ["form", "defaultValue"])} + > + + + + + {isValidating && + + + + } + + {props.children} + + + {Option.match(Array.head(issues), { + onSome: issue => ( + + {issue.message} + + ), + + onNone: () => <>, + })} + + ) +}).pipe( + Component.withSignature() +) diff --git a/packages/example-next/src/main.tsx b/packages/example-next/src/main.tsx new file mode 100644 index 0000000..1ed395f --- /dev/null +++ b/packages/example-next/src/main.tsx @@ -0,0 +1,21 @@ +import { createRouter, RouterProvider } from "@tanstack/react-router" +import { ReactRuntime } from "effect-fc-next" +import { StrictMode } from "react" +import { createRoot } from "react-dom/client" +import { routeTree } from "./routeTree.gen" +import { runtime } from "./runtime" + +const router = createRouter({ routeTree }) + +declare module "@tanstack/react-router" { + interface Register { router: typeof router } +} + +// biome-ignore lint/style/noNonNullAssertion: the Vite template provides this element +createRoot(document.getElementById("root")!).render( + + + + + , +) diff --git a/packages/example-next/src/routeTree.gen.ts b/packages/example-next/src/routeTree.gen.ts new file mode 100644 index 0000000..b70ab97 --- /dev/null +++ b/packages/example-next/src/routeTree.gen.ts @@ -0,0 +1,149 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// 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 IndexRouteImport } from './routes/index' +import { Route as AsyncRouteImport } from './routes/async' +import { Route as BlankRouteImport } from './routes/blank' +import { Route as FormRouteImport } from './routes/form' +import { Route as LensformRouteImport } from './routes/lensform' +import { Route as QueryRouteImport } from './routes/query' + +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const AsyncRoute = AsyncRouteImport.update({ + id: '/async', + path: '/async', + getParentRoute: () => rootRouteImport, +} as any) +const BlankRoute = BlankRouteImport.update({ + id: '/blank', + path: '/blank', + getParentRoute: () => rootRouteImport, +} as any) +const FormRoute = FormRouteImport.update({ + id: '/form', + path: '/form', + getParentRoute: () => rootRouteImport, +} as any) +const LensformRoute = LensformRouteImport.update({ + id: '/lensform', + path: '/lensform', + getParentRoute: () => rootRouteImport, +} as any) +const QueryRoute = QueryRouteImport.update({ + id: '/query', + path: '/query', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/async': typeof AsyncRoute + '/blank': typeof BlankRoute + '/form': typeof FormRoute + '/lensform': typeof LensformRoute + '/query': typeof QueryRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/async': typeof AsyncRoute + '/blank': typeof BlankRoute + '/form': typeof FormRoute + '/lensform': typeof LensformRoute + '/query': typeof QueryRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/async': typeof AsyncRoute + '/blank': typeof BlankRoute + '/form': typeof FormRoute + '/lensform': typeof LensformRoute + '/query': typeof QueryRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' | '/async' | '/blank' | '/form' | '/lensform' | '/query' + fileRoutesByTo: FileRoutesByTo + to: '/' | '/async' | '/blank' | '/form' | '/lensform' | '/query' + id: '__root__' | '/' | '/async' | '/blank' | '/form' | '/lensform' | '/query' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + AsyncRoute: typeof AsyncRoute + BlankRoute: typeof BlankRoute + FormRoute: typeof FormRoute + LensformRoute: typeof LensformRoute + QueryRoute: typeof QueryRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/async': { + id: '/async' + path: '/async' + fullPath: '/async' + preLoaderRoute: typeof AsyncRouteImport + parentRoute: typeof rootRouteImport + } + '/blank': { + id: '/blank' + path: '/blank' + fullPath: '/blank' + preLoaderRoute: typeof BlankRouteImport + parentRoute: typeof rootRouteImport + } + '/form': { + id: '/form' + path: '/form' + fullPath: '/form' + preLoaderRoute: typeof FormRouteImport + parentRoute: typeof rootRouteImport + } + '/lensform': { + id: '/lensform' + path: '/lensform' + fullPath: '/lensform' + preLoaderRoute: typeof LensformRouteImport + parentRoute: typeof rootRouteImport + } + '/query': { + id: '/query' + path: '/query' + fullPath: '/query' + preLoaderRoute: typeof QueryRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + AsyncRoute: AsyncRoute, + BlankRoute: BlankRoute, + FormRoute: FormRoute, + LensformRoute: LensformRoute, + QueryRoute: QueryRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/packages/example-next/src/routes/__root.tsx b/packages/example-next/src/routes/__root.tsx new file mode 100644 index 0000000..aba3a8d --- /dev/null +++ b/packages/example-next/src/routes/__root.tsx @@ -0,0 +1,32 @@ +import { Container, Flex, Theme } from "@radix-ui/themes" +import { createRootRoute, Link, Outlet } from "@tanstack/react-router" +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools" + +import "@radix-ui/themes/styles.css" +import "../index.css" + + +export const Route = createRootRoute({ + component: Root, +}) + +function Root() { + return ( + + + + Index + Blank + Async + Query + Form + LensForm + + + + + + + + ) +} diff --git a/packages/example-next/src/routes/async.tsx b/packages/example-next/src/routes/async.tsx new file mode 100644 index 0000000..45c12c2 --- /dev/null +++ b/packages/example-next/src/routes/async.tsx @@ -0,0 +1,77 @@ +import { Container, Flex, Heading, Slider, Text, TextField } from "@radix-ui/themes" +import { createFileRoute } from "@tanstack/react-router" +import { Console, Effect } from "effect" +import { Async, Component, Memoized } from "effect-fc-next" +import * as React from "react" +import { runtime } from "@/runtime" + + +const fetchPost = (id: number) => Effect.sleep("500 millis").pipe( + Effect.as({ + title: `Post ${id}`, + body: `This is the content of post ${id}.`, + }), +) + + +interface AsyncFetchPostViewProps { + readonly id: number +} + +const AsyncFetchPostView = Component.make("AsyncFetchPostView")(function*( + props: AsyncFetchPostViewProps, +) { + yield* Component.useOnMount(() => Effect.gen(function*() { + yield* Effect.addFinalizer(() => Console.log("AsyncFetchPostView unmounted")) + yield* Console.log("AsyncFetchPostView mounted") + })) + + const post = yield* Component.useOnChange( + () => fetchPost(props.id), + [props.id], + ) + + return ( +

+ {post.title} + {post.body} +
+ ) +}).pipe( + Async.async, + Async.withOptions({ defaultFallback: Loading post... }), + Memoized.memoized, +) + +const AsyncRouteComponent = Component.make("AsyncRouteView")(function*() { + const [text, setText] = React.useState("Typing here should not trigger a refetch of the post") + const [id, setId] = React.useState(1) + + const AsyncFetchPost = yield* AsyncFetchPostView.use + + return ( + + + setText(event.currentTarget.value)} + /> + + setId(value ?? 1)} + /> + + + + + ) +}).pipe( + Component.withContext(runtime.context), +) + +export const Route = createFileRoute("/async")({ + component: AsyncRouteComponent, +}) diff --git a/packages/example-next/src/routes/blank.tsx b/packages/example-next/src/routes/blank.tsx new file mode 100644 index 0000000..4f3c7df --- /dev/null +++ b/packages/example-next/src/routes/blank.tsx @@ -0,0 +1,10 @@ +import { createFileRoute } from "@tanstack/react-router" + + +export const Route = createFileRoute("/blank")({ + component: RouteComponent +}) + +function RouteComponent() { + return
Hello "/blank"!
+} diff --git a/packages/example-next/src/routes/form.tsx b/packages/example-next/src/routes/form.tsx new file mode 100644 index 0000000..38c9109 --- /dev/null +++ b/packages/example-next/src/routes/form.tsx @@ -0,0 +1,82 @@ +import { Button, Container, Flex, Text } from "@radix-ui/themes" +import { createFileRoute } from "@tanstack/react-router" +import { Console, Effect, Schema } from "effect" +import { Component, Form, MutationForm, View } from "effect-fc-next" +import { TextFieldFormInputView } from "@/lib/form/TextFieldFormInputView" +import { runtime } from "@/runtime" + + +const RegisterSchema = Schema.Struct({ + email: Schema.String.check( + Schema.isPattern(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, { + message: "Enter a valid email address", + }), + ), + password: Schema.String.check( + Schema.isMinLength(5, { + message: "Password must be at least 5 characters long", + }), + ), +}) + +const RegisterRouteComponent = Component.make("RegisterRouteView")(function*() { + yield* Component.useOnMount(() => Effect.gen(function*() { + yield* Effect.addFinalizer(() => Console.log("Form route unmounted")) + yield* Console.log("Form route mounted") + })) + + const [form, emailField, passwordField] = yield* Component.useOnMount(() => Effect.gen(function*() { + const form = yield* MutationForm.service({ + schema: RegisterSchema, + initialEncodedValue: { email: "", password: "" }, + f: ([value]) => Effect.log(`Registered ${value.email}`), + }) + + const emailField = Form.focusObjectOn(form, "email") + const passwordField = Form.focusObjectOn(form, "password") + + return [form, emailField, passwordField] as const + })) + + const [canCommit, isCommitting] = yield* View.useAll([ + form.canCommit, + form.isCommitting, + ]) + + const TextFieldFormInput = yield* TextFieldFormInputView.use + const runPromise = yield* Component.useRunPromise() + + + return ( + +
{ + event.preventDefault() + void runPromise(form.submit) + }}> + + + + + +
+ A MutationForm validates local input, then submits it. +
+ ) +}).pipe( + Component.withContext(runtime.context), +) + +export const Route = createFileRoute("/form")({ + component: RegisterRouteComponent, +}) diff --git a/packages/example-next/src/routes/index.tsx b/packages/example-next/src/routes/index.tsx new file mode 100644 index 0000000..7f98e30 --- /dev/null +++ b/packages/example-next/src/routes/index.tsx @@ -0,0 +1,56 @@ +import { Button, Container, Flex, Text, TextField } from "@radix-ui/themes" +import { createFileRoute } from "@tanstack/react-router" +import { Effect, SubscriptionRef } from "effect" +import { Component, Lens, View } from "effect-fc-next" +import { runtime } from "@/runtime" + + +const TodoRouteComponent = Component.make("TodoRouteView")(function*() { + const todosLens = yield* Component.useOnMount(() => Effect.map( + SubscriptionRef.make([]), + Lens.fromSubscriptionRef, + )) + const draftLens = yield* Component.useOnMount(() => Effect.map( + SubscriptionRef.make(""), + Lens.fromSubscriptionRef, + )) + + const [todos] = yield* View.useAll([todosLens]) + const [draft, setDraft] = yield* Lens.useState(draftLens) + const runPromise = yield* Component.useRunPromise() + + const addTodo = Lens.update(todosLens, todos => + draft.trim() === "" + ? todos + : [...todos, draft.trim()], + ).pipe( + Effect.andThen(Lens.set(draftLens, "")), + ) + + return ( + + + A small Effect v4 todo state example backed by a Lens. + + + setDraft(event.currentTarget.value)} + /> + + + + + {todos.map(todo => • {todo})} + + + ) +}).pipe( + Component.withContext(runtime.context), +) + +export const Route = createFileRoute("/")({ + component: TodoRouteComponent, +}) diff --git a/packages/example-next/src/routes/lensform.tsx b/packages/example-next/src/routes/lensform.tsx new file mode 100644 index 0000000..8b5b037 --- /dev/null +++ b/packages/example-next/src/routes/lensform.tsx @@ -0,0 +1,112 @@ +import { Container, Flex } from "@radix-ui/themes" +import { createFileRoute } from "@tanstack/react-router" +import { Console, Context, Effect, Layer, Schema, Stream, SubscriptionRef } from "effect" +import { Component, Form, Lens, LensForm } from "effect-fc-next" +import { TextFieldFormInputView } from "@/lib/form/TextFieldFormInputView" +import { runtime } from "@/runtime" + + +const UserProfileSchema = Schema.Struct({ + email: Schema.String.check( + Schema.isPattern(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, { + message: "Enter a valid email address", + }), + ), + password: Schema.String.check( + Schema.isMinLength(5, { + message: "Password must be at least 5 characters long", + }), + ), +}) + +const AppStateSchema = Schema.Struct({ + currentUser: UserProfileSchema, +}) + +class AppState extends Context.Service +}>()("AppState") { + static readonly layer = Layer.effect(AppState, Effect.gen(function*() { + return { + lens: Lens.fromSubscriptionRef( + yield* SubscriptionRef.make({ + currentUser: { + email: "", + password: "", + }, + }) + ), + } + })) +} + + +const LensFormPageView = Component.make("LensFormPageView")(function*() { + yield* Component.useOnMount(() => Effect.gen(function*() { + yield* Effect.addFinalizer(() => Console.log("LensForm route unmounted")) + yield* Console.log("LensForm route mounted") + })) + + const context = yield* Component.useLayer(AppState.layer) + const UserProfileEditor = yield* Effect.provide(UserProfileEditorView.use, context) + + return +}) + + +const UserProfileEditorView = Component.make("UserProfileEditorView")(function*() { + const appState = yield* AppState + + const [ + emailField, + passwordField, + ] = yield* Component.useOnMount(() => Effect.gen(function*() { + yield* Effect.forkScoped( + Stream.runForEach(Lens.changes(appState.lens), Console.log) + ) + + const form = yield* LensForm.service({ + schema: UserProfileSchema, + target: Lens.focusObjectOn(appState.lens, "currentUser"), + initialEncodedValue: { + email: "", + password: "", + }, + }) + + const emailField = Form.focusObjectOn(form, "email") + const passwordField = Form.focusObjectOn(form, "password") + + return [emailField, passwordField] as const + })) + + const TextFieldFormInput = yield* TextFieldFormInputView.use + + + return ( + +
{ + event.preventDefault() + }}> + + + + +
+
+ ) +}) + + +export const Route = createFileRoute("/lensform")({ + component: Component.withContext(LensFormPageView, runtime.context), +}) diff --git a/packages/example-next/src/routes/query.tsx b/packages/example-next/src/routes/query.tsx new file mode 100644 index 0000000..fd41ad8 --- /dev/null +++ b/packages/example-next/src/routes/query.tsx @@ -0,0 +1,102 @@ +import { Button, Container, Flex, Heading, Slider, Text } from "@radix-ui/themes" +import { createFileRoute } from "@tanstack/react-router" +import { Effect, Schema, SubscriptionRef } from "effect" +import { HttpClient } from "effect/unstable/http" +import { AsyncResult } from "effect/unstable/reactivity" +import { Component, Lens, Mutation, Query, View } from "effect-fc-next" +import { runtime } from "@/runtime" + + +const Post = Schema.Struct({ + userId: Schema.Int, + id: Schema.Int, + title: Schema.String, + body: Schema.String, +}) + + +interface PostResultViewProps { + readonly result: AsyncResult.AsyncResult +} + +const PostResultView = (props: PostResultViewProps) => AsyncResult.match(props.result, { + onInitial: result => result.waiting + ? Loading... + : No data., + onFailure: result => Request failed: { result.cause.toString() }, + onSuccess: result => <> + {result.waiting && Refreshing...} + {result.value.title} + {result.value.body} + , +}) + +const QueryRouteComponent = Component.make("QueryRouteView")(function*() { + const [idLens, query, mutation] = yield* Component.useOnMount(() => Effect.gen(function*() { + const keyLens = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(["post", 1 as number] as const)) + const idLens = Lens.focusTupleAt(keyLens, 1) + + const query = yield* Query.service({ + key: keyLens, + f: ([, id]) => HttpClient.HttpClient.pipe( + Effect.tap(Effect.sleep("1 second")), + Effect.andThen(client => client.get(`https://jsonplaceholder.typicode.com/posts/${ id }`)), + Effect.andThen(response => response.json), + Effect.andThen(Schema.decodeUnknownEffect(Post)), + ), + staleTime: "10 seconds", + }) + + const mutation = yield* Mutation.make({ + f: ([id]: [id: number]) => HttpClient.HttpClient.pipe( + Effect.tap(Effect.sleep("1 second")), + Effect.andThen(client => client.get(`https://jsonplaceholder.typicode.com/posts/${ id }`)), + Effect.andThen(response => response.json), + Effect.andThen(Schema.decodeUnknownEffect(Post)), + ), + }) + + return [idLens, query, mutation] as const + })) + + const [id, setId] = yield* Lens.useState(idLens) + const [queryState, mutationState] = yield* View.useAll([query.state, mutation.state]) + + const runSync = yield* Component.useRunSync() + + return ( + + + setId(value ?? 1)} + /> + + + + + + + + + + + + + + ) +}).pipe( + Component.withContext(runtime.context), +) + +export const Route = createFileRoute("/query")({ + component: QueryRouteComponent, +}) diff --git a/packages/example-next/src/runtime.ts b/packages/example-next/src/runtime.ts new file mode 100644 index 0000000..c50daee --- /dev/null +++ b/packages/example-next/src/runtime.ts @@ -0,0 +1,16 @@ +import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser" +import { DateTime, Layer } from "effect" +import { FetchHttpClient } from "effect/unstable/http" +import { QueryClient, ReactRuntime } from "effect-fc-next" + + +export const layer = Layer.empty.pipe( + Layer.provideMerge(QueryClient.layer()), + Layer.provideMerge(DateTime.layerCurrentZoneLocal), + Layer.provideMerge(Clipboard.layer), + Layer.provideMerge(Geolocation.layer), + Layer.provideMerge(Permissions.layer), + Layer.provideMerge(FetchHttpClient.layer), +) + +export const runtime = ReactRuntime.make(layer) diff --git a/packages/example-next/src/vite-env.d.ts b/packages/example-next/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/packages/example-next/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/example-next/tsconfig.app.json b/packages/example-next/tsconfig.app.json new file mode 100644 index 0000000..b823bd2 --- /dev/null +++ b/packages/example-next/tsconfig.app.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + "paths": { + "@/*": ["./src/*"] + }, + + "plugins": [ + { "name": "@effect/language-service" } + ] + }, + + "include": ["src"] +} diff --git a/packages/example-next/tsconfig.json b/packages/example-next/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/packages/example-next/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/packages/example-next/tsconfig.node.json b/packages/example-next/tsconfig.node.json new file mode 100644 index 0000000..0d067e8 --- /dev/null +++ b/packages/example-next/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + + "include": ["vite.config.ts"] +} diff --git a/packages/example-next/vite.config.ts b/packages/example-next/vite.config.ts new file mode 100644 index 0000000..45684ff --- /dev/null +++ b/packages/example-next/vite.config.ts @@ -0,0 +1,24 @@ +import { tanstackRouter } from "@tanstack/router-plugin/vite" +import react from "@vitejs/plugin-react" +import { effectViewPlugin } from "@effect-view/vite-plugin" +import path from "node:path" +import { defineConfig } from "vite" + + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + effectViewPlugin(), + tanstackRouter({ + target: "react", + autoCodeSplitting: true, + }), + react(), + ], + + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, +}) diff --git a/packages/example/package.json b/packages/example/package.json index e2b05c7..141145e 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -5,7 +5,7 @@ "private": true, "scripts": { "dev": "vite", - "lint:tsc": "tsc --noEmit", + "lint:tsc": "tsc -b --noEmit", "lint:biome": "biome lint", "preview": "vite preview", "clean:cache": "rm -rf .turbo node_modules/.tmp node_modules/.vite* .tanstack", diff --git a/packages/example/src/routes/dev/context.tsx b/packages/example/src/routes/dev/context.tsx index 26048a9..7e5e600 100644 --- a/packages/example/src/routes/dev/context.tsx +++ b/packages/example/src/routes/dev/context.tsx @@ -23,7 +23,7 @@ const SubComponent = Component.makeUntraced("SubComponent")(function*() { 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.use, yield* Component.useContextFromLayer(SubServiceLayer)) + const SubComponentFC = yield* Effect.provide(SubComponent.use, yield* Component.useLayer(SubServiceLayer)) return ( diff --git a/packages/example/src/routes/form.tsx b/packages/example/src/routes/form.tsx index 9ce3fae..cde4eda 100644 --- a/packages/example/src/routes/form.tsx +++ b/packages/example/src/routes/form.tsx @@ -129,7 +129,7 @@ class RegisterFormView extends Component.make("RegisterFormView")(function*() { const RegisterPage = Component.make("RegisterPageView")(function*() { const RegisterForm = yield* Effect.provide( RegisterFormView.use, - yield* Component.useContextFromLayer(RegisterFormService.Default), + yield* Component.useLayer(RegisterFormService.Default), ) return diff --git a/packages/example/src/routes/index.tsx b/packages/example/src/routes/index.tsx index d747b39..b4582f3 100644 --- a/packages/example/src/routes/index.tsx +++ b/packages/example/src/routes/index.tsx @@ -11,7 +11,7 @@ const TodosStateLive = TodosState.Default("todos") const Index = Component.make("IndexView")(function*() { const Todos = yield* Effect.provide( TodosView.use, - yield* Component.useContextFromLayer(TodosStateLive), + yield* Component.useLayer(TodosStateLive), ) return diff --git a/packages/example/tsconfig.app.json b/packages/example/tsconfig.app.json index 835427f..b823bd2 100644 --- a/packages/example/tsconfig.app.json +++ b/packages/example/tsconfig.app.json @@ -22,7 +22,6 @@ "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true, - "baseUrl": ".", "paths": { "@/*": ["./src/*"] }, diff --git a/packages/vite-plugin/README.md b/packages/vite-plugin/README.md new file mode 100644 index 0000000..8eb6160 --- /dev/null +++ b/packages/vite-plugin/README.md @@ -0,0 +1,41 @@ +# `@effect-view/vite-plugin` + +Experimental Vite Fast Refresh support for Effect View components. + +```ts +import { effectViewPlugin } from "@effect-view/vite-plugin" +import react from "@vitejs/plugin-react" +import { defineConfig } from "vite" + +export default defineConfig({ + plugins: [ + effectViewPlugin(), + react(), + ], +}) +``` + +The plugin recognizes `Component.make` and `Component.makeUntraced` +definitions imported from `effect-fc-next`. The legacy `effect-fc` package is +not supported. `effect-fc-next` owns the bundler-neutral refresh cell protocol; +this package is the Vite adapter that retains those cells in HMR data. The +plugin assigns stable development IDs and self-accepts successfully +instrumented modules. + +The adapter-facing protocol is exported from `effect-fc-next/Refreshable`. + +Renaming or removing an instrumented View invalidates the module upward instead +of leaving a stale mounted descriptor. + +React state is retained when the ordered hook signature is unchanged. Adding, +removing, or changing a hook call resets the Effect View implementation. Add +`// @refresh reset` to a module to reset its Views on every update. + +## Current limitations + +- Definitions must be top-level variable, class, or default-export + declarations. +- Hook signature analysis is conservative and based on `useX` call syntax. +- Changing a descriptor's trait pipeline during a refresh is not guaranteed to + preserve state. +- Source maps for the injected transform are not generated yet. diff --git a/packages/vite-plugin/biome.json b/packages/vite-plugin/biome.json new file mode 100644 index 0000000..41d707b --- /dev/null +++ b/packages/vite-plugin/biome.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://biomejs.dev/schemas/latest/schema.json", + "root": false, + "extends": "//", + "files": { + "includes": ["./src/**"] + } +} diff --git a/packages/vite-plugin/package.json b/packages/vite-plugin/package.json new file mode 100644 index 0000000..1fc14c6 --- /dev/null +++ b/packages/vite-plugin/package.json @@ -0,0 +1,47 @@ +{ + "name": "@effect-view/vite-plugin", + "description": "Vite Fast Refresh support for Effect View components", + "version": "0.0.1", + "type": "module", + "files": [ + "./README.md", + "./dist" + ], + "license": "MIT", + "repository": { + "url": "git+https://github.com/Thiladev/effect-fc.git" + }, + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./runtime": { + "types": "./dist/runtime.d.ts", + "default": "./dist/runtime.js" + } + }, + "scripts": { + "lint:tsc": "tsc -b --noEmit", + "lint:biome": "biome lint", + "test": "vitest run", + "build": "tsc -b tsconfig.build.json", + "pack": "npm pack", + "clean:cache": "rm -rf .turbo *.tsbuildinfo", + "clean:dist": "rm -rf dist", + "clean:modules": "rm -rf node_modules" + }, + "dependencies": { + "typescript": "^6.0.3" + }, + "devDependencies": { + "effect-fc-next": "workspace:*", + "vite": "^8.0.16", + "vitest": "^3.2.4" + }, + "peerDependencies": { + "effect-fc-next": "0.1.0-beta.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + } +} diff --git a/packages/vite-plugin/src/index.ts b/packages/vite-plugin/src/index.ts new file mode 100644 index 0000000..cd6db1a --- /dev/null +++ b/packages/vite-plugin/src/index.ts @@ -0,0 +1,435 @@ +import path from "node:path" +import ts from "typescript" +import type { Plugin } from "vite" + + +export interface EffectViewRefreshOptions { + /** + * Include filter for source files. + * + * @default /\.[cm]?[jt]sx?$/ + */ + readonly include?: RegExp + + /** + * Exclude filter for source files. + * + * @default /\/node_modules\// + */ + readonly exclude?: RegExp +} + +interface Edit { + readonly start: number + readonly end: number + readonly content: string +} + +interface ComponentImports { + readonly componentNamespaces: Set + readonly packageNamespaces: Set + readonly directFactories: Set +} + +interface Definition { + readonly expression: ts.Expression + readonly factoryCall: ts.CallExpression + readonly body: ts.FunctionLikeDeclaration | undefined + readonly id: string + readonly pipeline: ts.CallExpression | undefined + readonly entrypointIndex: number +} + +const defaultInclude = /\.[cm]?[jt]sx?$/ +const defaultExclude = /\/node_modules\// +const runtimeImport = "@effect-view/vite-plugin/runtime" +const refreshIdentifier = "__effectViewRefresh" +const acceptIdentifier = "__effectViewAccept" + +const isSupportedPackage = (source: string): boolean => + source === "effect-fc-next" + || source === "effect-fc-next/Component" + +const collectImports = ( + sourceFile: ts.SourceFile, +): ComponentImports => { + const componentNamespaces = new Set() + const packageNamespaces = new Set() + const directFactories = new Set() + + for (const statement of sourceFile.statements) { + if (!ts.isImportDeclaration(statement) + || !ts.isStringLiteral(statement.moduleSpecifier) + || !isSupportedPackage(statement.moduleSpecifier.text)) + continue + + const source = statement.moduleSpecifier.text + const clause = statement.importClause + if (!clause) + continue + + if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings)) { + if (source.endsWith("/Component")) + componentNamespaces.add(clause.namedBindings.name.text) + else + packageNamespaces.add(clause.namedBindings.name.text) + continue + } + + if (!clause.namedBindings || !ts.isNamedImports(clause.namedBindings)) + continue + + for (const element of clause.namedBindings.elements) { + const importedName = element.propertyName?.text ?? element.name.text + if (source.endsWith("/Component") && (importedName === "make" || importedName === "makeUntraced")) + directFactories.add(element.name.text) + else if (!source.endsWith("/Component") && importedName === "Component") + componentNamespaces.add(element.name.text) + } + } + + return { + componentNamespaces, + packageNamespaces, + directFactories, + } +} + +const isFactoryCallee = ( + expression: ts.Expression, + imports: ComponentImports, +): boolean => { + if (ts.isIdentifier(expression)) + return imports.directFactories.has(expression.text) + + if (!ts.isPropertyAccessExpression(expression)) + return false + + if (expression.name.text !== "make" && expression.name.text !== "makeUntraced") + return false + + if (ts.isIdentifier(expression.expression)) + return imports.componentNamespaces.has(expression.expression.text) + + return ts.isPropertyAccessExpression(expression.expression) + && expression.expression.name.text === "Component" + && ts.isIdentifier(expression.expression.expression) + && imports.packageNamespaces.has(expression.expression.expression.text) +} + +const functionArgument = ( + call: ts.CallExpression, +): ts.FunctionLikeDeclaration | undefined => call.arguments.find(argument => + ts.isArrowFunction(argument) + || ts.isFunctionExpression(argument) +) as ts.FunctionLikeDeclaration | undefined + +const findFactoryCall = ( + root: ts.Node, + imports: ComponentImports, +): { + readonly factoryCall: ts.CallExpression + readonly body: ts.FunctionLikeDeclaration | undefined +} | undefined => { + let result: { + readonly factoryCall: ts.CallExpression + readonly body: ts.FunctionLikeDeclaration | undefined + } | undefined + + const visit = (node: ts.Node): void => { + if (result) + return + + if (ts.isCallExpression(node)) { + if (isFactoryCallee(node.expression, imports)) { + result = { + factoryCall: node, + body: functionArgument(node), + } + return + } + + if (ts.isCallExpression(node.expression) && isFactoryCallee(node.expression.expression, imports)) { + result = { + factoryCall: node, + body: functionArgument(node), + } + return + } + } + + ts.forEachChild(node, visit) + } + + visit(root) + return result +} + +const isPipeline = (expression: ts.Expression): expression is ts.CallExpression => + ts.isCallExpression(expression) + && ts.isPropertyAccessExpression(expression.expression) + && expression.expression.name.text === "pipe" + +const isEntrypoint = (expression: ts.Expression): boolean => { + if (!ts.isCallExpression(expression)) + return false + + const callee = expression.expression + return ts.isPropertyAccessExpression(callee) + && (callee.name.text === "withRuntime" || callee.name.text === "withContext") +} + +const makeDefinition = ( + expression: ts.Expression, + id: string, + imports: ComponentImports, +): Definition | undefined => { + const factory = findFactoryCall(expression, imports) + if (!factory) + return undefined + + const pipeline = isPipeline(expression) ? expression : undefined + if (expression !== factory.factoryCall && !pipeline) + return undefined + + const entrypointIndex = pipeline + ? pipeline.arguments.findIndex(isEntrypoint) + : -1 + + return { + expression, + factoryCall: factory.factoryCall, + body: factory.body, + id, + pipeline, + entrypointIndex, + } +} + +const collectDefinitions = ( + sourceFile: ts.SourceFile, + imports: ComponentImports, + moduleId: string, +): readonly Definition[] => { + const definitions: Definition[] = [] + + for (const statement of sourceFile.statements) { + if (ts.isVariableStatement(statement)) { + for (const declaration of statement.declarationList.declarations) { + if (!declaration.initializer || !ts.isIdentifier(declaration.name)) + continue + const definition = makeDefinition( + declaration.initializer, + `${moduleId}:${declaration.name.text}`, + imports, + ) + if (definition) + definitions.push(definition) + } + continue + } + + if (ts.isClassDeclaration(statement) && statement.name) { + const heritage = statement.heritageClauses + ?.find(clause => clause.token === ts.SyntaxKind.ExtendsKeyword) + ?.types[0] + ?.expression + if (!heritage) + continue + const definition = makeDefinition( + heritage, + `${moduleId}:${statement.name.text}`, + imports, + ) + if (definition) + definitions.push(definition) + continue + } + + if (ts.isExportAssignment(statement)) { + const definition = makeDefinition( + statement.expression, + `${moduleId}:default`, + imports, + ) + if (definition) + definitions.push(definition) + } + } + + return definitions +} + +const hookSignature = ( + body: ts.FunctionLikeDeclaration | undefined, + sourceFile: ts.SourceFile, +): string => { + if (!body?.body) + return "unknown" + + const hooks: string[] = [] + const root = body.body + + const visit = (node: ts.Node): void => { + if (node !== root && ts.isFunctionLike(node)) + return + + if (ts.isCallExpression(node)) { + const callee = node.expression + const name = ts.isIdentifier(callee) + ? callee.text + : ts.isPropertyAccessExpression(callee) + ? callee.name.text + : undefined + + if (name && /^use[A-Z0-9]/.test(name)) + hooks.push(node.getText(sourceFile)) + } + + ts.forEachChild(node, visit) + } + + visit(root) + return hash(hooks.join("\n")) +} + +const hash = (value: string): string => { + let result = 0x811c9dc5 + for (let index = 0; index < value.length; index++) { + result ^= value.charCodeAt(index) + result = Math.imul(result, 0x01000193) + } + return (result >>> 0).toString(36) +} + +const quote = (value: string): string => JSON.stringify(value) + +const registration = ( + expression: string, + definition: Definition, + signature: string, + forceReset: boolean, +): string => `${refreshIdentifier}(${expression}, import.meta.hot, ${quote(definition.id)}, ${quote(signature)}, ${forceReset})` + +const applyEdits = (code: string, edits: readonly Edit[]): string => { + let output = code + for (const edit of [...edits].sort((self, that) => that.start - self.start)) + output = output.slice(0, edit.start) + edit.content + output.slice(edit.end) + return output +} + +const importPosition = (sourceFile: ts.SourceFile): number => { + let position = 0 + for (const statement of sourceFile.statements) { + if (ts.isImportDeclaration(statement)) + position = statement.end + else if (position > 0) + break + } + return position +} + +const scriptKind = (id: string): ts.ScriptKind => id.endsWith(".tsx") + ? ts.ScriptKind.TSX + : id.endsWith(".jsx") + ? ts.ScriptKind.JSX + : id.endsWith(".js") || id.endsWith(".mjs") || id.endsWith(".cjs") + ? ts.ScriptKind.JS + : ts.ScriptKind.TS + +/** + * Adds Fast Refresh support for Effect View components. + * + * Place this plugin before `@vitejs/plugin-react`. + */ +export function effectViewPlugin( + options: EffectViewRefreshOptions = {}, +): Plugin { + const include = options.include ?? defaultInclude + const exclude = options.exclude ?? defaultExclude + const instrumentedModules = new Set() + + return { + name: "effect-view:refresh", + enforce: "pre", + apply: "serve", + transform(code, rawId) { + const [id] = rawId.split("?", 1) + if (!id) + return null + if (!include.test(id) || exclude.test(id)) + return null + + const sourceFile = ts.createSourceFile( + id, + code, + ts.ScriptTarget.Latest, + true, + scriptKind(id), + ) + const imports = collectImports(sourceFile) + if (imports.componentNamespaces.size === 0 + && imports.packageNamespaces.size === 0 + && imports.directFactories.size === 0 + && !instrumentedModules.has(id)) + return null + + const moduleId = path.relative(process.cwd(), id).split(path.sep).join("/") + const definitions = collectDefinitions(sourceFile, imports, moduleId) + if (definitions.length === 0 && !instrumentedModules.has(id)) + return null + instrumentedModules.add(id) + + const forceReset = /@refresh\s+reset\b/.test(code) + const edits: Edit[] = [] + + for (const definition of definitions) { + const signature = hookSignature(definition.body, sourceFile) + + if (definition.pipeline && definition.entrypointIndex >= 0) { + const entrypoint = definition.pipeline.arguments[definition.entrypointIndex] + if (!entrypoint) + continue + edits.push({ + start: entrypoint.getStart(sourceFile), + end: entrypoint.getStart(sourceFile), + content: `(${refreshIdentifier}View) => ${registration( + `${refreshIdentifier}View`, + definition, + signature, + forceReset, + )}, `, + }) + continue + } + + const start = definition.expression.getStart(sourceFile) + const end = definition.expression.end + edits.push({ + start, + end, + content: registration( + code.slice(start, end), + definition, + signature, + forceReset, + ), + }) + } + + const position = importPosition(sourceFile) + edits.push({ + start: position, + end: position, + content: `${position === 0 ? "" : "\n"}import { accept as ${acceptIdentifier}, register as ${refreshIdentifier} } from ${quote(runtimeImport)};\n`, + }) + + const transformed = applyEdits(code, edits) + const definitionIds = definitions.map(definition => quote(definition.id)).join(", ") + return { + code: `${transformed}\n${acceptIdentifier}(import.meta.hot, [${definitionIds}])\n`, + map: null, + } + }, + } +} diff --git a/packages/vite-plugin/src/plugin.test.ts b/packages/vite-plugin/src/plugin.test.ts new file mode 100644 index 0000000..822391f --- /dev/null +++ b/packages/vite-plugin/src/plugin.test.ts @@ -0,0 +1,138 @@ +import path from "node:path" +import type { Plugin } from "vite" +import { describe, expect, it } from "vitest" +import { effectViewPlugin } from "./index.js" + + +type TransformHook = Extract< + NonNullable, + (...args: never[]) => unknown +> +type TransformPluginContext = ThisParameterType + +const runTransform = async ( + plugin: Plugin, + code: string, + id: string, +): Promise => { + const hook = plugin.transform + if (!hook) + return undefined + + const result = typeof hook === "function" + ? await hook.call({} as TransformPluginContext, code, id) + : await hook.handler.call({} as TransformPluginContext, code, id) + + if (!result) + return undefined + return typeof result === "string" ? result : result.code?.toString() +} + +const transform = ( + code: string, + id = path.join(process.cwd(), "src/View.tsx"), +): Promise => runTransform(effectViewPlugin(), code, id) + +describe("effectViewPlugin", () => { + it("wraps a const Effect View descriptor", async () => { + const result = await transform(` +import { Component } from "effect-fc-next" +import * as React from "react" + +export const CounterView = Component.make("CounterView")(function*() { + const [count] = React.useState(0) + return
{count}
+}) +`) + + expect(result).toContain("import { accept as __effectViewAccept, register as __effectViewRefresh } from \"@effect-view/vite-plugin/runtime\"") + expect(result).toContain("__effectViewRefresh(Component.make(\"CounterView\")") + expect(result).toContain("\"src/View.tsx:CounterView\"") + expect(result).toContain("__effectViewAccept(import.meta.hot, [\"src/View.tsx:CounterView\"])") + }) + + it("registers a pipeline before withContext", async () => { + const result = await transform(` +import { Component } from "effect-fc-next" + +const Page = Component.make("Page")(function*() { + return
+}).pipe( + Component.withContext(runtime.context), +) +`) + + expect(result).toContain("(__effectViewRefreshView) => __effectViewRefresh(__effectViewRefreshView") + expect(result).toContain("Component.withContext(runtime.context)") + expect(result).not.toContain("__effectViewRefresh(Component.make(\"Page\")") + }) + + it("wraps a class's complete trait pipeline", async () => { + const result = await transform(` +import { Async, Component, Memoized } from "effect-fc-next" + +class PostView extends Component.make("PostView")(function*() { + const value = yield* Component.useOnMount(load) + return
{value}
+}).pipe( + Async.async, + Memoized.memoized, +) {} +`) + + expect(result).toContain("class PostView extends __effectViewRefresh(Component.make(\"PostView\")") + expect(result).toContain("Memoized.memoized,") + expect(result).toContain("\"src/View.tsx:PostView\"") + }) + + it("supports aliased Component imports and refresh reset", async () => { + const result = await transform(` +// @refresh reset +import { Component as View } from "effect-fc-next" + +const Probe = View.makeUntraced(function*() { + return null +}) +`) + + expect(result).toContain("__effectViewRefresh(View.makeUntraced") + expect(result).toMatch(/"src\/View\.tsx:Probe", "[a-z0-9]+", true/) + }) + + it("ignores modules without Effect View definitions", async () => { + expect(await transform(` +import * as React from "react" +export function View() { + return
+} +`)).toBeUndefined() + }) + + it("keeps instrumenting a module when all Effect Views are removed", async () => { + const plugin = effectViewPlugin() as Plugin + const id = path.join(process.cwd(), "src/Removed.tsx") + + await runTransform(plugin, ` +import { Component } from "effect-fc-next" +export const Probe = Component.makeUntraced(function*() { + return null +}) +`, id) + + const result = await runTransform(plugin, ` +export const value = 1 +`, id) + + expect(result).toContain("__effectViewAccept(import.meta.hot, [])") + expect(result).not.toContain("__effectViewRefresh(") + }) + + it("ignores the legacy effect-fc package", async () => { + expect(await transform(` +import { Component } from "effect-fc" +export const Legacy = Component.makeUntraced(function*() { + return null +}) +`)).toBeUndefined() + }) +}) diff --git a/packages/vite-plugin/src/runtime.test.ts b/packages/vite-plugin/src/runtime.test.ts new file mode 100644 index 0000000..da5745b --- /dev/null +++ b/packages/vite-plugin/src/runtime.test.ts @@ -0,0 +1,78 @@ +import type * as Component from "effect-fc-next/Component" +import * as Refreshable from "effect-fc-next/Refreshable" +import { describe, expect, it, vi } from "vitest" +import { accept, register } from "./runtime.js" + + +describe("refresh runtime", () => { + const component = (value: A): A & Component.Component.Any => + value as A & Component.Component.Any + + const refreshCell = (value: Component.Component.Any): Refreshable.Cell => { + if (!Refreshable.isRefreshable(value)) + throw new Error("Expected a refreshable component") + return value[Refreshable.RefreshableTypeId] + } + + it("retains a cell and notifies subscribers for compatible updates", async () => { + const hot = { + data: {}, + accept: vi.fn(), + invalidate: vi.fn(), + } + const first = register(component({ body: "first" }), hot, "module:View", "hooks") + const cell = refreshCell(first) + const listener = vi.fn() + cell.subscribe(listener) + + const second = register(component({ body: "second" }), hot, "module:View", "hooks") + const secondCell = refreshCell(second) + + expect(secondCell).toBe(cell) + expect(cell.current).toBe(second) + expect(cell.snapshot).toEqual({ + revision: 1, + resetRevision: 0, + }) + + await Promise.resolve() + expect(listener).toHaveBeenCalledTimes(1) + }) + + it("increments resetRevision for incompatible and forced updates", () => { + const hot = { + data: {}, + accept: vi.fn(), + invalidate: vi.fn(), + } + const first = register(component({}), hot, "module:View", "one") + const cell = refreshCell(first) + + register(component({}), hot, "module:View", "two") + expect(cell.snapshot.resetRevision).toBe(1) + + register(component({}), hot, "module:View", "two", true) + expect(cell.snapshot.resetRevision).toBe(2) + }) + + it("is inert outside a Vite hot context", () => { + const descriptor = component({}) + expect(register(descriptor, undefined, "module:View", "hooks")).toBe(descriptor) + expect(Refreshable.isRefreshable(descriptor)).toBe(false) + }) + + it("invalidates when the module's View IDs change", () => { + const hot = { + data: {}, + accept: vi.fn(), + invalidate: vi.fn(), + } + + accept(hot, ["module:First"]) + expect(hot.accept).toHaveBeenCalledTimes(1) + expect(hot.invalidate).not.toHaveBeenCalled() + + accept(hot, ["module:Second"]) + expect(hot.invalidate).toHaveBeenCalledWith("[effect-view] Effect View exports changed") + }) +}) diff --git a/packages/vite-plugin/src/runtime.ts b/packages/vite-plugin/src/runtime.ts new file mode 100644 index 0000000..a6faa36 --- /dev/null +++ b/packages/vite-plugin/src/runtime.ts @@ -0,0 +1,86 @@ +import type * as Component from "effect-fc-next/Component" +import * as Refreshable from "effect-fc-next/Refreshable" + +export interface HotContext { + readonly data: Record + accept(): void + invalidate(message?: string): void +} + +interface RefreshData { + readonly cells: Map + ids?: readonly string[] +} + +const hotDataKey = "__effectViewRefresh" + +const getRefreshData = (hot: HotContext): RefreshData => { + const data = hot.data as Record + const current = data[hotDataKey] as RefreshData | undefined + if (current) + return current + + const refreshData: RefreshData = { + cells: new Map(), + } + data[hotDataKey] = refreshData + return refreshData +} + +/** + * Registers an Effect View descriptor in a Vite HMR data cell. + * + * This API is injected by `@effect-view/vite-plugin`; applications should not need to + * call it directly. + */ +export const register = ( + component: A, + hot: HotContext | undefined, + id: string, + signature: string, + forceReset = false, +): A => { + if (!hot) + return component + + const refreshData = getRefreshData(hot) + const previous = refreshData.cells.get(id) + if (!previous) { + const cell = Refreshable.makeCell(component, signature, forceReset) + refreshData.cells.set(id, cell) + return Refreshable.attach(component, cell) + } + + previous.update(component, signature, forceReset) + return Refreshable.attach(component, previous) +} + +const sameIds = ( + self: readonly string[], + that: readonly string[], +): boolean => self.length === that.length + && self.every((id, index) => id === that[index]) + +/** + * Accepts an instrumented module when its Effect View definition set is + * unchanged. Renames and removals invalidate upward so a stale cell cannot + * remain mounted indefinitely. + */ +export const accept = ( + hot: HotContext | undefined, + ids: readonly string[], +): void => { + if (!hot) + return + + const refreshData = getRefreshData(hot) + const previousIds = refreshData.ids + refreshData.ids = ids + + if (previousIds && !sameIds(previousIds, ids)) { + hot.invalidate("[effect-view] Effect View exports changed") + return + } + + hot.accept() +} diff --git a/packages/vite-plugin/tsconfig.build.json b/packages/vite-plugin/tsconfig.build.json new file mode 100644 index 0000000..a79c9cd --- /dev/null +++ b/packages/vite-plugin/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["**/setup-tests.ts", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"] +} diff --git a/packages/vite-plugin/tsconfig.json b/packages/vite-plugin/tsconfig.json new file mode 100644 index 0000000..f5ac024 --- /dev/null +++ b/packages/vite-plugin/tsconfig.json @@ -0,0 +1,39 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "NodeNext", + "moduleDetection": "force", + "jsx": "react-jsx", + // "allowJs": true, + + // Bundler mode + "moduleResolution": "NodeNext", + // "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + // "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false, + + // Build + "rootDir": "./src", + "outDir": "./dist", + "declaration": true, + "sourceMap": true, + + "plugins": [ + { "name": "@effect/language-service" } + ] + }, + + "include": ["./src"], +} diff --git a/packages/vite-plugin/vitest.config.ts b/packages/vite-plugin/vitest.config.ts new file mode 100644 index 0000000..a5cdb63 --- /dev/null +++ b/packages/vite-plugin/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config" + + +export default defineConfig({ + test: { + include: ["./src/**/*.test.ts?(x)"], + }, +}) diff --git a/turbo.json b/turbo.json index 75a43f8..6a2ee39 100644 --- a/turbo.json +++ b/turbo.json @@ -3,11 +3,15 @@ "tasks": { "lint:tsc": { + "dependsOn": ["^build"], "cache": false }, "lint:biome": { "cache": false }, + "test": { + "cache": false + }, "build": { "dependsOn": ["^build"], "inputs": ["./src/**"],

, + ) { + return React.memo(f, this.propsEquivalence) + }, +} as const) + + +export const isMemoized = (u: unknown): u is Memoized => Predicate.hasProperty(u, MemoizedTypeId) + +/** + * Converts a Component into a `Memoized` component that optimizes re-renders using `React.memo`. + * + * @param self - The component to convert to a Memoized component + * @returns A new `Memoized` component with the same body, error, and context types as the input + * + * @example + * ```ts + * const MyMemoizedComponent = MyComponent.pipe( + * Memoized.memoized, + * ) + * ``` + */ +export const memoized = ( + self: T +): T & Memoized> => Object.setPrototypeOf( + Object.assign(function() {}, self), + Object.freeze(Object.setPrototypeOf( + Object.assign({}, MemoizedPrototype), + Object.getPrototypeOf(self), + )), +) + +/** + * Applies options to a Memoized component, returning a new Memoized component with the updated configuration. + * + * Supports both curried and uncurried application styles. + * + * @param self - The Memoized component to apply options to (in uncurried form) + * @param options - The options to apply to the component + * @returns A Memoized component with the applied options + * + * @example + * ```ts + * // Curried + * const MyMemoizedComponent = MyComponent.pipe( + * Memoized.memoized, + * Memoized.withOptions({ propsEquivalence: (a, b) => a.id === b.id }), + * ) + * + * // Uncurried + * const MyMemoizedComponent = Memoized.withOptions( + * Memoized.memoized(MyComponent), + * { propsEquivalence: (a, b) => a.id === b.id }, + * ) + * ``` + */ +export const withOptions: { + >( + options: Partial>> + ): (self: T) => T + >( + self: T, + options: Partial>>, + ): T +} = Function.dual(2, >( + self: T, + options: Partial>>, +): T => Object.setPrototypeOf( + Object.assign(function() {}, self, options), + Object.getPrototypeOf(self), +)) diff --git a/packages/effect-fc-next/src/Mutation.ts b/packages/effect-fc-next/src/Mutation.ts new file mode 100644 index 0000000..3e13174 --- /dev/null +++ b/packages/effect-fc-next/src/Mutation.ts @@ -0,0 +1,153 @@ +import { type Context, Effect, Equal, Exit, type Fiber, Option, Pipeable, Predicate, type Scope, Stream, SubscriptionRef } from "effect" +import { AsyncResult } from "effect/unstable/reactivity" +import * as Lens from "./Lens.js" +import * as View from "./View.js" + + +export const MutationTypeId: unique symbol = Symbol.for("@effect-fc/Mutation/Mutation") +export type MutationTypeId = typeof MutationTypeId + +export interface Mutation +extends Pipeable.Pipeable { + readonly [MutationTypeId]: MutationTypeId + + readonly context: Context.Context + readonly f: (key: K) => Effect.Effect + + readonly latestKey: View.View> + readonly fiber: View.View>> + readonly state: View.View> + readonly latestFinalResult: View.View | AsyncResult.Failure>> + + mutate(key: K): Effect.Effect | AsyncResult.Failure> + mutateView(key: K): Effect.Effect>> +} + +export const isMutation = (u: unknown): u is Mutation => Predicate.hasProperty(u, MutationTypeId) + + +export class MutationImpl +extends Pipeable.Class implements Mutation { + readonly [MutationTypeId]: MutationTypeId = MutationTypeId + + constructor( + readonly context: Context.Context, + readonly f: (key: K) => Effect.Effect, + + readonly latestKey: Lens.Lens>, + readonly fiber: Lens.Lens>>, + readonly state: Lens.Lens>, + readonly latestFinalResult: Lens.Lens | AsyncResult.Failure>>, + ) { + super() + } + + mutate(key: K): Effect.Effect | AsyncResult.Failure> { + return Lens.set(this.latestKey, Option.some(key)).pipe( + Effect.andThen(this.start(key)), + Effect.flatMap(state => this.watch(state)), + Effect.provide(this.context), + ) + } + mutateView(key: K): Effect.Effect>> { + return Lens.set(this.latestKey, Option.some(key)).pipe( + Effect.andThen(this.start(key)), + Effect.tap(state => Effect.forkScoped(this.watch(state))), + Effect.provide(this.context), + ) + } + + start(key: K): Effect.Effect< + View.View>, + never, + Scope.Scope | R + > { + return Effect.gen({ self: this }, function*() { + const previous = yield* Lens.get(this.latestFinalResult) + const state = Lens.fromSubscriptionRef(yield* SubscriptionRef.make>( + Option.getOrElse(previous, () => AsyncResult.initial(false)) + )) + + const fiber = yield* Effect.forkScoped(Effect.andThen( + Lens.update(state, AsyncResult.match({ + onInitial: () => AsyncResult.initial(true), + onSuccess: v => AsyncResult.success(v.value, { + waiting: true, + }), + onFailure: v => AsyncResult.failure(v.cause, { + waiting: true, + previousSuccess: v.previousSuccess, + }) + })), + + Effect.onExit(this.f(key), exit => Lens.update( + state, + previous => Exit.match(exit, { + onSuccess: v => AsyncResult.success(v), + onFailure: c => AsyncResult.match(previous, { + onInitial: () => AsyncResult.failure(c), + onSuccess: v => AsyncResult.failure(c, { + previousSuccess: Option.some(v), + }), + onFailure: v => AsyncResult.failure(c, { + previousSuccess: v.previousSuccess, + }) + }), + }), + ).pipe( + Effect.andThen(Effect.all([ + Effect.fiberId, + Lens.get(this.fiber), + ])), + Effect.flatMap(([fiberId, fiber]) => Option.match(fiber, { + onSome: v => Equal.equals(fiberId, v.id) + ? Lens.set(this.fiber, Option.none()) + : Effect.void, + onNone: () => Effect.void, + })), + )), + )) + + yield* Lens.set(this.fiber, Option.some(fiber)) + return state + }) + } + + watch( + state: View.View> + ): Effect.Effect | AsyncResult.Failure> { + return View.get(state).pipe( + Effect.andThen(initial => Stream.runFoldEffect( + View.changes(state), + () => initial, + (_, result) => Effect.as(Lens.set(this.state, result), result), + ) as Effect.Effect | AsyncResult.Failure>), + Effect.tap(result => Lens.set(this.latestFinalResult, Option.some(result))), + ) + } +} + + +export declare namespace make { + export interface Options { + readonly f: (key: K) => Effect.Effect + } +} + +export const make = Effect.fnUntraced(function* ( + options: make.Options +): Effect.fn.Return< + Mutation, + never, + Scope.Scope | R +> { + return new MutationImpl( + yield* Effect.context(), + options.f, + + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none())), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none>())), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make>(AsyncResult.initial())), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none | AsyncResult.Failure>())), + ) +}) diff --git a/packages/effect-fc-next/src/MutationForm.ts b/packages/effect-fc-next/src/MutationForm.ts new file mode 100644 index 0000000..55d5ebc --- /dev/null +++ b/packages/effect-fc-next/src/MutationForm.ts @@ -0,0 +1,213 @@ +import type { StandardSchemaV1 } from "@standard-schema/spec" +import { Array, Cause, type Context, Effect, Fiber, Option, Pipeable, Predicate, Schema, SchemaError, SchemaIssue, type Scope, Semaphore, SubscriptionRef } from "effect" +import { AsyncResult } from "effect/unstable/reactivity" +import * as Form from "./Form.js" +import * as Lens from "./Lens.js" +import * as Mutation from "./Mutation.js" +import * as View from "./View.js" + + +export const MutationFormTypeId: unique symbol = Symbol.for("@effect-fc/Form/MutationForm") +export type MutationFormTypeId = typeof MutationFormTypeId + +export interface MutationForm +extends Form.Form { + readonly [MutationFormTypeId]: MutationFormTypeId + + readonly schema: Schema.ConstraintCodec + readonly context: Context.Context + readonly mutation: Mutation.Mutation< + readonly [value: A, form: MutationForm], + MA, ME, MR + > + readonly validationFiber: View.View>, never, never> + + readonly run: Effect.Effect + readonly submit: Effect.Effect | AsyncResult.Failure>, Cause.NoSuchElementError> +} + +export class MutationFormImpl +extends Pipeable.Class implements MutationForm { + readonly [Form.FormTypeId]: Form.FormTypeId = Form.FormTypeId + readonly [MutationFormTypeId]: MutationFormTypeId = MutationFormTypeId + + readonly path = [] as const + + readonly encodedValue: Lens.Lens + readonly isValidating: View.View + readonly canCommit: View.View + readonly isCommitting: View.View + + constructor( + readonly schema: Schema.ConstraintCodec, + readonly context: Context.Context, + readonly mutation: Mutation.Mutation< + readonly [value: A, form: MutationForm], + MA, ME, MR + >, + readonly value: Lens.Lens, never, never, never, never>, + readonly internalEncodedValue: Lens.Lens, + readonly issues: Lens.Lens, + readonly validationFiber: Lens.Lens>, never, never, never, never>, + + readonly runSemaphore: Semaphore.Semaphore, + ) { + super() + + this.encodedValue = Effect.all([ + Effect.succeed(this), + Effect.succeed(Lens.asLensImpl(this.internalEncodedValue)), + ]).pipe( + Effect.map(([self, parent]) => Lens.make({ + get: parent.get, + get changes() { return parent.changes }, + commit: a => Effect.andThen( + Effect.flatMap( + parent.resolve, + resolved => resolved.commit(Effect.succeed(a)), + ), + self.synchronizeEncodedValue(a), + ), + lock: parent.lock, + })), + Lens.unwrap, + ) + this.isValidating = Effect.succeed(this).pipe( + Effect.map(self => View.map(self.validationFiber, Option.isSome)), + View.unwrap, + ) + this.canCommit = Effect.succeed(this).pipe( + Effect.map(self => View.map( + View.zipLatestAll(self.value, self.issues, self.validationFiber, self.mutation.state), + ([value, issues, validationFiber, result]) => ( + Option.isSome(value) && + Array.isReadonlyArrayEmpty(issues) && + Option.isNone(validationFiber) && + !AsyncResult.isWaiting(result) + ), + )), + View.unwrap, + ) + this.isCommitting = Effect.succeed(this).pipe( + Effect.map(self => View.map(self.mutation.state, AsyncResult.isWaiting)), + View.unwrap, + ) + } + + synchronizeEncodedValue(encodedValue: I): Effect.Effect { + return Lens.get(this.validationFiber).pipe( + Effect.andThen(Option.match({ + onSome: Fiber.interrupt, + onNone: () => Effect.void, + })), + Effect.andThen(Effect.forkScoped( + Effect.ensuring( + Schema.decodeEffect(this.schema, { errors: "all" })(encodedValue), + Lens.set(this.validationFiber, Option.none()), + ) + )), + Effect.tap(fiber => Lens.set(this.validationFiber, Option.some(fiber))), + Effect.flatMap(Fiber.join), + + Effect.tap(() => Lens.set(this.issues, Array.empty())), + Effect.flatMap(value => Lens.set(this.value, Option.some(value))), + Effect.catchIf( + SchemaError.isSchemaError, + error => Lens.set(this.issues, SchemaIssue.makeFormatterStandardSchemaV1()(error.issue).issues), + ), + + Effect.provide(this.context), + ) + } + + get run(): Effect.Effect { + return Lens.get(this.encodedValue).pipe( + Effect.flatMap(v => Schema.decodeEffect(this.schema)(v)), + Effect.option, + Effect.flatMap(v => Lens.set(this.value, v)), + Effect.provide(this.context), + this.runSemaphore.withPermits(1), + ) + } + + get submit(): Effect.Effect | AsyncResult.Failure>, Cause.NoSuchElementError, never> { + return Lens.get(this.value).pipe( + Effect.flatMap(Effect.fromOption), + Effect.flatMap(value => this.submitValue(value)), + ) + } + + submitValue(value: A): Effect.Effect | AsyncResult.Failure>, never, never> { + return Effect.when( + Effect.tap( + this.mutation.mutate([value, this as any]), + result => AsyncResult.isFailure(result) + ? Option.match( + Array.findFirst( + result.cause.reasons, + reason => Cause.isFailReason(reason) && SchemaError.isSchemaError(reason.error) + ? Option.some(reason.error) + : Option.none(), + ), + { + onSome: error => Lens.set(this.issues, SchemaIssue.makeFormatterStandardSchemaV1()(error.issue).issues), + onNone: () => Effect.void, + }, + ) + : Effect.void, + ), + View.get(this.canCommit), + ) + } +} + +export const isMutationForm = (u: unknown): u is MutationForm => Predicate.hasProperty(u, MutationFormTypeId) + + +export declare namespace make { + export interface Options + extends Mutation.make.Options< + readonly [value: NoInfer, form: MutationForm, NoInfer, NoInfer, NoInfer, unknown, unknown, unknown>], + MA, ME, MR + > { + readonly schema: Schema.ConstraintCodec + readonly initialEncodedValue: NoInfer + } +} + +export const make = Effect.fnUntraced(function* ( + options: make.Options +): Effect.fn.Return< + MutationForm, + never, + Scope.Scope | RD | RE | MR +> { + return new MutationFormImpl( + options.schema, + yield* Effect.context(), + yield* Mutation.make(options), + + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none())), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(options.initialEncodedValue)), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Array.empty())), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none>())), + + yield* Semaphore.make(1), + ) +}) + +export declare namespace service { + export interface Options + extends make.Options {} +} + +export const service = ( + options: service.Options +): Effect.Effect< + MutationForm, + never, + Scope.Scope | RD | RE | MR +> => Effect.tap( + make(options), + form => Effect.forkScoped(form.run), +) diff --git a/packages/effect-fc-next/src/PubSub.ts b/packages/effect-fc-next/src/PubSub.ts new file mode 100644 index 0000000..17c44bc --- /dev/null +++ b/packages/effect-fc-next/src/PubSub.ts @@ -0,0 +1,17 @@ +import { Effect, PubSub, type Scope } from "effect" +import type * as React from "react" +import * as Component from "./Component.js" + + +export * from "effect/PubSub" + +export const useFromReactiveValues = Effect.fnUntraced(function* ( + values: A +): Effect.fn.Return, never, Scope.Scope> { + const pubsub = yield* Component.useOnMount(() => Effect.acquireRelease(PubSub.unbounded(), PubSub.shutdown)) + yield* Component.useReactEffect(() => Effect.flatMap( + PubSub.isShutdown(pubsub), + shutdown => shutdown ? Effect.succeed(undefined) : Effect.asVoid(PubSub.publish(pubsub, values)), + ), values) + return pubsub +}) diff --git a/packages/effect-fc-next/src/Query.test.ts b/packages/effect-fc-next/src/Query.test.ts new file mode 100644 index 0000000..b518c0d --- /dev/null +++ b/packages/effect-fc-next/src/Query.test.ts @@ -0,0 +1,167 @@ +import { Effect, type Scope, Stream } from "effect" +import { AsyncResult } from "effect/unstable/reactivity" +import { describe, expect, it } from "vitest" +import * as Query from "./Query.js" +import * as QueryClient from "./QueryClient.js" +import * as View from "./View.js" + + +const runQueryTest = (effect: Effect.Effect) => + Effect.runPromise(Effect.scoped(effect.pipe( + Effect.provide(QueryClient.layer()), + ))) + +const staticKey = (key: K): View.View => View.make({ + get: Effect.succeed(key), + changes: Stream.make(key), +}) + +const expectSuccessValue = ( + state: Query.FinalQueryState, +): A => { + expect(AsyncResult.isSuccess(state.result)).toBe(true) + + if (!AsyncResult.isSuccess(state.result)) + throw new Error(`Expected Success result, received ${state.result._tag}`) + + return state.result.value +} + +describe("Query", () => { + it("fetch caches successful results until they are invalidated or stale", async () => { + let calls = 0 + const key = staticKey([1]) + + const result = await runQueryTest(Effect.gen(function*() { + const query = yield* Query.make({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "1 minute", + }) + + const first = yield* query.fetch([1]) + const second = yield* query.fetch([1]) + + return [first, second] as const + })) + + expect(calls).toBe(1) + expect(expectSuccessValue(result[0])).toBe("value:1:1") + expect(expectSuccessValue(result[1])).toBe("value:1:1") + }) + + it("refresh reruns the latest query key", async () => { + let calls = 0 + const key = staticKey([1]) + + const result = await runQueryTest(Effect.gen(function*() { + const query = yield* Query.make({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "0 millis", + }) + + const first = yield* query.fetch([1]) + yield* Effect.sleep("1 millis") + const refreshed = yield* query.refresh + + return [first, refreshed] as const + })) + + expect(calls).toBe(2) + expect(expectSuccessValue(result[0])).toBe("value:1:1") + expect(expectSuccessValue(result[1])).toBe("value:1:2") + }) + + it("invalidateCacheEntry forces the next fetch for that key to rerun", async () => { + let calls = 0 + const key = staticKey([1]) + + const result = await runQueryTest(Effect.gen(function*() { + const query = yield* Query.make({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "1 minute", + }) + + const first = yield* query.fetch([1]) + yield* query.invalidateCacheEntry([1]) + const second = yield* query.fetch([1]) + + return [first, second] as const + })) + + expect(calls).toBe(2) + expect(expectSuccessValue(result[0])).toBe("value:1:1") + expect(expectSuccessValue(result[1])).toBe("value:1:2") + }) + + it("invalidateCache clears cached entries for the query function", async () => { + let calls = 0 + const key = staticKey([1]) + + const result = await runQueryTest(Effect.gen(function*() { + const query = yield* Query.make({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "1 minute", + }) + + const first = yield* query.fetch([1]) + yield* query.invalidateCache + const second = yield* query.fetch([1]) + + return [first, second] as const + })) + + expect(calls).toBe(2) + expect(expectSuccessValue(result[0])).toBe("value:1:1") + expect(expectSuccessValue(result[1])).toBe("value:1:2") + }) + + it("service starts the key view automatically and records its latest final state", async () => { + let calls = 0 + const key = staticKey([1]) + + const effect = Effect.gen(function*() { + const query = yield* Query.service({ + key, + f: ([id]: readonly [number]) => Effect.sync(() => { + calls += 1 + return `value:${id}:${calls}` + }), + staleTime: "1 minute", + }) + + const latestFinalState = yield* Effect.sleep("1 millis").pipe( + Effect.andThen(View.get(query.latestFinalState)), + Effect.flatMap(Effect.fromOption), + Effect.eventually, + Effect.timeout("1 second"), + ) + + return { + state: yield* View.get(query.state), + latestFinalState, + } + }) + + const result = await runQueryTest(effect) + + expect(calls).toBe(1) + expect(result.state.key).toEqual([1]) + expect(expectSuccessValue(result.latestFinalState)).toBe("value:1:1") + }) +}) diff --git a/packages/effect-fc-next/src/Query.ts b/packages/effect-fc-next/src/Query.ts new file mode 100644 index 0000000..73aac39 --- /dev/null +++ b/packages/effect-fc-next/src/Query.ts @@ -0,0 +1,463 @@ +import { Cause, type Context, Duration, Effect, Equal, type Equivalence, Exit, Fiber, Option, Pipeable, Predicate, PubSub, Ref, type Scope, Semaphore, Stream, SubscriptionRef } from "effect" +import { AsyncResult } from "effect/unstable/reactivity" +import * as Lens from "./Lens.js" +import * as QueryClient from "./QueryClient.js" +import * as View from "./View.js" + + +export const QueryTypeId: unique symbol = Symbol.for("@effect-fc/Query/Query") +export type QueryTypeId = typeof QueryTypeId + +export interface Query +extends Pipeable.Pipeable { + readonly [QueryTypeId]: QueryTypeId + + readonly context: Context.Context + readonly key: View.View + readonly keyEquivalence: Equivalence.Equivalence + readonly f: (key: K) => Effect.Effect + + readonly staleTime: Duration.Duration + readonly refreshOnWindowFocus: boolean + + readonly fiber: View.View>> + readonly state: View.View> + readonly latestFinalState: View.View>> + + readonly run: Effect.Effect + fetch(key: K): Effect.Effect, Cause.NoSuchElementError> + fetchView(key: K): Effect.Effect>, Cause.NoSuchElementError> + readonly refresh: Effect.Effect, Cause.NoSuchElementError> + readonly refreshView: Effect.Effect>, Cause.NoSuchElementError> + + readonly invalidateCache: Effect.Effect + invalidateCacheEntry(key: K): Effect.Effect +} + +export interface QueryState { + readonly key: K + readonly result: AsyncResult.AsyncResult +} + +export interface FinalQueryState { + readonly key: K + readonly result: AsyncResult.Success | AsyncResult.Failure +} + +export const isQuery = (u: unknown): u is Query => Predicate.hasProperty(u, QueryTypeId) + + +export class QueryImpl +extends Pipeable.Class implements Query { + readonly [QueryTypeId]: QueryTypeId = QueryTypeId + + constructor( + readonly context: Context.Context, + readonly key: View.View, + readonly keyEquivalence: Equivalence.Equivalence, + readonly f: (key: K) => Effect.Effect, + + readonly staleTime: Duration.Duration, + readonly refreshOnWindowFocus: boolean, + + readonly fiber: Lens.Lens>>, + readonly state: Lens.Lens>, + readonly latestFinalState: Lens.Lens>>, + + readonly runSemaphore: Semaphore.Semaphore, + ) { + super() + } + + get run(): Effect.Effect { + return Effect.all([ + Stream.runForEach( + this.key.changes, + key => Effect.gen({ self: this }, function*() { + yield* this.interrupt + const latestFinalState = yield* Lens.get(this.latestFinalState) + + const state = yield* this.startCached( + Option.isSome(latestFinalState) && this.keyEquivalence(key, latestFinalState.value.key) + ? latestFinalState.value + : { + key, + result: AsyncResult.initial(false), + } + ) + + yield* Effect.forkScoped(this.watch(state)) + }), + ), + + Effect.promise(() => import("@effect/platform-browser")).pipe( + Effect.flatMap(({ BrowserStream }) => this.refreshOnWindowFocus + ? Stream.runForEach( + BrowserStream.fromEventListenerWindow("focus"), + () => this.refreshView, + ) + : Effect.void + ), + Effect.catchDefect(() => Effect.void), + ), + ], { concurrency: "unbounded" }).pipe( + Effect.ignore, + this.runSemaphore.withPermits(1), + Effect.provide(this.context), + ) + } + + get interrupt(): Effect.Effect { + return Effect.flatMap(Lens.get(this.fiber), Option.match({ + onSome: Fiber.interrupt, + onNone: () => Effect.void, + })) + } + + fetch(key: K): Effect.Effect, Cause.NoSuchElementError> { + return Effect.gen({ self: this }, function*() { + yield* this.interrupt + const state = yield* this.startCached({ + key, + result: AsyncResult.initial(false), + }) + return yield* this.watch(state) + }).pipe( + Effect.provide(this.context), + ) + } + + fetchView(key: K): Effect.Effect< + View.View>, + Cause.NoSuchElementError + > { + return Effect.gen({ self: this }, function*() { + yield* this.interrupt + const state = yield* this.startCached({ + key, + result: AsyncResult.initial(false), + }) + + yield* Effect.forkScoped(this.watch(state)) + return state + }).pipe( + Effect.provide(this.context), + ) + } + + get refresh(): Effect.Effect, Cause.NoSuchElementError> { + return Effect.gen({ self: this }, function*() { + yield* this.interrupt + const latestState = yield* Lens.get(this.state) + const latestFinalState = yield* Lens.get(this.latestFinalState) + + const state = yield* this.startCached( + Option.isSome(latestFinalState) && this.keyEquivalence(latestState.key, latestFinalState.value.key) + ? latestFinalState.value + : { + key: latestState.key, + result: AsyncResult.initial(false), + } + ) + + return yield* this.watch(state) + }).pipe( + Effect.provide(this.context), + ) + } + + get refreshView(): Effect.Effect< + View.View>, + Cause.NoSuchElementError + > { + return Effect.gen({ self: this }, function*() { + yield* this.interrupt + const latestState = yield* Lens.get(this.state) + const latestFinalState = yield* Lens.get(this.latestFinalState) + + const state = yield* this.startCached( + Option.isSome(latestFinalState) && this.keyEquivalence(latestState.key, latestFinalState.value.key) + ? latestFinalState.value + : { + key: latestState.key, + result: AsyncResult.initial(false), + } + ) + + yield* Effect.forkScoped(this.watch(state)) + return state + }).pipe( + Effect.provide(this.context), + ) + } + + startCached( + previous: QueryState, + ): Effect.Effect< + View.View>, + Cause.NoSuchElementError, + Scope.Scope | QueryClient.QueryClient | R + > { + return Effect.flatMap(this.getCacheEntry(previous.key), Option.match({ + onSome: entry => Effect.flatMap( + QueryClient.isQueryClientCacheEntryStale(entry), + isStale => isStale + ? this.start({ + key: previous.key, + result: entry.result as AsyncResult.AsyncResult, + }) + : Effect.succeed(View.make({ + get: Effect.succeed({ + key: previous.key, + result: entry.result as AsyncResult.AsyncResult, + }), + get changes() { + return Stream.make({ + key: previous.key, + result: entry.result as AsyncResult.AsyncResult, + }) + }, + })), + ), + onNone: () => this.start(previous), + })) + } + + start( + previous: QueryState, + ): Effect.Effect< + View.View>, + never, + Scope.Scope | R + > { + return Effect.gen({ self: this }, function*() { + const state = yield* makeQueryStateLens(previous) + + const fiber = yield* Effect.forkScoped(Effect.andThen( + Lens.update, never, never, never, never>( + state, + previous => AsyncResult.match(previous.result, { + onInitial: () => ({ + key: previous.key, + result: AsyncResult.initial(true), + }), + onSuccess: result => ({ + key: previous.key, + result: AsyncResult.success(result.value, { + waiting: true, + }), + }), + onFailure: result => ({ + key: previous.key, + result: AsyncResult.failure(result.cause, { + waiting: true, + previousSuccess: result.previousSuccess, + }), + }), + } + )), + + Effect.onExit(this.f(previous.key), exit => Effect.gen({ self: this }, function*() { + const fiberId = yield* Effect.fiberId + const fiber = yield* Lens.get(this.fiber) + + if (Option.isSome(fiber) && fiberId === fiber.value.id) + yield* Lens.set(this.fiber, Option.none()) + + const finalState = (yield* Lens.updateAndGet, never, never, never, never>( + state, + previous => Exit.match(exit, { + onSuccess: v => ({ + key: previous.key, + result: AsyncResult.success(v), + }), + onFailure: c => Cause.hasInterruptsOnly(c) + ? previous + : AsyncResult.match(previous.result, { + onInitial: () => ({ + key: previous.key, + result: AsyncResult.failure(c), + }), + onSuccess: v => ({ + key: previous.key, + result: AsyncResult.failure(c, { + previousSuccess: Option.some(v), + }), + }), + onFailure: v => ({ + key: previous.key, + result: AsyncResult.failure(c, { + previousSuccess: v.previousSuccess, + }), + }), + }), + }), + )) as FinalQueryState + + yield* Lens.set(this.latestFinalState, Option.some(finalState)) + yield* PubSub.shutdown(state.pubsub) + })) + )) + + yield* Lens.set(this.fiber, Option.some(fiber)) + return state + }) + } + + watch( + view: View.View> + ): Effect.Effect, never, QueryClient.QueryClient> { + return Effect.gen({ self: this }, function*() { + const initial = yield* View.get(view) + const final = yield* Stream.runFoldEffect( + View.changes(view), + () => initial, + (_, state) => Effect.as(Lens.set(this.state, state), state), + ) as Effect.Effect> + + yield* Lens.set(this.latestFinalState, Option.some(final)) + if (AsyncResult.isSuccess(final.result)) + yield* this.setCacheEntry(final.key, final.result) + + return final + }) + } + + makeCacheKey(key: K): QueryClient.QueryClientCacheKey { + return new QueryClient.QueryClientCacheKey(key, this.f as (key: unknown) => Effect.Effect) + } + + getCacheEntry( + key: K + ): Effect.Effect, never, QueryClient.QueryClient> { + return Effect.andThen( + Effect.all([ + Effect.succeed(this.makeCacheKey(key)), + QueryClient.QueryClient, + ]), + ([key, client]) => client.getCacheEntry(key), + ) + } + + setCacheEntry( + key: K, + result: AsyncResult.Success, + ): Effect.Effect { + return Effect.flatMap( + Effect.all([ + Effect.succeed(this.makeCacheKey(key)), + QueryClient.QueryClient, + ]), + ([key, client]) => client.setCacheEntry(key, result, this.staleTime), + ) + } + + get invalidateCache(): Effect.Effect { + return QueryClient.QueryClient.pipe( + Effect.andThen(client => client.invalidateCacheEntries(this.f as (key: unknown) => Effect.Effect)), + Effect.provide(this.context), + ) + } + + invalidateCacheEntry(key: K): Effect.Effect { + return Effect.all([ + Effect.succeed(this.makeCacheKey(key)), + QueryClient.QueryClient, + ]).pipe( + Effect.andThen(([key, client]) => client.invalidateCacheEntry(key)), + Effect.provide(this.context), + ) + } +} + +export declare namespace make { + export interface Options { + readonly key: View.View, + readonly keyEquivalence?: Equivalence.Equivalence, + readonly f: (key: K) => Effect.Effect + + readonly staleTime?: Duration.Input + readonly refreshOnWindowFocus?: boolean + } +} + +export const make = Effect.fnUntraced(function* ( + options: make.Options +): Effect.fn.Return< + Query, + Cause.NoSuchElementError, + Scope.Scope | QueryClient.QueryClient | R +> { + const client = yield* QueryClient.QueryClient + + return new QueryImpl( + yield* Effect.context(), + options.key, + options.keyEquivalence ?? Equal.asEquivalence(), + options.f, + + options.staleTime ? yield* Effect.fromOption(Duration.fromInput(options.staleTime)) : client.defaultStaleTime, + options.refreshOnWindowFocus ?? client.defaultRefreshOnWindowFocus, + + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none>())), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make>({ + key: yield* View.get(options.key), + result: AsyncResult.initial(false), + })), + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none>())), + + yield* Semaphore.make(1), + ) +}) + +export const service = ( + options: make.Options +): Effect.Effect< + Query, + Cause.NoSuchElementError, + Scope.Scope | QueryClient.QueryClient | R +> => Effect.tap( + make(options), + query => Effect.forkScoped(query.run), +) + + +export class QueryStateLens +extends Lens.LensImpl, never, never, never, never> { + constructor( + readonly ref: Ref.Ref>, + readonly pubsub: PubSub.PubSub>, + readonly semaphore: Semaphore.Semaphore, + ) { + super() + } + + get resolve(): Effect.Effect>, never, never> { + return Effect.map( + Ref.get(this.ref), + value => ({ + value, + commit: next => Effect.flatMap( + next, + value => Effect.andThen( + Ref.set(this.ref, value), + PubSub.publish(this.pubsub, value), + ), + ), + }), + ) + } + get changes() { return Stream.fromPubSub(this.pubsub) } + get lock() { return Effect.succeed(this.semaphore.withPermit) } +} + +export const makeQueryStateLens = ( + initial: QueryState, +) => Effect.all([ + Ref.make(initial), + PubSub.unbounded>({ replay: 1 }), + Semaphore.make(1), +]).pipe( + Effect.tap(([, pubsub]) => PubSub.publish(pubsub, initial)), + Effect.map(([ref, pubsub, semaphore]) => new QueryStateLens(ref, pubsub, semaphore)), +) diff --git a/packages/effect-fc-next/src/QueryClient.ts b/packages/effect-fc-next/src/QueryClient.ts new file mode 100644 index 0000000..ed0544b --- /dev/null +++ b/packages/effect-fc-next/src/QueryClient.ts @@ -0,0 +1,183 @@ +import { type Cause, Context, DateTime, Duration, Effect, Equal, Equivalence, Hash, HashMap, Layer, type Option, Pipeable, Predicate, Schedule, type Scope, Semaphore, SubscriptionRef } from "effect" +import type { AsyncResult } from "effect/unstable/reactivity" +import * as Lens from "./Lens.js" +import type * as View from "./View.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: View.View> + readonly cacheGcTime: Duration.Duration + readonly defaultStaleTime: Duration.Duration + readonly defaultRefreshOnWindowFocus: boolean + + readonly run: Effect.Effect + getCacheEntry(key: QueryClientCacheKey): Effect.Effect> + setCacheEntry( + key: QueryClientCacheKey, + result: AsyncResult.Success, + staleTime: Duration.Duration, + ): Effect.Effect + invalidateCacheEntries(f: (key: unknown) => Effect.Effect): Effect.Effect + invalidateCacheEntry(key: QueryClientCacheKey): Effect.Effect +} + +export class QueryClient extends Context.Service()( + "@effect-fc/QueryClient/QueryClient" +) {} + +export class QueryClientServiceImpl +extends Pipeable.Class +implements QueryClientService { + readonly [QueryClientServiceTypeId]: QueryClientServiceTypeId = QueryClientServiceTypeId + + constructor( + readonly cache: Lens.Lens>, + readonly cacheGcTime: Duration.Duration, + readonly defaultStaleTime: Duration.Duration, + readonly defaultRefreshOnWindowFocus: boolean, + readonly runSemaphore: Semaphore.Semaphore, + ) { + super() + } + + get run(): Effect.Effect { + return this.runSemaphore.withPermits(1)(Effect.repeat( + Effect.flatMap( + DateTime.now, + now => Lens.update(this.cache, HashMap.filter(entry => + Duration.isLessThan( + DateTime.distance(entry.lastAccessedAt, now), + Duration.sum(entry.staleTime, this.cacheGcTime), + ) + )), + ), + Schedule.spaced("30 second"), + )) + } + + getCacheEntry(key: QueryClientCacheKey): Effect.Effect> { + return Effect.all([ + DateTime.now, + Effect.flatMap( + Effect.map(Lens.get(this.cache), HashMap.get(key)), + Effect.fromOption, + ), + ]).pipe( + Effect.map(([now, entry]) => new QueryClientCacheEntry(entry.result, entry.staleTime, entry.createdAt, now)), + Effect.tap(entry => Lens.update(this.cache, HashMap.set(key, entry))), + Effect.option, + ) + } + + setCacheEntry( + key: QueryClientCacheKey, + result: AsyncResult.Success, + staleTime: Duration.Duration, + ): Effect.Effect { + return DateTime.now.pipe( + Effect.map(now => new QueryClientCacheEntry(result, staleTime, now, now)), + Effect.tap(entry => Lens.update(this.cache, HashMap.set(key, entry))), + ) + } + + invalidateCacheEntries(f: (key: unknown) => Effect.Effect): Effect.Effect { + return Lens.update(this.cache, HashMap.filter((_, key) => !Equivalence.strictEqual()(key.f, f))) + } + invalidateCacheEntry(key: QueryClientCacheKey): Effect.Effect { + return Lens.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.Input + readonly defaultStaleTime?: Duration.Input + readonly defaultRefreshOnWindowFocus?: boolean + } +} + +export const make = Effect.fnUntraced(function* ( + options: make.Options = {} +): Effect.fn.Return { + return new QueryClientServiceImpl( + Lens.fromSubscriptionRef(yield* SubscriptionRef.make(HashMap.empty())), + yield* Effect.fromOption(Duration.fromInput(options.cacheGcTime ?? "5 minutes")), + yield* Effect.fromOption(Duration.fromInput(options.defaultStaleTime ?? "0 minutes")), + options.defaultRefreshOnWindowFocus ?? true, + yield* Semaphore.make(1), + ) +}) + +export declare namespace service { + export interface Options extends make.Options {} +} + +export const service = ( + options?: service.Options +): Effect.Effect => Effect.tap( + make(options), + client => Effect.forkScoped(client.run), +) + +export const layer = (options?: service.Options) => Layer.effect(QueryClient, service(options)) + + +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: unknown, + readonly f: (key: unknown) => Effect.Effect, + ) { + super() + } + + [Equal.symbol](that: Equal.Equal) { + return isQueryClientCacheKey(that) && Equal.equals(this.key, that.key) && Equivalence.strictEqual()(this.f, that.f) + } + [Hash.symbol]() { + return Hash.combine(Hash.hash(this.f))(Hash.hash(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: AsyncResult.Success, + readonly staleTime: Duration.Duration, + 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 => Effect.map( + DateTime.now, + now => Duration.isGreaterThanOrEqualTo(DateTime.distance(self.createdAt, now), self.staleTime), +) diff --git a/packages/effect-fc-next/src/ReactRuntime.ts b/packages/effect-fc-next/src/ReactRuntime.ts new file mode 100644 index 0000000..52fd82c --- /dev/null +++ b/packages/effect-fc-next/src/ReactRuntime.ts @@ -0,0 +1,73 @@ +/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ +import { type Context, Effect, Layer, ManagedRuntime, Predicate } from "effect" +import * as React from "react" +import * as Component from "./Component.js" +import * as ScopeRegistry from "./ScopeRegistry.js" + + +export const ReactRuntimeTypeId: unique symbol = Symbol.for("@effect-fc/ReactRuntime/ReactRuntime") +export type ReactRuntimeTypeId = typeof ReactRuntimeTypeId + +export interface ReactRuntime { + new(_: never): Record + readonly [ReactRuntimeTypeId]: ReactRuntimeTypeId + readonly runtime: ManagedRuntime.ManagedRuntime + readonly context: React.Context> +} + +const ReactRuntimePrototype = Object.freeze({ [ReactRuntimeTypeId]: ReactRuntimeTypeId } as const) + +export const preludeLayer: Layer.Layer = ScopeRegistry.layer + +export const isReactRuntime = (u: unknown): u is ReactRuntime => Predicate.hasProperty(u, ReactRuntimeTypeId) + +export const make = ( + layer: Layer.Layer, + memoMap?: Layer.MemoMap, +): ReactRuntime | R, ER> => Object.setPrototypeOf( + Object.assign(function() {}, { + runtime: ManagedRuntime.make( + Layer.merge(preludeLayer, layer), + { memoMap }, + ), + // biome-ignore lint/style/noNonNullAssertion: context initialization + context: React.createContext | R>>(null!), + }), + ReactRuntimePrototype, +) + + +export namespace Provider { + export interface Props extends React.SuspenseProps { + readonly runtime: ReactRuntime + readonly children?: React.ReactNode + } +} + +export const Provider = ( + { runtime, children, ...suspenseProps }: Provider.Props +): React.ReactNode => { + const promise = React.useMemo(() => runtime.runtime.context(), [runtime]) + + return React.createElement( + React.Suspense, + suspenseProps, + React.createElement(ProviderInner, { runtime, promise, children }), + ) +} + +const ProviderInner = ( + { runtime, promise, children }: { + readonly runtime: ReactRuntime + readonly promise: Promise> + readonly children?: React.ReactNode + } +): React.ReactNode => { + const context = React.use(promise) + Effect.runSyncWith(context)(Component.useOnChange( + () => Effect.addFinalizer(() => runtime.runtime.disposeEffect), + [runtime], + )) + + return React.createElement(runtime.context, { value: context }, children) +} diff --git a/packages/effect-fc-next/src/Refreshable.test.ts b/packages/effect-fc-next/src/Refreshable.test.ts new file mode 100644 index 0000000..110ca74 --- /dev/null +++ b/packages/effect-fc-next/src/Refreshable.test.ts @@ -0,0 +1,60 @@ +import { describe, expect, it, vi } from "vitest" +import type * as Component from "./Component.js" +import * as Refreshable from "./Refreshable.js" + + +describe("Refreshable", () => { + it("attaches a cell and notifies subscribers after a compatible update", async () => { + const first = {} as Component.Component.Any + const cell = Refreshable.makeCell(first, "hooks", false) + const listener = vi.fn() + + expect(Refreshable.isRefreshable(first)).toBe(false) + const attached = Refreshable.attach(first, cell) + expect(attached).toBe(first) + expect(Refreshable.isRefreshable(first)).toBe(true) + expect(attached[Refreshable.RefreshableTypeId]).toBe(cell) + expect(Object.getPrototypeOf(attached).asFunctionComponent) + .toBe(Refreshable.RefreshablePrototype.asFunctionComponent) + + cell.subscribe(listener) + const second = {} as Component.Component.Any + cell.update(second, "hooks", false) + + expect(cell.current).toBe(second) + expect(cell.snapshot).toEqual({ + revision: 1, + resetRevision: 0, + }) + + await Promise.resolve() + expect(listener).toHaveBeenCalledTimes(1) + }) + + it("requests a remount when a signature changes or reset is forced", () => { + const component = {} as Component.Component.Any + const cell = Refreshable.makeCell(component, "one", false) + + cell.update({} as Component.Component.Any, "two", false) + expect(cell.snapshot.resetRevision).toBe(1) + + cell.update({} as Component.Component.Any, "two", true) + expect(cell.snapshot.resetRevision).toBe(2) + }) + + it("builds the refresh shell from the current descriptor implementation", () => { + const implementation = () => null + const makeFunctionComponent = vi.fn(() => implementation) + const component = { + makeFunctionComponent, + } as unknown as Component.ComponentImpl.Any + const contextRef = { + current: {}, + } as never + const cell = Refreshable.makeCell(component, "hooks", false) + const attached = Refreshable.attach(component, cell) + + expect(attached.asFunctionComponent(contextRef)).not.toBe(implementation) + expect(makeFunctionComponent).toHaveBeenCalledWith(contextRef) + }) +}) diff --git a/packages/effect-fc-next/src/Refreshable.ts b/packages/effect-fc-next/src/Refreshable.ts new file mode 100644 index 0000000..781f895 --- /dev/null +++ b/packages/effect-fc-next/src/Refreshable.ts @@ -0,0 +1,181 @@ +import type { Context, Scope } from "effect" +import * as React from "react" +import type * as Component from "./Component.js" + + +/** + * A stable identifier used to associate an Effect View descriptor with its + * development refresh cell. + * + * This low-level API is intended for development-server integrations such as + * `@effect-view/vite-plugin`. + */ +export const RefreshableTypeId: unique symbol = Symbol.for("@effect-view/Refreshable/Refreshable") +export type RefreshableTypeId = typeof RefreshableTypeId + +/** + * The version observed by a mounted Effect View refresh shell. + * + * `revision` changes for every update. `resetRevision` changes only when the + * adapter determines that preserving React state is unsafe. + */ +export interface Snapshot { + readonly revision: number + readonly resetRevision: number +} + +/** + * A mutable development cell holding the latest version of an Effect View + * descriptor. + * + * This low-level API is intended for development-server integrations. + */ +export interface Cell { + current: Component.ComponentImpl.Any + signature: string + forceReset: boolean + snapshot: Snapshot + readonly subscribe: (listener: () => void) => () => void + readonly getSnapshot: () => Snapshot + readonly update: ( + component: Component.Component.Any, + signature: string, + forceReset: boolean, + ) => void +} + +export const RefreshablePrototype = Object.freeze({ + asFunctionComponent