Add Zod dependency and update API interfaces
- Added Zod as a dependency in package.json. - Updated pnpm-lock.yaml to include Zod. - Refactored API interfaces: exported new modules for perk, survivor, mission, and encounter. - Removed obsolete api-interfaces.ts file. - Enhanced tests for new schemas in api-interfaces.spec.ts, covering various validation scenarios.
This commit is contained in:
52
docs/adr/0001-twitch-extension-type.md
Executable file
52
docs/adr/0001-twitch-extension-type.md
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
# 0001 — Twitch Video Overlay over Panel extension
|
||||||
|
|
||||||
|
- **Status:** Accepted
|
||||||
|
- **Date:** 2026-05-06
|
||||||
|
|
||||||
|
## Context and problem statement
|
||||||
|
|
||||||
|
Twitch offers three extension placements: Panel (fixed 318×496px below the video, always visible), Component (small attached affordance on the video that expands), and Video Overlay (full transparent layer over the stream, can be minimised to a configured slot).
|
||||||
|
|
||||||
|
Fog Expedition is an autonomous, tick-based ZPG that runs in parallel to a streamer's gameplay. The viewer experience needs to feel ambient and atmospheric — not a separate UI demanding attention, but a layer of fiction that complements the stream.
|
||||||
|
|
||||||
|
Which extension placement best supports this experience?
|
||||||
|
|
||||||
|
## Decision drivers
|
||||||
|
|
||||||
|
- **Aesthetic fit.** The "lantern in the fog" concept needs a small, persistent, atmospheric presence over the stream — not a docked widget below it.
|
||||||
|
- **Glanceability.** Viewers should be able to consume the latest log line in peripheral vision without taking focus from gameplay.
|
||||||
|
- **Streamer control.** Streamers need to position the overlay so it doesn't obscure their gameplay HUD.
|
||||||
|
- **Review feasibility.** All three pass Twitch review with reasonable design discipline; Video Overlay has stricter pixel-obstruction checks.
|
||||||
|
- **Ambient event surfacing.** Significant moments (injury, sacrifice) should briefly surface without forcing the viewer to open anything.
|
||||||
|
|
||||||
|
## Considered options
|
||||||
|
|
||||||
|
1. **Panel extension** — sits below the video, always visible.
|
||||||
|
2. **Component extension** — Twitch-managed icon attached to the video edge, expands to a card on click.
|
||||||
|
3. **Video Overlay extension** — custom-positioned element drawn over the stream, with a configured collapsed/minimised state.
|
||||||
|
|
||||||
|
## Decision outcome
|
||||||
|
|
||||||
|
**Chosen: Video Overlay extension.**
|
||||||
|
|
||||||
|
The minimised state is a custom "lantern + ticker" element (~290×56px) positioned at a streamer-configured corner. It shows the current survivor's state colour and the latest log line. Significant events ("ambient event" state) briefly surface a larger card before auto-dismissing. Click expands the lantern to a full survivor + log + action card (~320×440px) with a backdrop dim.
|
||||||
|
|
||||||
|
This is the only placement that supports the ambient-event surfacing pattern, and the only one that lets viewers consume the experience entirely in peripheral vision.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- Aesthetic latitude — the lantern is custom-designed, not Twitch-chrome-constrained.
|
||||||
|
- Viewers see content without taking focus; the experience is genuinely ambient.
|
||||||
|
- Streamer config screen lets broadcasters position the overlay to avoid their HUD.
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
- Stricter Twitch review: overlays must not obscure meaningful gameplay pixels, must include a streamer kill switch, and the visibility lifecycle (`onVisibilityChanged`) is more nuanced than a Panel.
|
||||||
|
- Higher design discipline required — bad overlays drive streamers to disable the extension across all viewers.
|
||||||
|
- Anonymous viewer experience must be designed explicitly (panel placement makes this trivial; overlay does not).
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
- The visibility lifecycle becomes an explicit concern. When the overlay is hidden, PubSub processing and polling must stop; when re-shown, state must be re-fetched. This shapes how the frontend store reconciles.
|
||||||
70
docs/adr/0002-nx-monorepo-with-strict-boundaries.md
Executable file
70
docs/adr/0002-nx-monorepo-with-strict-boundaries.md
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
# 0002 — Nx monorepo with enforced module boundaries
|
||||||
|
|
||||||
|
- **Status:** Accepted
|
||||||
|
- **Date:** 2026-05-06
|
||||||
|
|
||||||
|
## Context and problem statement
|
||||||
|
|
||||||
|
Fog Expedition has at least three distinct deployable surfaces (Twitch Video Overlay frontend, NestJS EBS backend, content/balance library), and types must be shared between them (DTOs, domain models, encounter records). The project is being built with heavy AI assistance, which adds a specific failure mode: AI assistants happily reach across project boundaries with relative imports if not constrained.
|
||||||
|
|
||||||
|
How should the codebase be structured?
|
||||||
|
|
||||||
|
## Decision drivers
|
||||||
|
|
||||||
|
- **Type sharing without duplication.** The overlay and EBS exchange `Mission`, `Survivor`, `EncounterResult` etc. Hand-keeping types in sync across separate repos is bug-prone.
|
||||||
|
- **AI-assisted-build discipline.** AI tools generate plausible-looking code that violates architectural conventions unless those conventions are mechanically enforced.
|
||||||
|
- **Solo-developer simplicity.** Multiple repos mean multiple CI configs, multiple versioning streams, multiple onboarding paths.
|
||||||
|
- **Future scaling.** Should the project ever grow to more contributors, the architecture should still be coherent.
|
||||||
|
- **Tooling support for the chosen language stack** (TypeScript, Angular, NestJS).
|
||||||
|
|
||||||
|
## Considered options
|
||||||
|
|
||||||
|
1. **Multi-repo (polyrepo).** Frontend, backend, and shared types each in their own repository. Shared types published to a private npm registry.
|
||||||
|
2. **Loose monorepo (npm/pnpm workspaces only).** All projects in one repo, no orchestrator. No automated boundary enforcement.
|
||||||
|
3. **Nx monorepo with `enforce-module-boundaries`.** All projects in one repo. Project tags (`scope:api`, `scope:overlay`, `scope:shared`, `type:app`, `type:lib`) define dependency rules enforced at lint time.
|
||||||
|
4. **Turborepo.** Lighter monorepo orchestrator, focused on caching and task running. No native module boundary enforcement.
|
||||||
|
|
||||||
|
## Decision outcome
|
||||||
|
|
||||||
|
**Chosen: Nx monorepo with enforced module boundaries.**
|
||||||
|
|
||||||
|
Project structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
apps/
|
||||||
|
api/ # scope:api, type:app
|
||||||
|
overlay/ # scope:overlay, type:app
|
||||||
|
libs/
|
||||||
|
api-interfaces/ # scope:shared, type:lib (Zod schemas, DTOs)
|
||||||
|
mission-logic/ # scope:shared, type:lib (encounter resolver, perk math)
|
||||||
|
encounter-library/ # scope:shared, type:lib (content + helpers)
|
||||||
|
```
|
||||||
|
|
||||||
|
Boundary rules enforced via `@nx/enforce-module-boundaries`:
|
||||||
|
|
||||||
|
- Apps can only depend on libs (not other apps).
|
||||||
|
- `scope:api` can depend on `scope:api` and `scope:shared`.
|
||||||
|
- `scope:overlay` can depend on `scope:overlay` and `scope:shared`.
|
||||||
|
- `scope:shared` can only depend on `scope:shared`.
|
||||||
|
|
||||||
|
Violations fail lint (verified at workspace setup with a deliberate negative test).
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- Type sharing is direct via TypeScript imports, no version coordination needed.
|
||||||
|
- Module boundary enforcement catches architecturally incorrect AI-generated code at lint time before code review.
|
||||||
|
- Single CI pipeline, single dependency tree, single onboarding flow.
|
||||||
|
- `nx affected` runs only what changed, keeping CI fast as the project grows.
|
||||||
|
- Per-project `package.json` files keep workspace libs publish-ready (e.g., `api-interfaces` could later be published as a community SDK without restructuring).
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
- Steeper learning curve than plain pnpm workspaces — Nx generators, executors, and project configuration are non-trivial.
|
||||||
|
- Tighter coupling to Nx's release cadence; `nx migrate` is required for major version upgrades but generally handles them well.
|
||||||
|
- Some Nx generators lag behind the underlying tooling (e.g., `@nx/nest` doesn't yet support Vitest natively — see ADR-0003).
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
- The monorepo single source of truth makes architectural mistakes more visible; it also makes them more impactful when they happen.
|
||||||
54
docs/adr/0003-mixed-test-runners.md
Executable file
54
docs/adr/0003-mixed-test-runners.md
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
# 0003 — Vitest in libs and overlay, Jest in API
|
||||||
|
|
||||||
|
- **Status:** Accepted
|
||||||
|
- **Date:** 2026-05-06
|
||||||
|
|
||||||
|
## Context and problem statement
|
||||||
|
|
||||||
|
The Nx workspace contains an Angular frontend, a NestJS backend, and three TypeScript libraries. Each subsystem has different test runner support in current Nx generators. Should the workspace standardise on a single runner, accept mixed runners, or prioritise tooling alignment over uniformity?
|
||||||
|
|
||||||
|
## Decision drivers
|
||||||
|
|
||||||
|
- **Generator support.** Forcing a non-default runner means working against the grain of the Nx generator and maintaining custom configuration.
|
||||||
|
- **Speed.** Vitest is meaningfully faster than Jest for monorepo work.
|
||||||
|
- **Ecosystem fit.** Angular 21 made Vitest the official default. NestJS examples and community resources still assume Jest.
|
||||||
|
- **Test isolation.** API tests and frontend tests rarely run in the same breath; the cost of a mixed setup is mostly cognitive, not operational.
|
||||||
|
- **Future migration cost.** If we standardise wrong now, the cost of switching later is non-trivial — Jest and Vitest mock semantics differ subtly.
|
||||||
|
|
||||||
|
## Considered options
|
||||||
|
|
||||||
|
1. **Jest everywhere.** Use the API's default and force Jest into the libs and overlay.
|
||||||
|
2. **Vitest everywhere.** Force Vitest into the API by manually configuring it after the Nx Nest generator runs.
|
||||||
|
3. **Mixed: Vitest in libs and overlay, Jest in API.** Use each subsystem's native default.
|
||||||
|
4. **Vitest in shared libs, Jest in both apps.** Compromise position.
|
||||||
|
|
||||||
|
## Decision outcome
|
||||||
|
|
||||||
|
**Chosen: Mixed — Vitest in libs and overlay, Jest in API.**
|
||||||
|
|
||||||
|
The Nx Nest generator (`@nx/nest:application`) only supports `jest` and `none` for its `unitTestRunner` option in the version we're using. The Angular generator (`@nx/angular:application`) supports `vitest-angular` (the official Angular Vitest integration) and uses it as the default. The plain JS library generator (`@nx/js:library`) supports both; we chose Vitest there for consistency with the overlay.
|
||||||
|
|
||||||
|
Working with the generator defaults avoids fighting the tooling. The cost — two test runners in one workspace — is small in practice because:
|
||||||
|
|
||||||
|
- Nx's `run-many --target=test` runs both transparently.
|
||||||
|
- Property-based tests (`fast-check`) work identically in both.
|
||||||
|
- Mock semantics differ slightly, but the differences only matter at the test author level, and shared libs use one runner consistently.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- Each generator runs cleanly with default flags — minimal custom configuration.
|
||||||
|
- Vitest gives us fast feedback on the overlay and shared libs (the parts most under iteration).
|
||||||
|
- Jest gives us battle-tested Nest testing utilities (`Test.createTestingModule`, `getRepositoryToken`, etc.) without translation.
|
||||||
|
- When `@nx/nest` adds first-class Vitest support (likely a future Nx version), migration is contained to one project.
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
- Two sets of test config files (`jest.config.cts` for API, `vitest.config.mts` for libs and overlay).
|
||||||
|
- Onboarding requires explaining the split.
|
||||||
|
- A test utility that targets one runner can't be trivially shared to projects using the other.
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
- This decision should be revisited when `@nx/nest` ships native Vitest support, or when the Nest community shifts decisively to Vitest. Track in `PROJECT_CONTEXT.md` "Open decisions" section.
|
||||||
68
docs/adr/0004-stateless-seeded-encounter-resolver.md
Executable file
68
docs/adr/0004-stateless-seeded-encounter-resolver.md
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
# 0004 — Encounter resolver as pure library with seeded PRNG
|
||||||
|
|
||||||
|
- **Status:** Accepted
|
||||||
|
- **Date:** 2026-05-06
|
||||||
|
|
||||||
|
## Context and problem statement
|
||||||
|
|
||||||
|
The mission engine resolves an encounter every 60 seconds for each active mission. The resolver takes survivor stats, perk modifiers, group context, and difficulty, then produces an outcome (success, failure, injury, sacrifice) with associated log text.
|
||||||
|
|
||||||
|
Where in the architecture should this logic live, and how should randomness be handled?
|
||||||
|
|
||||||
|
The choice has cascading implications: testability, replayability for debugging, the feasibility of automated balance testing, and how easily the logic can be exercised in CI without spinning up the full Nest application.
|
||||||
|
|
||||||
|
## Decision drivers
|
||||||
|
|
||||||
|
- **Testability.** The encounter resolver is the most game-critical and balance-sensitive code in the project. It must be exhaustively testable.
|
||||||
|
- **Determinism.** When a viewer reports "my mission desynced at tick 7," we need to reproduce the exact roll that occurred. Without determinism, the bug report is useless.
|
||||||
|
- **Balance validation.** AI-assisted development tends to invent plausible-looking probability numbers that produce degenerate gameplay. We need automated checks that catch this.
|
||||||
|
- **Pluggability.** Future iterations may want to substitute the resolver (different game modes, A/B tests, content versions).
|
||||||
|
- **Performance.** A 60-second tick is forgiving, but the resolver shouldn't allocate database connections or perform I/O.
|
||||||
|
|
||||||
|
## Considered options
|
||||||
|
|
||||||
|
1. **Resolver as a NestJS service.** Lives in the API, dependency-injected, can call other services.
|
||||||
|
2. **Resolver as a static method on a domain class.** Pure but tightly coupled to specific entity types.
|
||||||
|
3. **Resolver as a pure function in a shared library, with `Math.random()` for randomness.** Simple, but non-deterministic.
|
||||||
|
4. **Resolver as a pure function in a shared library, with a seeded PRNG injected as input.** Pure and deterministic.
|
||||||
|
|
||||||
|
## Decision outcome
|
||||||
|
|
||||||
|
**Chosen: Pure function in `libs/mission-logic`, accepting a seed as input and using a seeded PRNG (`seedrandom`).**
|
||||||
|
|
||||||
|
Signature:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function resolveEncounter(
|
||||||
|
survivor: SurvivorStats,
|
||||||
|
perks: PerkModifier[],
|
||||||
|
difficulty: Difficulty,
|
||||||
|
groupContext: GroupContext | null,
|
||||||
|
seed: string
|
||||||
|
): EncounterResult
|
||||||
|
```
|
||||||
|
|
||||||
|
The seed is generated at the API layer (via cryptographic randomness), passed to the resolver, and persisted in `mission_logs` alongside the result. To replay any tick, fetch its seed and modifiers from the database and call the resolver with identical inputs.
|
||||||
|
|
||||||
|
`Math.random()` is forbidden anywhere in `libs/mission-logic`. This is enforced via lint rule and called out as a hard rule in `CLAUDE.md`.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- **Property-based testing** with `fast-check` exercises the full input space — empty perks, modifier overflow, negative modifiers, extreme difficulty — in a way that wasn't feasible with stateful or non-pure designs.
|
||||||
|
- **Monte Carlo balance harness** can simulate 10,000 missions across perk loadouts in CI as a snapshot test, catching balance regressions before merge.
|
||||||
|
- **Replayable debugging.** Any reported mission desync can be reproduced exactly by replaying the seed.
|
||||||
|
- **No database or HTTP dependencies in the resolver** means tests run in milliseconds, not seconds.
|
||||||
|
- **Future SWF (group) logic** layers cleanly on top — the group context is just another input to the same pure function.
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
- **Seed management discipline required.** Every tick must persist its seed, or replay capability is lost. Discoverable, but easy to forget.
|
||||||
|
- **Slightly more boilerplate at the call site** — the API has to generate and pass a seed, where with `Math.random()` it would be implicit.
|
||||||
|
- **`Math.random()` in dependencies** can sneak in transitively. The lint rule and code review must guard against this.
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
- This design also enables **deterministic frontend preview/demo modes** in the future — the overlay could replay a canned mission with a known seed for documentation or marketing.
|
||||||
|
- Pure-library placement means the resolver can be reused if we ever build a CLI tool, a Discord bot variant, or an offline simulator without Nest.
|
||||||
59
docs/adr/0005-per-mission-jittered-tick-scheduling.md
Executable file
59
docs/adr/0005-per-mission-jittered-tick-scheduling.md
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
# 0005 — Per-mission jittered tick scheduling
|
||||||
|
|
||||||
|
- **Status:** Accepted
|
||||||
|
- **Date:** 2026-05-06
|
||||||
|
|
||||||
|
## Context and problem statement
|
||||||
|
|
||||||
|
The mission engine processes one encounter per mission every 60 seconds. The original plan called for a global heartbeat — a single timer that fires every 60 seconds and processes all active missions in lockstep. This design has a simple failure mode at scale: if many missions are active, every 60 seconds the system simultaneously executes hundreds or thousands of database writes, PubSub publishes, and Redis state updates.
|
||||||
|
|
||||||
|
How should ticks be scheduled to avoid this thundering herd?
|
||||||
|
|
||||||
|
## Decision drivers
|
||||||
|
|
||||||
|
- **Database load smoothness.** Synchronised tick processing creates a sawtooth load pattern on Postgres. A flat baseline is easier to provision for and easier to monitor.
|
||||||
|
- **PubSub rate limits.** Twitch's PubSub allows 1 message/sec per channel. A synchronised tick that touches 500 channels at once creates a queue spike.
|
||||||
|
- **Operational simplicity.** A single global timer is conceptually clean; per-mission timers add bookkeeping.
|
||||||
|
- **Crash recovery.** Whichever scheduling model is chosen, a worker crash mid-tick must not leave missions stuck or double-processed.
|
||||||
|
- **Distributed processing.** The system may eventually run on multiple worker instances. The scheduling model must support distributed locking.
|
||||||
|
|
||||||
|
## Considered options
|
||||||
|
|
||||||
|
1. **Global synchronised tick.** Single cron-style scheduler fires every 60s, processes all due missions in batch.
|
||||||
|
2. **Per-mission timers in memory.** Each mission has a `setTimeout` for its next tick.
|
||||||
|
3. **Per-mission `nextTickAt` timestamps in Redis, with a worker that polls for due missions and jitters new ticks across the next 60s window.**
|
||||||
|
4. **Message-queue-driven scheduling** (e.g., RabbitMQ, BullMQ) with delayed jobs.
|
||||||
|
|
||||||
|
## Decision outcome
|
||||||
|
|
||||||
|
**Chosen: Per-mission `nextTickAt` timestamps in Redis with jitter, processed by a polling worker.**
|
||||||
|
|
||||||
|
Each mission stores `nextTickAt` in Redis. When a mission starts (or after each tick processes), `nextTickAt` is set to `now() + 60s + random(±15s)`. A worker polls Redis every ~5 seconds for missions where `nextTickAt <= now()`, processes them, and reschedules.
|
||||||
|
|
||||||
|
Distributed safety is provided by `SET key value NX PX <ttl>` with a unique token (verified before release) on a per-mission lock. This pattern handles concurrent worker instances and crash recovery — a stuck lock expires after its TTL and another worker picks up the mission.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- **Smooth Postgres write load.** Across many active missions, ticks are spread evenly through every 60-second window rather than clustered.
|
||||||
|
- **Headroom for PubSub batching.** Per-channel rate limits are easier to respect when channels' missions don't all tick at the exact same moment.
|
||||||
|
- **Crash-safe.** A worker that dies mid-tick releases its lock via TTL; another worker picks up the mission on the next poll.
|
||||||
|
- **Easy to reason about per-mission.** Each mission's lifecycle is independent in Redis, with no shared mutable state.
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
- **More moving parts than a global cron.** Polling logic, lock semantics, and TTL tuning are all distinct things to get right.
|
||||||
|
- **Polling latency.** Worst-case, a tick fires up to ~5 seconds late (the polling interval). Acceptable for a 60-second cadence, would not be for sub-second.
|
||||||
|
- **Redis becomes operationally critical.** A Redis outage stops mission progression. Mitigate with monitoring and a clearly-documented recovery path.
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
- The polling interval is a tuning knob: shorter intervals reduce tick latency but increase Redis load. Default to 5 seconds; revisit if mission counts grow into the tens of thousands.
|
||||||
|
- This pattern generalises to other periodic work (PubSub batched flushes, mission timeout enforcement) without architectural change.
|
||||||
|
|
||||||
|
## Implementation notes
|
||||||
|
|
||||||
|
- Lock key shape: `tick_lock:{missionId}`, value is a UUID generated by the worker, TTL is 30 seconds (longer than worst-case tick duration, shorter than the 60s cadence).
|
||||||
|
- Release pattern: Lua script that checks the lock value matches the worker's UUID before deleting. Prevents accidentally releasing another worker's lock if your tick took too long.
|
||||||
|
- `nextTickAt` is set by the lock-holding worker after the encounter resolves. If the worker crashes between resolving and setting, the lock expires and the next worker reprocesses — safe because tick processing is idempotent on `(missionId, tickIndex)` thanks to the seeded resolver (see ADR-0004).
|
||||||
74
docs/adr/0006-postgres-plus-redis-data-split.md
Executable file
74
docs/adr/0006-postgres-plus-redis-data-split.md
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
# 0006 — PostgreSQL for durable state, Redis for ephemeral state
|
||||||
|
|
||||||
|
- **Status:** Accepted
|
||||||
|
- **Date:** 2026-05-06
|
||||||
|
|
||||||
|
## Context and problem statement
|
||||||
|
|
||||||
|
The system has two distinct data access patterns:
|
||||||
|
|
||||||
|
- **Durable state** — users, survivors, mission history, mission logs. Must survive crashes, restarts, and deploys. Read patterns are infrequent (mostly on session start) but writes need full ACID guarantees.
|
||||||
|
- **Ephemeral state** — active mission state, mission lobbies, tick locks, `nextTickAt` timestamps, rate limit counters. Read and written every poll cycle (~5 seconds), can be reconstructed from durable state if lost, must be very fast.
|
||||||
|
|
||||||
|
What datastore strategy supports both?
|
||||||
|
|
||||||
|
## Decision drivers
|
||||||
|
|
||||||
|
- **Performance for hot path.** Tick processing reads and writes mission state every 5 seconds per mission. A traditional SQL roundtrip per access is wasteful.
|
||||||
|
- **Durability for cold path.** Mission history, logs, and user records must survive any failure mode.
|
||||||
|
- **Operational complexity.** Each datastore added is another system to monitor, back up, and reason about during incidents.
|
||||||
|
- **Crash recovery.** Ephemeral state should be recoverable from durable state, so loss of the ephemeral store is degraded-but-not-broken.
|
||||||
|
- **Atomic operations.** Tick scheduling needs `SET NX` semantics for distributed locks, which Postgres can simulate but Redis does natively.
|
||||||
|
|
||||||
|
## Considered options
|
||||||
|
|
||||||
|
1. **Postgres only, with `pg_notify` and advisory locks.** Single datastore, all state durable, ephemeral access via in-memory cache.
|
||||||
|
2. **Redis only, with periodic snapshot to disk.** Single datastore, ephemeral by nature, durability via Redis persistence (RDB/AOF).
|
||||||
|
3. **Postgres + Redis split.** Each datastore plays to its strengths.
|
||||||
|
4. **Postgres + in-memory state in the API process.** No second datastore, but loses state on restart and doesn't support multi-instance.
|
||||||
|
|
||||||
|
## Decision outcome
|
||||||
|
|
||||||
|
**Chosen: PostgreSQL for durable state, Redis for ephemeral state.**
|
||||||
|
|
||||||
|
Postgres tables (durable):
|
||||||
|
|
||||||
|
- `users` — internal ID, Twitch opaque user ID, created at.
|
||||||
|
- `survivors` — FK to user, stats, perk slots, current lifecycle state.
|
||||||
|
- `missions` — FK to survivor or group, difficulty, status, timestamps.
|
||||||
|
- `mission_logs` — FK to mission, tick index, encounter ID, rendered text, seed, modifiers applied.
|
||||||
|
|
||||||
|
Redis keys (ephemeral):
|
||||||
|
|
||||||
|
- `active_mission:{missionId}` — JSON snapshot of in-progress mission state.
|
||||||
|
- `mission_lobby:{lobbyId}` — lobby member list and ready flags.
|
||||||
|
- `tick_lock:{missionId}` — distributed lock (see ADR-0005).
|
||||||
|
- `rate_limit:{userId}:{endpoint}` — rate limiting counters.
|
||||||
|
|
||||||
|
Rule: anything in Redis must be reconstructable from Postgres. Loss of Redis means active missions resume from their last persisted tick on next worker poll, after a brief delay.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- **Hot-path performance.** Tick processing operates against Redis with sub-millisecond latency, only writing to Postgres at end-of-tick (the durable log entry).
|
||||||
|
- **Native primitives where useful.** `SET NX PX` for locks, `SETEX` for TTLs, sorted sets for "missions due" queries — all clean in Redis, awkward in SQL.
|
||||||
|
- **Failure isolation.** A Postgres slowdown doesn't immediately stop tick processing (Redis state continues); a Redis outage doesn't lose mission history (Postgres persists).
|
||||||
|
- **Familiar operational tooling.** Both Postgres and Redis have decades of operational maturity.
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
- **Two datastores to operate.** Backups, monitoring, capacity planning, security hardening multiplied by two.
|
||||||
|
- **Consistency boundary.** Redis can drift from Postgres if the API crashes between Redis write and Postgres write. Mitigated by treating Postgres as authoritative on every cold-start reconciliation.
|
||||||
|
- **Schema discipline.** The "what lives where" rule must be documented and respected — accidentally putting durable data only in Redis is a class of bug that's invisible until something restarts.
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
- This split is a common pattern in real-time systems and is well-understood. Hiring or onboarding contributors with experience in either or both is straightforward.
|
||||||
|
- We deliberately avoid more exotic stores (event sourcing, time-series databases, document stores) until the data model demonstrably needs them.
|
||||||
|
|
||||||
|
## Implementation notes
|
||||||
|
|
||||||
|
- `mission_logs` rows are append-only; never updated after creation. This makes them trivially safe under concurrent writes and supports replay/debug.
|
||||||
|
- Plan retention/archival from day one — `mission_logs` will grow fast. Default: partition by month, archive partitions older than N months to cold storage.
|
||||||
|
- Consider Redis ACL setup before production deploy. Local dev runs without auth; production must not.
|
||||||
73
docs/adr/0007-devcontainer-with-host-services.md
Executable file
73
docs/adr/0007-devcontainer-with-host-services.md
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
# 0007 — Devcontainer with docker-outside-of-docker, services on host
|
||||||
|
|
||||||
|
- **Status:** Accepted
|
||||||
|
- **Date:** 2026-05-06
|
||||||
|
|
||||||
|
## Context and problem statement
|
||||||
|
|
||||||
|
The development environment must support a Node 22 LTS toolchain, pnpm, the Nx CLI, Playwright with Chromium, and connectivity to local Postgres and Redis. The target host is Windows 11 with WSL2 Ubuntu and Docker Desktop. The developer wants reproducible environments that mirror enterprise patterns.
|
||||||
|
|
||||||
|
How should the dev environment be structured? Specifically: should Postgres and Redis run inside the devcontainer, alongside it as sibling containers, or directly on the host?
|
||||||
|
|
||||||
|
## Decision drivers
|
||||||
|
|
||||||
|
- **Reproducibility.** A new machine or a fresh container should yield an identical toolchain.
|
||||||
|
- **File watcher reliability.** Vitest, Nx daemon, and Angular dev server all rely on inotify-based file watching, which behaves poorly across virtualisation boundaries.
|
||||||
|
- **Debugger attachment.** The Nest API debugger (`node --inspect`) must be reachable from the host VS Code without complicated port-forwarding rituals.
|
||||||
|
- **Service persistence across container rebuilds.** Postgres data should not vanish every time the devcontainer is rebuilt for a configuration change.
|
||||||
|
- **Twitch dev rig connectivity.** The Twitch dev rig runs on Windows and must reach the API. The networking chain (Windows → WSL2 → devcontainer → API) must be navigable.
|
||||||
|
- **Enterprise pattern alignment.** The setup should reflect patterns used in real-world enterprise devcontainers, not just solo-friendly shortcuts.
|
||||||
|
|
||||||
|
## Considered options
|
||||||
|
|
||||||
|
1. **Native WSL2, no devcontainer.** All tooling installed directly in the WSL2 Ubuntu environment.
|
||||||
|
2. **Devcontainer with all services inside it (compose-based devcontainer).** Postgres, Redis, and the dev workspace all in one Compose stack tied to the devcontainer lifecycle.
|
||||||
|
3. **Devcontainer with `docker-outside-of-docker`, services on host.** The devcontainer contains the dev toolchain only; Postgres and Redis run as plain Docker containers on the host, accessed via `host.docker.internal`.
|
||||||
|
4. **Devcontainer with services as sibling containers in Compose, but `docker-outside-of-docker`.** Variation of option 3 but with all containers managed via one Compose file.
|
||||||
|
|
||||||
|
## Decision outcome
|
||||||
|
|
||||||
|
**Chosen: Devcontainer with `docker-outside-of-docker` feature, Postgres and Redis as plain Docker containers on the host (separate from the devcontainer).**
|
||||||
|
|
||||||
|
Architecture:
|
||||||
|
|
||||||
|
```
|
||||||
|
Windows host
|
||||||
|
└── WSL2 Ubuntu
|
||||||
|
└── Docker Desktop daemon
|
||||||
|
├── postgres container (host:5432)
|
||||||
|
├── redis container (host:6379)
|
||||||
|
└── devcontainer (mounts repo, talks to host daemon via DooD)
|
||||||
|
└── pnpm, nx, claude code, vscode-server
|
||||||
|
```
|
||||||
|
|
||||||
|
The devcontainer mounts the repo at `/workspaces/fog-expedition` and uses `host.docker.internal` to reach Postgres and Redis. The `docker-outside-of-docker` feature lets the developer run `docker compose` commands inside the container against the host's daemon.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- **Toolchain reproducibility.** Node 22 LTS, pnpm, Nx, and Playwright are pinned in the Dockerfile. Any machine with VS Code and Docker Desktop can rebuild the environment identically.
|
||||||
|
- **Service persistence.** Postgres data survives devcontainer rebuilds because the database container has its own lifecycle and named volume.
|
||||||
|
- **Debugger simplicity.** The Nest API runs inside the devcontainer; VS Code's debugger attaches via the standard "Reopen in Container" + launch config flow.
|
||||||
|
- **File watching works.** The repo is bind-mounted into the devcontainer's Linux filesystem, where inotify behaves correctly. (It would not, were the repo mounted from `/mnt/c/`.)
|
||||||
|
- **Enterprise pattern.** This DooD setup is widely used in real-world dev environments — the developer gains transferable experience.
|
||||||
|
- **Native WSL2 fallback works.** If the devcontainer breaks, the developer can still work in native WSL2 with the same services. No lock-in.
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
- **`host.docker.internal` is Docker Desktop-specific.** A pure-Linux production-style setup (without Docker Desktop) doesn't get this hostname for free; it has to be set up manually with `extra_hosts: host-gateway`. Worth knowing for future portability.
|
||||||
|
- **Two container lifecycles to manage.** Stopping the devcontainer doesn't stop Postgres and Redis; they're independent. Slight cognitive overhead.
|
||||||
|
- **Connection strings must use `host.docker.internal`, not `localhost`.** A common stumble for new contributors. Documented in `CLAUDE.md` and `TOOLCHAIN.md`.
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
- The project deliberately doesn't use a Compose-based devcontainer where all services come up together. That pattern is appropriate for projects where the database is short-lived dev-only data; this project uses the same Postgres for development across many sessions and benefits from independent service lifecycles.
|
||||||
|
- `pnpm install` runs as a `postCreateCommand`, which means devcontainer creation takes longer but immediately yields a working environment.
|
||||||
|
|
||||||
|
## Implementation notes
|
||||||
|
|
||||||
|
- Base image: `mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm` (LTS-aligned).
|
||||||
|
- `~/.gitconfig` from the host is bind-mounted into the container so git identity persists.
|
||||||
|
- Forwarded ports: 3000 (API), 4200 (overlay dev server), 5432 (Postgres), 6379 (Redis), 443 (Caddy HTTPS).
|
||||||
|
- The `node` user has passwordless sudo (a base image convenience). This is dev-only and would not appear in a production container.
|
||||||
44
docs/adr/README.md
Executable file
44
docs/adr/README.md
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
# Architecture Decision Records
|
||||||
|
|
||||||
|
This directory contains ADRs for Fog Expedition — durable records of architectural choices, why they were made, and what trade-offs they imply.
|
||||||
|
|
||||||
|
## Format
|
||||||
|
|
||||||
|
We use [MADR](https://adr.github.io/madr/) (Markdown ADR) format. Each record has:
|
||||||
|
|
||||||
|
- **Status** — proposed, accepted, deprecated, or superseded
|
||||||
|
- **Context and problem statement** — what situation forced a decision
|
||||||
|
- **Decision drivers** — the factors that mattered
|
||||||
|
- **Considered options** — what we looked at
|
||||||
|
- **Decision outcome** — what we chose and why
|
||||||
|
- **Consequences** — what this means going forward, good and bad
|
||||||
|
|
||||||
|
## Index
|
||||||
|
|
||||||
|
| # | Title | Status |
|
||||||
|
|---|-------|--------|
|
||||||
|
| [0001](./0001-twitch-extension-type.md) | Twitch Video Overlay over Panel extension | Accepted |
|
||||||
|
| [0002](./0002-nx-monorepo-with-strict-boundaries.md) | Nx monorepo with enforced module boundaries | Accepted |
|
||||||
|
| [0003](./0003-mixed-test-runners.md) | Vitest in libs and overlay, Jest in API | Accepted |
|
||||||
|
| [0004](./0004-stateless-seeded-encounter-resolver.md) | Encounter resolver as pure library with seeded PRNG | Accepted |
|
||||||
|
| [0005](./0005-per-mission-jittered-tick-scheduling.md) | Per-mission jittered tick scheduling | Accepted |
|
||||||
|
| [0006](./0006-postgres-plus-redis-data-split.md) | PostgreSQL for durable state, Redis for ephemeral | Accepted |
|
||||||
|
| [0007](./0007-devcontainer-with-host-services.md) | Devcontainer with docker-outside-of-docker, services on host | Accepted |
|
||||||
|
|
||||||
|
## When to write a new ADR
|
||||||
|
|
||||||
|
Write one when:
|
||||||
|
|
||||||
|
- The decision has plausible alternatives that reasonable people might pick differently
|
||||||
|
- The reasoning will matter six months from now
|
||||||
|
- The decision shapes how the codebase evolves
|
||||||
|
|
||||||
|
Don't write one for:
|
||||||
|
|
||||||
|
- Style or convention (those go in `CLAUDE.md`)
|
||||||
|
- Decisions with one obvious answer (no real choice was made)
|
||||||
|
- Implementation details that change frequently (those go in code comments)
|
||||||
|
|
||||||
|
## Superseding
|
||||||
|
|
||||||
|
If a future decision overrides one here, mark the old one's status as `Superseded by ADR-NNNN` and link forward. Don't delete superseded ADRs — the history is the value.
|
||||||
@@ -1 +1,4 @@
|
|||||||
export * from './lib/api-interfaces';
|
export * from './lib/perk';
|
||||||
|
export * from './lib/survivor';
|
||||||
|
export * from './lib/mission';
|
||||||
|
export * from './lib/encounter';
|
||||||
|
|||||||
@@ -1,7 +1,199 @@
|
|||||||
import { apiInterfaces } from './api-interfaces';
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import {
|
||||||
|
EncounterResultSchema,
|
||||||
|
MissionParticipantSchema,
|
||||||
|
MissionSchema,
|
||||||
|
PerkModifierSchema,
|
||||||
|
PerkSchema,
|
||||||
|
SurvivorSchema,
|
||||||
|
SurvivorStatsSchema,
|
||||||
|
SurvivorStateSchema,
|
||||||
|
} from '../index';
|
||||||
|
|
||||||
describe('apiInterfaces', () => {
|
const PERK_ID = 'a0000000-0000-4000-8000-000000000001';
|
||||||
it('should work', () => {
|
const SURVIVOR_ID = 'a0000000-0000-4000-8000-000000000002';
|
||||||
expect(apiInterfaces()).toEqual('api-interfaces');
|
const MISSION_ID = 'a0000000-0000-4000-8000-000000000003';
|
||||||
|
|
||||||
|
const validPerk = {
|
||||||
|
id: PERK_ID,
|
||||||
|
key: 'borrowed_time',
|
||||||
|
name: 'Borrowed Time',
|
||||||
|
description: 'Extends the window for decisive action.',
|
||||||
|
tags: ['rescue', 'altruism'],
|
||||||
|
modifiers: [
|
||||||
|
{ target: 'altruism', type: 'additive', amount: 2 },
|
||||||
|
{
|
||||||
|
target: 'successChance',
|
||||||
|
type: 'multiplicative',
|
||||||
|
amount: 1.1,
|
||||||
|
condition: { encounterTags: ['hook'] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const validSurvivor = {
|
||||||
|
id: SURVIVOR_ID,
|
||||||
|
opaqueUserId: 'U123456',
|
||||||
|
channelId: 'ch_001',
|
||||||
|
name: 'Ada',
|
||||||
|
state: 'active',
|
||||||
|
stats: { objectives: 7, survival: 5, altruism: 8 },
|
||||||
|
perkSlots: [validPerk],
|
||||||
|
createdAt: '2026-01-01T00:00:00.000Z',
|
||||||
|
};
|
||||||
|
|
||||||
|
const validMission = {
|
||||||
|
id: MISSION_ID,
|
||||||
|
groupId: null,
|
||||||
|
participants: [
|
||||||
|
{
|
||||||
|
survivorId: SURVIVOR_ID,
|
||||||
|
state: 'active',
|
||||||
|
hookCount: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
difficulty: 2,
|
||||||
|
status: 'active',
|
||||||
|
encounterLibraryVersion: '1.0.0',
|
||||||
|
nextTickAt: '2026-01-01T00:01:00.000Z',
|
||||||
|
tickIndex: 0,
|
||||||
|
startedAt: '2026-01-01T00:00:00.000Z',
|
||||||
|
endedAt: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('SurvivorStateSchema', () => {
|
||||||
|
it('accepts all valid states', () => {
|
||||||
|
for (const s of ['idle', 'active', 'injured', 'downed', 'sacrificed']) {
|
||||||
|
expect(SurvivorStateSchema.parse(s)).toBe(s);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects unknown states', () => {
|
||||||
|
expect(() => SurvivorStateSchema.parse('dead')).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('SurvivorStatsSchema', () => {
|
||||||
|
it('rejects stats outside 1–10', () => {
|
||||||
|
expect(() =>
|
||||||
|
SurvivorStatsSchema.parse({ objectives: 0, survival: 5, altruism: 5 })
|
||||||
|
).toThrow();
|
||||||
|
expect(() =>
|
||||||
|
SurvivorStatsSchema.parse({ objectives: 5, survival: 11, altruism: 5 })
|
||||||
|
).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('PerkModifierSchema', () => {
|
||||||
|
it('accepts a conditional modifier', () => {
|
||||||
|
const result = PerkModifierSchema.parse(validPerk.modifiers[1]);
|
||||||
|
expect(result.condition?.encounterTags).toEqual(['hook']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('PerkSchema', () => {
|
||||||
|
it('parses a valid perk', () => {
|
||||||
|
expect(PerkSchema.parse(validPerk).key).toBe('borrowed_time');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('SurvivorSchema', () => {
|
||||||
|
it('parses a valid survivor', () => {
|
||||||
|
expect(SurvivorSchema.parse(validSurvivor).name).toBe('Ada');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects anonymous opaque user IDs', () => {
|
||||||
|
expect(() =>
|
||||||
|
SurvivorSchema.parse({ ...validSurvivor, opaqueUserId: 'A999' })
|
||||||
|
).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects more than 4 perk slots', () => {
|
||||||
|
expect(() =>
|
||||||
|
SurvivorSchema.parse({
|
||||||
|
...validSurvivor,
|
||||||
|
perkSlots: [validPerk, validPerk, validPerk, validPerk, validPerk],
|
||||||
|
})
|
||||||
|
).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('MissionParticipantSchema', () => {
|
||||||
|
it('rejects hookCount > 2', () => {
|
||||||
|
expect(() =>
|
||||||
|
MissionParticipantSchema.parse({
|
||||||
|
survivorId: SURVIVOR_ID,
|
||||||
|
state: 'downed',
|
||||||
|
hookCount: 3,
|
||||||
|
})
|
||||||
|
).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('MissionSchema', () => {
|
||||||
|
it('parses a valid solo mission', () => {
|
||||||
|
expect(MissionSchema.parse(validMission).difficulty).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects difficulty outside 1–3', () => {
|
||||||
|
expect(() =>
|
||||||
|
MissionSchema.parse({ ...validMission, difficulty: 4 })
|
||||||
|
).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects groups larger than 4', () => {
|
||||||
|
const participant = validMission.participants[0];
|
||||||
|
expect(() =>
|
||||||
|
MissionSchema.parse({
|
||||||
|
...validMission,
|
||||||
|
participants: [
|
||||||
|
participant,
|
||||||
|
participant,
|
||||||
|
participant,
|
||||||
|
participant,
|
||||||
|
participant,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('EncounterResultSchema', () => {
|
||||||
|
it('parses a successful encounter with no state change', () => {
|
||||||
|
const result = EncounterResultSchema.parse({
|
||||||
|
missionId: MISSION_ID,
|
||||||
|
survivorId: SURVIVOR_ID,
|
||||||
|
encounterKey: 'cleanse_hex',
|
||||||
|
tickIndex: 1,
|
||||||
|
seed: 'abc123',
|
||||||
|
success: true,
|
||||||
|
survivorStateChange: null,
|
||||||
|
modifiersApplied: [],
|
||||||
|
logText: 'Ada cleanses the hex totem. The fog thins briefly.',
|
||||||
|
});
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
expect(result.survivorStateChange).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parses an encounter that injures the survivor', () => {
|
||||||
|
const result = EncounterResultSchema.parse({
|
||||||
|
missionId: MISSION_ID,
|
||||||
|
survivorId: SURVIVOR_ID,
|
||||||
|
encounterKey: 'stalked',
|
||||||
|
tickIndex: 2,
|
||||||
|
seed: 'def456',
|
||||||
|
success: false,
|
||||||
|
survivorStateChange: { from: 'active', to: 'injured' },
|
||||||
|
modifiersApplied: [
|
||||||
|
{
|
||||||
|
perkKey: 'borrowed_time',
|
||||||
|
target: 'survival',
|
||||||
|
type: 'additive',
|
||||||
|
effectiveAmount: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
logText: 'Something moves in the trees. Ada takes a hit.',
|
||||||
|
});
|
||||||
|
expect(result.survivorStateChange?.to).toBe('injured');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
export function apiInterfaces(): string {
|
|
||||||
return 'api-interfaces';
|
|
||||||
}
|
|
||||||
29
libs/api-interfaces/src/lib/encounter.ts
Normal file
29
libs/api-interfaces/src/lib/encounter.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
import { PerkModifierTargetSchema, PerkModifierTypeSchema } from './perk';
|
||||||
|
import { SurvivorStateSchema } from './survivor';
|
||||||
|
|
||||||
|
export const ModifierApplicationSchema = z.object({
|
||||||
|
perkKey: z.string().min(1),
|
||||||
|
target: PerkModifierTargetSchema,
|
||||||
|
type: PerkModifierTypeSchema,
|
||||||
|
effectiveAmount: z.number(),
|
||||||
|
});
|
||||||
|
export type ModifierApplication = z.infer<typeof ModifierApplicationSchema>;
|
||||||
|
|
||||||
|
export const EncounterResultSchema = z.object({
|
||||||
|
missionId: z.uuid(),
|
||||||
|
survivorId: z.uuid(),
|
||||||
|
encounterKey: z.string().min(1),
|
||||||
|
tickIndex: z.number().int().min(0),
|
||||||
|
seed: z.string().min(1),
|
||||||
|
success: z.boolean(),
|
||||||
|
survivorStateChange: z
|
||||||
|
.object({
|
||||||
|
from: SurvivorStateSchema,
|
||||||
|
to: SurvivorStateSchema,
|
||||||
|
})
|
||||||
|
.nullable(),
|
||||||
|
modifiersApplied: z.array(ModifierApplicationSchema),
|
||||||
|
logText: z.string().min(1),
|
||||||
|
});
|
||||||
|
export type EncounterResult = z.infer<typeof EncounterResultSchema>;
|
||||||
32
libs/api-interfaces/src/lib/mission.ts
Normal file
32
libs/api-interfaces/src/lib/mission.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
import { SurvivorStateSchema } from './survivor';
|
||||||
|
|
||||||
|
export const MissionStateSchema = z.enum([
|
||||||
|
'lobby',
|
||||||
|
'active',
|
||||||
|
'success',
|
||||||
|
'sacrifice',
|
||||||
|
'abandoned',
|
||||||
|
]);
|
||||||
|
export type MissionState = z.infer<typeof MissionStateSchema>;
|
||||||
|
|
||||||
|
export const MissionParticipantSchema = z.object({
|
||||||
|
survivorId: z.uuid(),
|
||||||
|
state: SurvivorStateSchema,
|
||||||
|
hookCount: z.number().int().min(0).max(2),
|
||||||
|
});
|
||||||
|
export type MissionParticipant = z.infer<typeof MissionParticipantSchema>;
|
||||||
|
|
||||||
|
export const MissionSchema = z.object({
|
||||||
|
id: z.uuid(),
|
||||||
|
groupId: z.uuid().nullable(),
|
||||||
|
participants: z.array(MissionParticipantSchema).min(1).max(4),
|
||||||
|
difficulty: z.number().int().min(1).max(3),
|
||||||
|
status: MissionStateSchema,
|
||||||
|
encounterLibraryVersion: z.string().min(1),
|
||||||
|
nextTickAt: z.iso.datetime(),
|
||||||
|
tickIndex: z.number().int().min(0),
|
||||||
|
startedAt: z.iso.datetime(),
|
||||||
|
endedAt: z.iso.datetime().nullable(),
|
||||||
|
});
|
||||||
|
export type Mission = z.infer<typeof MissionSchema>;
|
||||||
34
libs/api-interfaces/src/lib/perk.ts
Normal file
34
libs/api-interfaces/src/lib/perk.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const PerkModifierTargetSchema = z.enum([
|
||||||
|
'successChance',
|
||||||
|
'objectives',
|
||||||
|
'survival',
|
||||||
|
'altruism',
|
||||||
|
]);
|
||||||
|
export type PerkModifierTarget = z.infer<typeof PerkModifierTargetSchema>;
|
||||||
|
|
||||||
|
export const PerkModifierTypeSchema = z.enum(['additive', 'multiplicative']);
|
||||||
|
export type PerkModifierType = z.infer<typeof PerkModifierTypeSchema>;
|
||||||
|
|
||||||
|
export const PerkModifierSchema = z.object({
|
||||||
|
target: PerkModifierTargetSchema,
|
||||||
|
type: PerkModifierTypeSchema,
|
||||||
|
amount: z.number(),
|
||||||
|
condition: z
|
||||||
|
.object({
|
||||||
|
encounterTags: z.array(z.string()).min(1),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
});
|
||||||
|
export type PerkModifier = z.infer<typeof PerkModifierSchema>;
|
||||||
|
|
||||||
|
export const PerkSchema = z.object({
|
||||||
|
id: z.uuid(),
|
||||||
|
key: z.string().min(1),
|
||||||
|
name: z.string().min(1),
|
||||||
|
description: z.string(),
|
||||||
|
tags: z.array(z.string()),
|
||||||
|
modifiers: z.array(PerkModifierSchema),
|
||||||
|
});
|
||||||
|
export type Perk = z.infer<typeof PerkSchema>;
|
||||||
30
libs/api-interfaces/src/lib/survivor.ts
Normal file
30
libs/api-interfaces/src/lib/survivor.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
import { PerkSchema } from './perk';
|
||||||
|
|
||||||
|
export const SurvivorStateSchema = z.enum([
|
||||||
|
'idle',
|
||||||
|
'active',
|
||||||
|
'injured',
|
||||||
|
'downed',
|
||||||
|
'sacrificed',
|
||||||
|
]);
|
||||||
|
export type SurvivorState = z.infer<typeof SurvivorStateSchema>;
|
||||||
|
|
||||||
|
export const SurvivorStatsSchema = z.object({
|
||||||
|
objectives: z.number().int().min(1).max(10),
|
||||||
|
survival: z.number().int().min(1).max(10),
|
||||||
|
altruism: z.number().int().min(1).max(10),
|
||||||
|
});
|
||||||
|
export type SurvivorStats = z.infer<typeof SurvivorStatsSchema>;
|
||||||
|
|
||||||
|
export const SurvivorSchema = z.object({
|
||||||
|
id: z.uuid(),
|
||||||
|
opaqueUserId: z.string().regex(/^U/, 'Must be a logged-in viewer opaque user ID'),
|
||||||
|
channelId: z.string().min(1),
|
||||||
|
name: z.string().min(1).max(32),
|
||||||
|
state: SurvivorStateSchema,
|
||||||
|
stats: SurvivorStatsSchema,
|
||||||
|
perkSlots: z.array(PerkSchema).max(4),
|
||||||
|
createdAt: z.iso.datetime(),
|
||||||
|
});
|
||||||
|
export type Survivor = z.infer<typeof SurvivorSchema>;
|
||||||
@@ -70,6 +70,7 @@
|
|||||||
"@nestjs/platform-express": "^11.0.0",
|
"@nestjs/platform-express": "^11.0.0",
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rxjs": "^7.8.0"
|
"rxjs": "^7.8.0",
|
||||||
|
"zod": "^4.4.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
86
pnpm-lock.yaml
generated
86
pnpm-lock.yaml
generated
@@ -44,6 +44,9 @@ importers:
|
|||||||
rxjs:
|
rxjs:
|
||||||
specifier: ^7.8.0
|
specifier: ^7.8.0
|
||||||
version: 7.8.2
|
version: 7.8.2
|
||||||
|
zod:
|
||||||
|
specifier: ^4.4.3
|
||||||
|
version: 4.4.3
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@angular-devkit/core':
|
'@angular-devkit/core':
|
||||||
specifier: ~21.2.0
|
specifier: ~21.2.0
|
||||||
@@ -2019,49 +2022,42 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@napi-rs/nice-linux-arm64-musl@1.1.1':
|
'@napi-rs/nice-linux-arm64-musl@1.1.1':
|
||||||
resolution: {integrity: sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==}
|
resolution: {integrity: sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@napi-rs/nice-linux-ppc64-gnu@1.1.1':
|
'@napi-rs/nice-linux-ppc64-gnu@1.1.1':
|
||||||
resolution: {integrity: sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==}
|
resolution: {integrity: sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@napi-rs/nice-linux-riscv64-gnu@1.1.1':
|
'@napi-rs/nice-linux-riscv64-gnu@1.1.1':
|
||||||
resolution: {integrity: sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==}
|
resolution: {integrity: sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@napi-rs/nice-linux-s390x-gnu@1.1.1':
|
'@napi-rs/nice-linux-s390x-gnu@1.1.1':
|
||||||
resolution: {integrity: sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==}
|
resolution: {integrity: sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@napi-rs/nice-linux-x64-gnu@1.1.1':
|
'@napi-rs/nice-linux-x64-gnu@1.1.1':
|
||||||
resolution: {integrity: sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==}
|
resolution: {integrity: sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@napi-rs/nice-linux-x64-musl@1.1.1':
|
'@napi-rs/nice-linux-x64-musl@1.1.1':
|
||||||
resolution: {integrity: sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==}
|
resolution: {integrity: sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@napi-rs/nice-openharmony-arm64@1.1.1':
|
'@napi-rs/nice-openharmony-arm64@1.1.1':
|
||||||
resolution: {integrity: sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==}
|
resolution: {integrity: sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==}
|
||||||
@@ -2302,25 +2298,21 @@ packages:
|
|||||||
resolution: {integrity: sha512-GdgPYMfbijBRFJs1absL/9QdSNLsTAGdyKykDf9CaVxEMZ92VB+pncpX9Vn/ZBCSeeWTLF+bSK3UM5v+loIObQ==}
|
resolution: {integrity: sha512-GdgPYMfbijBRFJs1absL/9QdSNLsTAGdyKykDf9CaVxEMZ92VB+pncpX9Vn/ZBCSeeWTLF+bSK3UM5v+loIObQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@nx/nx-linux-arm64-musl@22.7.1':
|
'@nx/nx-linux-arm64-musl@22.7.1':
|
||||||
resolution: {integrity: sha512-HyBgPtY1hyNTk8683nt7F29jh3lVdS/zul9vS0NgKeCSoYL3GRM3nLoTPynoHUxyVP/tWYOE3ymvnk92qYwL4Q==}
|
resolution: {integrity: sha512-HyBgPtY1hyNTk8683nt7F29jh3lVdS/zul9vS0NgKeCSoYL3GRM3nLoTPynoHUxyVP/tWYOE3ymvnk92qYwL4Q==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@nx/nx-linux-x64-gnu@22.7.1':
|
'@nx/nx-linux-x64-gnu@22.7.1':
|
||||||
resolution: {integrity: sha512-bQBgRiEsanNvKcDOjVAUPjvcp0iDLofYYUL2af2iuCDxreLOej+J6MeA5bWTLNly5ly1d4voKGTqa+OsouVyLg==}
|
resolution: {integrity: sha512-bQBgRiEsanNvKcDOjVAUPjvcp0iDLofYYUL2af2iuCDxreLOej+J6MeA5bWTLNly5ly1d4voKGTqa+OsouVyLg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@nx/nx-linux-x64-musl@22.7.1':
|
'@nx/nx-linux-x64-musl@22.7.1':
|
||||||
resolution: {integrity: sha512-gcco2GjcAztF/fRcAgFxtWxrWDnQdNmPaAN9FTt1+qQ9RUSLvdL8bQxKx4Kd9N9T+gXPlrWhMkBkKbbV09+X1Q==}
|
resolution: {integrity: sha512-gcco2GjcAztF/fRcAgFxtWxrWDnQdNmPaAN9FTt1+qQ9RUSLvdL8bQxKx4Kd9N9T+gXPlrWhMkBkKbbV09+X1Q==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@nx/nx-win32-arm64-msvc@22.7.1':
|
'@nx/nx-win32-arm64-msvc@22.7.1':
|
||||||
resolution: {integrity: sha512-IT9oEn0YQ83iPH7666aoPyTRsUzBIBJdBLMXeLX4I60fHPXWhUSGpfiLtIsgU2OfeOVb9hU9idwNh1wc4u9rWQ==}
|
resolution: {integrity: sha512-IT9oEn0YQ83iPH7666aoPyTRsUzBIBJdBLMXeLX4I60fHPXWhUSGpfiLtIsgU2OfeOVb9hU9idwNh1wc4u9rWQ==}
|
||||||
@@ -2444,49 +2436,41 @@ packages:
|
|||||||
resolution: {integrity: sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig==}
|
resolution: {integrity: sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-arm64-musl@11.19.1':
|
'@oxc-resolver/binding-linux-arm64-musl@11.19.1':
|
||||||
resolution: {integrity: sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==}
|
resolution: {integrity: sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-ppc64-gnu@11.19.1':
|
'@oxc-resolver/binding-linux-ppc64-gnu@11.19.1':
|
||||||
resolution: {integrity: sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==}
|
resolution: {integrity: sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-riscv64-gnu@11.19.1':
|
'@oxc-resolver/binding-linux-riscv64-gnu@11.19.1':
|
||||||
resolution: {integrity: sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w==}
|
resolution: {integrity: sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-riscv64-musl@11.19.1':
|
'@oxc-resolver/binding-linux-riscv64-musl@11.19.1':
|
||||||
resolution: {integrity: sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==}
|
resolution: {integrity: sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-s390x-gnu@11.19.1':
|
'@oxc-resolver/binding-linux-s390x-gnu@11.19.1':
|
||||||
resolution: {integrity: sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA==}
|
resolution: {integrity: sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-x64-gnu@11.19.1':
|
'@oxc-resolver/binding-linux-x64-gnu@11.19.1':
|
||||||
resolution: {integrity: sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==}
|
resolution: {integrity: sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-x64-musl@11.19.1':
|
'@oxc-resolver/binding-linux-x64-musl@11.19.1':
|
||||||
resolution: {integrity: sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==}
|
resolution: {integrity: sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@oxc-resolver/binding-openharmony-arm64@11.19.1':
|
'@oxc-resolver/binding-openharmony-arm64@11.19.1':
|
||||||
resolution: {integrity: sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==}
|
resolution: {integrity: sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==}
|
||||||
@@ -2542,42 +2526,36 @@ packages:
|
|||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm-musl@2.5.6':
|
'@parcel/watcher-linux-arm-musl@2.5.6':
|
||||||
resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
|
resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm64-glibc@2.5.6':
|
'@parcel/watcher-linux-arm64-glibc@2.5.6':
|
||||||
resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
|
resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm64-musl@2.5.6':
|
'@parcel/watcher-linux-arm64-musl@2.5.6':
|
||||||
resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
|
resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-x64-glibc@2.5.6':
|
'@parcel/watcher-linux-x64-glibc@2.5.6':
|
||||||
resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
|
resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-x64-musl@2.5.6':
|
'@parcel/watcher-linux-x64-musl@2.5.6':
|
||||||
resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
|
resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@parcel/watcher-win32-arm64@2.5.6':
|
'@parcel/watcher-win32-arm64@2.5.6':
|
||||||
resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==}
|
resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==}
|
||||||
@@ -2721,70 +2699,60 @@ packages:
|
|||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4':
|
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4':
|
||||||
resolution: {integrity: sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==}
|
resolution: {integrity: sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.17':
|
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.17':
|
||||||
resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==}
|
resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.4':
|
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.4':
|
||||||
resolution: {integrity: sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==}
|
resolution: {integrity: sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17':
|
'@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17':
|
||||||
resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==}
|
resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17':
|
'@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17':
|
||||||
resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==}
|
resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.17':
|
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.17':
|
||||||
resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==}
|
resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.4':
|
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.4':
|
||||||
resolution: {integrity: sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==}
|
resolution: {integrity: sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-musl@1.0.0-rc.17':
|
'@rolldown/binding-linux-x64-musl@1.0.0-rc.17':
|
||||||
resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==}
|
resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rolldown/binding-linux-x64-musl@1.0.0-rc.4':
|
'@rolldown/binding-linux-x64-musl@1.0.0-rc.4':
|
||||||
resolution: {integrity: sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==}
|
resolution: {integrity: sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rolldown/binding-openharmony-arm64@1.0.0-rc.17':
|
'@rolldown/binding-openharmony-arm64@1.0.0-rc.17':
|
||||||
resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==}
|
resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==}
|
||||||
@@ -2872,79 +2840,66 @@ packages:
|
|||||||
resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==}
|
resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.60.3':
|
'@rollup/rollup-linux-arm-musleabihf@4.60.3':
|
||||||
resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==}
|
resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.60.3':
|
'@rollup/rollup-linux-arm64-gnu@4.60.3':
|
||||||
resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==}
|
resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.60.3':
|
'@rollup/rollup-linux-arm64-musl@4.60.3':
|
||||||
resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==}
|
resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-loong64-gnu@4.60.3':
|
'@rollup/rollup-linux-loong64-gnu@4.60.3':
|
||||||
resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==}
|
resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-loong64-musl@4.60.3':
|
'@rollup/rollup-linux-loong64-musl@4.60.3':
|
||||||
resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==}
|
resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-gnu@4.60.3':
|
'@rollup/rollup-linux-ppc64-gnu@4.60.3':
|
||||||
resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==}
|
resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-musl@4.60.3':
|
'@rollup/rollup-linux-ppc64-musl@4.60.3':
|
||||||
resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==}
|
resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.60.3':
|
'@rollup/rollup-linux-riscv64-gnu@4.60.3':
|
||||||
resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==}
|
resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-musl@4.60.3':
|
'@rollup/rollup-linux-riscv64-musl@4.60.3':
|
||||||
resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==}
|
resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.60.3':
|
'@rollup/rollup-linux-s390x-gnu@4.60.3':
|
||||||
resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==}
|
resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.60.3':
|
'@rollup/rollup-linux-x64-gnu@4.60.3':
|
||||||
resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==}
|
resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.60.3':
|
'@rollup/rollup-linux-x64-musl@4.60.3':
|
||||||
resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==}
|
resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-openbsd-x64@4.60.3':
|
'@rollup/rollup-openbsd-x64@4.60.3':
|
||||||
resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==}
|
resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==}
|
||||||
@@ -2990,25 +2945,21 @@ packages:
|
|||||||
resolution: {integrity: sha512-fvZX6xZPvBT8qipSpvkKMX5M7yd2BSpZNCZXcefw6gA3uC7LI3gu+er0LrDXY1PtPzVuHTyDx+abwWpagV3PiQ==}
|
resolution: {integrity: sha512-fvZX6xZPvBT8qipSpvkKMX5M7yd2BSpZNCZXcefw6gA3uC7LI3gu+er0LrDXY1PtPzVuHTyDx+abwWpagV3PiQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rspack/binding-linux-arm64-musl@1.6.8':
|
'@rspack/binding-linux-arm64-musl@1.6.8':
|
||||||
resolution: {integrity: sha512-++XMKcMNrt59HcFBLnRaJcn70k3X0GwkAegZBVpel8xYIAgvoXT5+L8P1ExId/yTFxqedaz8DbcxQnNmMozviw==}
|
resolution: {integrity: sha512-++XMKcMNrt59HcFBLnRaJcn70k3X0GwkAegZBVpel8xYIAgvoXT5+L8P1ExId/yTFxqedaz8DbcxQnNmMozviw==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rspack/binding-linux-x64-gnu@1.6.8':
|
'@rspack/binding-linux-x64-gnu@1.6.8':
|
||||||
resolution: {integrity: sha512-tv3BWkTE1TndfX+DsE1rSTg8fBevCxujNZ3MlfZ22Wfy9x1FMXTJlWG8VIOXmaaJ1wUHzv8S7cE2YUUJ2LuiCg==}
|
resolution: {integrity: sha512-tv3BWkTE1TndfX+DsE1rSTg8fBevCxujNZ3MlfZ22Wfy9x1FMXTJlWG8VIOXmaaJ1wUHzv8S7cE2YUUJ2LuiCg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rspack/binding-linux-x64-musl@1.6.8':
|
'@rspack/binding-linux-x64-musl@1.6.8':
|
||||||
resolution: {integrity: sha512-DCGgZ5/in1O3FjHWqXnDsncRy+48cMhfuUAAUyl0yDj1NpsZu9pP+xfGLvGcQTiYrVl7IH9Aojf1eShP/77WGA==}
|
resolution: {integrity: sha512-DCGgZ5/in1O3FjHWqXnDsncRy+48cMhfuUAAUyl0yDj1NpsZu9pP+xfGLvGcQTiYrVl7IH9Aojf1eShP/77WGA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rspack/binding-wasm32-wasi@1.6.8':
|
'@rspack/binding-wasm32-wasi@1.6.8':
|
||||||
resolution: {integrity: sha512-VUwdhl/lI4m6o1OGCZ9JwtMjTV/yLY5VZTQdEPKb40JMTlmZ5MBlr5xk7ByaXXYHr6I+qnqEm73iMKQvg6iknw==}
|
resolution: {integrity: sha512-VUwdhl/lI4m6o1OGCZ9JwtMjTV/yLY5VZTQdEPKb40JMTlmZ5MBlr5xk7ByaXXYHr6I+qnqEm73iMKQvg6iknw==}
|
||||||
@@ -3138,42 +3089,36 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@swc/core-linux-arm64-musl@1.15.33':
|
'@swc/core-linux-arm64-musl@1.15.33':
|
||||||
resolution: {integrity: sha512-il7tYM+CpUNzieQbwAjFT1P8zqAhmGWNAGhQZBnxurXZ0aNn+5nqYFTEUKNZl7QibtT0uQXzTZrNGHCIj6Y1Og==}
|
resolution: {integrity: sha512-il7tYM+CpUNzieQbwAjFT1P8zqAhmGWNAGhQZBnxurXZ0aNn+5nqYFTEUKNZl7QibtT0uQXzTZrNGHCIj6Y1Og==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@swc/core-linux-ppc64-gnu@1.15.33':
|
'@swc/core-linux-ppc64-gnu@1.15.33':
|
||||||
resolution: {integrity: sha512-ZtNBwN0Z7CFj9Il0FcPaKdjgP7URyKu/3RfH46vq+0paOBqLj4NYldD6Qo//Duif/7IOtAraUfDOmp0PLAufog==}
|
resolution: {integrity: sha512-ZtNBwN0Z7CFj9Il0FcPaKdjgP7URyKu/3RfH46vq+0paOBqLj4NYldD6Qo//Duif/7IOtAraUfDOmp0PLAufog==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@swc/core-linux-s390x-gnu@1.15.33':
|
'@swc/core-linux-s390x-gnu@1.15.33':
|
||||||
resolution: {integrity: sha512-De1IyajoOmhOYYjw/lx66bKlyDpHZTueqwpDrWgf5O7T6d1ODeJJO9/OqMBmrBQc5C+dNnlmIufHsp4QVCWufA==}
|
resolution: {integrity: sha512-De1IyajoOmhOYYjw/lx66bKlyDpHZTueqwpDrWgf5O7T6d1ODeJJO9/OqMBmrBQc5C+dNnlmIufHsp4QVCWufA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@swc/core-linux-x64-gnu@1.15.33':
|
'@swc/core-linux-x64-gnu@1.15.33':
|
||||||
resolution: {integrity: sha512-mGTH0YxmUN+x6vRN/I6NOk5X0ogNktkwPnJ94IMvR7QjhRDwL0O8RXEDhyUM0YtwWrryBOqaJQBX4zruxEPRGw==}
|
resolution: {integrity: sha512-mGTH0YxmUN+x6vRN/I6NOk5X0ogNktkwPnJ94IMvR7QjhRDwL0O8RXEDhyUM0YtwWrryBOqaJQBX4zruxEPRGw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@swc/core-linux-x64-musl@1.15.33':
|
'@swc/core-linux-x64-musl@1.15.33':
|
||||||
resolution: {integrity: sha512-hj628ZkSEJf6zMf5VMbYrG2O6QqyTIp2qwY6VlCjvIa9lAEZ5c2lfPblCLVGYubTeLJDxadLB/CxqQYOQABeEQ==}
|
resolution: {integrity: sha512-hj628ZkSEJf6zMf5VMbYrG2O6QqyTIp2qwY6VlCjvIa9lAEZ5c2lfPblCLVGYubTeLJDxadLB/CxqQYOQABeEQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@swc/core-win32-arm64-msvc@1.15.33':
|
'@swc/core-win32-arm64-msvc@1.15.33':
|
||||||
resolution: {integrity: sha512-GV2oohtN2/5+KSccl86VULu3aT+LrISC8uzgSq0FRnikpD+Zwc+sBlXmoKQ+Db6jI57ITUOIB8jRkdGMABC29g==}
|
resolution: {integrity: sha512-GV2oohtN2/5+KSccl86VULu3aT+LrISC8uzgSq0FRnikpD+Zwc+sBlXmoKQ+Db6jI57ITUOIB8jRkdGMABC29g==}
|
||||||
@@ -3468,49 +3413,41 @@ packages:
|
|||||||
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
|
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
|
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
|
||||||
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
|
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
|
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
|
||||||
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
|
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
|
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
|
||||||
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
|
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
|
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
|
||||||
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
|
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
|
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
|
||||||
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
|
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
|
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
|
||||||
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
|
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
|
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
|
||||||
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
|
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
|
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
|
||||||
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
|
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
|
||||||
@@ -5715,28 +5652,24 @@ packages:
|
|||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
lightningcss-linux-arm64-musl@1.32.0:
|
lightningcss-linux-arm64-musl@1.32.0:
|
||||||
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
|
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
lightningcss-linux-x64-gnu@1.32.0:
|
lightningcss-linux-x64-gnu@1.32.0:
|
||||||
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
|
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
lightningcss-linux-x64-musl@1.32.0:
|
lightningcss-linux-x64-musl@1.32.0:
|
||||||
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
|
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
lightningcss-win32-arm64-msvc@1.32.0:
|
lightningcss-win32-arm64-msvc@1.32.0:
|
||||||
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
|
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
|
||||||
@@ -6893,56 +6826,48 @@ packages:
|
|||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: glibc
|
|
||||||
|
|
||||||
sass-embedded-linux-arm@1.99.0:
|
sass-embedded-linux-arm@1.99.0:
|
||||||
resolution: {integrity: sha512-d4IjJZrX2+AwB2YCy1JySwdptJECNP/WfAQLUl8txI3ka8/d3TUI155GtelnoZUkio211PwIeFvvAeZ9RXPQnw==}
|
resolution: {integrity: sha512-d4IjJZrX2+AwB2YCy1JySwdptJECNP/WfAQLUl8txI3ka8/d3TUI155GtelnoZUkio211PwIeFvvAeZ9RXPQnw==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: glibc
|
|
||||||
|
|
||||||
sass-embedded-linux-musl-arm64@1.99.0:
|
sass-embedded-linux-musl-arm64@1.99.0:
|
||||||
resolution: {integrity: sha512-Hi2bt/IrM5P4FBKz6EcHAlniwfpoz9mnTdvSd58y+avA3SANM76upIkAdSayA8ZGwyL3gZokru1AKDPF9lJDNw==}
|
resolution: {integrity: sha512-Hi2bt/IrM5P4FBKz6EcHAlniwfpoz9mnTdvSd58y+avA3SANM76upIkAdSayA8ZGwyL3gZokru1AKDPF9lJDNw==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: musl
|
|
||||||
|
|
||||||
sass-embedded-linux-musl-arm@1.99.0:
|
sass-embedded-linux-musl-arm@1.99.0:
|
||||||
resolution: {integrity: sha512-2gvHOupgIw3ytatXT4nFUow71LFbuOZPEwG+HUzcNQDH8ue4Ez8cr03vsv5MDv3lIjOKcXwDvWD980t18MwkoQ==}
|
resolution: {integrity: sha512-2gvHOupgIw3ytatXT4nFUow71LFbuOZPEwG+HUzcNQDH8ue4Ez8cr03vsv5MDv3lIjOKcXwDvWD980t18MwkoQ==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: musl
|
|
||||||
|
|
||||||
sass-embedded-linux-musl-riscv64@1.99.0:
|
sass-embedded-linux-musl-riscv64@1.99.0:
|
||||||
resolution: {integrity: sha512-mKqGvVaJ9rHMqyZsF0kikQe4NO0f4osb67+X6nLhBiVDKvyazQHJ3zJQreNefIE36yL2sjHIclSB//MprzaQDg==}
|
resolution: {integrity: sha512-mKqGvVaJ9rHMqyZsF0kikQe4NO0f4osb67+X6nLhBiVDKvyazQHJ3zJQreNefIE36yL2sjHIclSB//MprzaQDg==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: musl
|
|
||||||
|
|
||||||
sass-embedded-linux-musl-x64@1.99.0:
|
sass-embedded-linux-musl-x64@1.99.0:
|
||||||
resolution: {integrity: sha512-huhgOMmOc30r7CH7qbRbT9LerSEGSnWuS4CYNOskr9BvNeQp4dIneFufNRGZ7hkOAxUM8DglxIZJN/cyAT95Ew==}
|
resolution: {integrity: sha512-huhgOMmOc30r7CH7qbRbT9LerSEGSnWuS4CYNOskr9BvNeQp4dIneFufNRGZ7hkOAxUM8DglxIZJN/cyAT95Ew==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: musl
|
|
||||||
|
|
||||||
sass-embedded-linux-riscv64@1.99.0:
|
sass-embedded-linux-riscv64@1.99.0:
|
||||||
resolution: {integrity: sha512-mevFPIFAVhrH90THifxLfOntFmHtcEKOcdWnep2gJ0X4DVva4AiVIRlQe/7w9JFx5+gnDRE1oaJJkzuFUuYZsA==}
|
resolution: {integrity: sha512-mevFPIFAVhrH90THifxLfOntFmHtcEKOcdWnep2gJ0X4DVva4AiVIRlQe/7w9JFx5+gnDRE1oaJJkzuFUuYZsA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: glibc
|
|
||||||
|
|
||||||
sass-embedded-linux-x64@1.99.0:
|
sass-embedded-linux-x64@1.99.0:
|
||||||
resolution: {integrity: sha512-9k7IkULqIZdCIVt4Mboryt6vN8Mjmm3EhI1P3mClU5y5i3wLK5ExC3cbVWk047KsID/fvB1RLslqghXJx5BoxA==}
|
resolution: {integrity: sha512-9k7IkULqIZdCIVt4Mboryt6vN8Mjmm3EhI1P3mClU5y5i3wLK5ExC3cbVWk047KsID/fvB1RLslqghXJx5BoxA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: glibc
|
|
||||||
|
|
||||||
sass-embedded-unknown-all@1.99.0:
|
sass-embedded-unknown-all@1.99.0:
|
||||||
resolution: {integrity: sha512-P7MxiUtL/XzGo3PX0CaB8lNNEFLQWKikPA8pbKytx9ZCLZSDkt2NJcdAbblB/sqMs4AV3EK2NadV8rI/diq3xg==}
|
resolution: {integrity: sha512-P7MxiUtL/XzGo3PX0CaB8lNNEFLQWKikPA8pbKytx9ZCLZSDkt2NJcdAbblB/sqMs4AV3EK2NadV8rI/diq3xg==}
|
||||||
@@ -8098,6 +8023,9 @@ packages:
|
|||||||
zod@4.3.6:
|
zod@4.3.6:
|
||||||
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||||
|
|
||||||
|
zod@4.4.3:
|
||||||
|
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@acemir/cssom@0.9.31': {}
|
'@acemir/cssom@0.9.31': {}
|
||||||
@@ -17041,3 +16969,5 @@ snapshots:
|
|||||||
zod: 4.3.6
|
zod: 4.3.6
|
||||||
|
|
||||||
zod@4.3.6: {}
|
zod@4.3.6: {}
|
||||||
|
|
||||||
|
zod@4.4.3: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user