Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/articles/concepts/abstractions-first.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ SquidStd is built abstractions-first: code depends on contracts, and concrete ba

## Contract package plus provider packages

Each capability is a contract package paired with one or more provider packages. The contract package `*.Abstractions` defines the interfaces and DTOs. Provider packages implement them. Your application references the abstraction and depends on the provider only in the host project. See the [architecture](architecture.md) overview for how this shapes the package graph.
Each capability is a contract package paired with one or more provider packages. The contract package - `*.Abstractions` - defines the interfaces and DTOs. Provider packages implement them. Your application references the abstraction and depends on the provider only in the host project. See the [architecture](architecture.md) overview for how this shapes the package graph.

## In-memory for tests, external for prod

Most capabilities ship an in-memory provider for tests and an external-backend provider for production:

- **Messaging** in-memory, or `SquidStd.Messaging.RabbitMq` / `SquidStd.Messaging.Sqs`.
- **Caching** in-memory, or `SquidStd.Caching.Redis`.
- **Storage** file-backed, or `SquidStd.Storage.S3` (S3 and MinIO).
- **Messaging** - in-memory, or `SquidStd.Messaging.RabbitMq` / `SquidStd.Messaging.Sqs`.
- **Caching** - in-memory, or `SquidStd.Caching.Redis`.
- **Storage** - file-backed, or `SquidStd.Storage.S3` (S3 and MinIO).

Tests run fast and deterministically against the in-memory provider; production swaps in the external backend.

## Swapping providers without touching call sites

Because call sites depend only on the contract, switching backends is a registration change in the host `container.AddInMemoryMessaging()` versus `container.AddRabbitMqMessaging(...)` with no edits to the code that publishes or consumes messages. See [dependency injection](dependency-injection.md) for the registration pattern that makes the swap a one-line change.
Because call sites depend only on the contract, switching backends is a registration change in the host - `container.AddInMemoryMessaging()` versus `container.AddRabbitMqMessaging(...)` - with no edits to the code that publishes or consumes messages. See [dependency injection](dependency-injection.md) for the registration pattern that makes the swap a one-line change.
12 changes: 6 additions & 6 deletions docs/articles/concepts/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ Every capability is split in two: an `*.Abstractions` package that holds the con

The dependency flow runs in one direction:

- **Core** (`SquidStd.Core`) primitives, options, and the building blocks everything else sits on.
- **Abstractions** per-capability contract packages.
- **Providers** concrete implementations of those contracts.
- **Host** `SquidStdBootstrap` composes services and runs them.
- **Core** (`SquidStd.Core`) - primitives, options, and the building blocks everything else sits on.
- **Abstractions** - per-capability contract packages.
- **Providers** - concrete implementations of those contracts.
- **Host** - `SquidStdBootstrap` composes services and runs them.

Higher layers depend on lower ones, never the reverse.

Expand All @@ -30,5 +30,5 @@ graph TD

## Next

- [Bootstrap lifecycle](bootstrap-lifecycle.md) how the host starts and stops services.
- [Abstractions first](abstractions-first.md) the contract-plus-provider pattern in depth.
- [Bootstrap lifecycle](bootstrap-lifecycle.md) - how the host starts and stops services.
- [Abstractions first](abstractions-first.md) - the contract-plus-provider pattern in depth.
2 changes: 1 addition & 1 deletion docs/articles/concepts/messaging-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The Event Bus (`IEventBus`) is a stateless broadcast. Publishers call `PublishAs

## Command Dispatcher

The Command Dispatcher is a stateless request routed to a single handler that returns a result. Unlike the Event Bus there is exactly one handler per command, and the caller awaits its result. Use it for request/response work validating input, performing an operation, returning an outcome where ownership of the action is unambiguous.
The Command Dispatcher is a stateless request routed to a single handler that returns a result. Unlike the Event Bus there is exactly one handler per command, and the caller awaits its result. Use it for request/response work - validating input, performing an operation, returning an outcome - where ownership of the action is unambiguous.

## Actors

Expand Down
14 changes: 7 additions & 7 deletions docs/articles/felix.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Felix Network

**[Felix Network](https://github.com/tgiachi/SquidStd-Felix)** is a standalone companion library to
SquidStd: secure, cross-platform **binary mesh networking** for .NET and for a constrained C
SquidStd: secure, cross-platform **binary mesh networking** for .NET - and for a constrained C
target such as the ESP32. It lives in its own repository and ships its own NuGet packages under the
`SquidStd.Felix.*` prefix.

Expand All @@ -12,15 +12,15 @@ nodes over **ENet** (reliable UDP), behind a small **portable binary frame** tha
can speak byte-for-byte. On top of that secure node it adds an optional self-forming **mesh** layer
(seed discovery + gossip of the peer list with auto-connect).

- **Secure node** ENet transport, the portable frame (its header is authenticated as AES-GCM
- **Secure node** - ENet transport, the portable frame (its header is authenticated as AES-GCM
additional data), best-effort DEFLATE, and a raw `(type, bytes)` API.
- **Typed layer** optional `Send<T>` / `On<T>` over MemoryPack with a `[FelixMessage(id)]`
- **Typed layer** - optional `Send<T>` / `On<T>` over MemoryPack with a `[FelixMessage(id)]`
attribute mapping message types to wire ids.
- **Mesh** fully-connected, self-healing peer discovery via seeds and portable gossip.
- **Pluggable transport** the encrypted frame is transport-agnostic; `ITransport` decouples the
- **Mesh** - fully-connected, self-healing peer discovery via seeds and portable gossip.
- **Pluggable transport** - the encrypted frame is transport-agnostic; `ITransport` decouples the
node from the link (ENet ships; a serial/UART transport carries Felix over a reliable serial or
Bluetooth RFCOMM stream without WiFi).
- **Portable** the wire format is documented for non-.NET targets, with a host-testable C core
- **Portable** - the wire format is documented for non-.NET targets, with a host-testable C core
(`felix-c`) and ESP32 (ESP-IDF) examples proving byte-for-byte C↔.NET parity.

## Packages
Expand Down Expand Up @@ -84,7 +84,7 @@ mesh.Broadcast(type: 7, "hi mesh"u8.ToArray());

The protocol is portable. The Felix repository ships a portable C core (`felix-c`: AES-256-GCM over
mbedTLS, raw-DEFLATE inflate, the Felix frame, an ENet leaf transport, and a `felix_serial` UART
module) plus host harnesses all testable without an ESP32, proving byte-for-byte C↔.NET parity.
module) plus host harnesses - all testable without an ESP32, proving byte-for-byte C↔.NET parity.
The same C builds on an ESP32 (ESP-IDF), over ENet/WiFi or over UART / Bluetooth Classic SPP.

## Learn more
Expand Down
2 changes: 1 addition & 1 deletion docs/articles/guides/choosing-search-database.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ bootstrap.ConfigureServices(container => container.RegisterDatabase());

Reach for `AddElasticsearch` when the core requirement is searching text or
documents by relevance; use `RegisterDatabase` with the FreeSql provider that
matches your engine for everything relational. They compose many apps use both.
matches your engine for everything relational. They compose - many apps use both.
2 changes: 1 addition & 1 deletion docs/articles/guides/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ hashing credentials, protecting payloads with a key, and storing named secrets.
## Recommendation

Use `HashUtils` for credentials, `ISecretProtector` (AES-GCM locally, KMS in the
cloud) for encrypting blobs, and `ISecretStore` for named secrets backed by
cloud) for encrypting blobs, and `ISecretStore` for named secrets - backed by
files in development and AWS Secrets Manager in production.
2 changes: 1 addition & 1 deletion docs/articles/health-checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The health-check aggregator (`IHealthCheckService` in `SquidStd.Core`, implement

- Implement `IHealthCheck` (`Name` + `CheckAsync`) and register it as `IHealthCheck`.
- `CheckHealthAsync()` runs all checks **in parallel**, each with a per-check timeout and exception
isolation a failing or timed-out check becomes an `Unhealthy` entry without breaking the others.
isolation - a failing or timed-out check becomes an `Unhealthy` entry without breaking the others.
- The overall `HealthReport.Status` is `Unhealthy` if any check is `Unhealthy`, otherwise `Healthy`.

```csharp
Expand Down
6 changes: 3 additions & 3 deletions docs/articles/scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ standard 5-field cron expressions evaluated in UTC.

- `Schedule(name, cronExpression, handler)` → returns a job id.
- `Unschedule(jobId)` / `UnscheduleByName(name)`.
- `Jobs` a snapshot of registered jobs (`CronJobInfo`).
- `Jobs` - a snapshot of registered jobs (`CronJobInfo`).

Each job is a one-shot, self-rescheduling timer on the timer wheel: when it fires, the handler is
dispatched through `IJobSystem`, and the next occurrence is registered. An occurrence is **skipped** if the
Expand All @@ -31,7 +31,7 @@ scheduler.Schedule("cleanup", "0 3 * * *", async ct =>
## Event loop

For applications that need a tight, frame-driven loop (game servers, simulations, real-time
processing), `SquidStd.Services.Core` provides `EventLoopService` a dedicated background thread
processing), `SquidStd.Services.Core` provides `EventLoopService` - a dedicated background thread
(`SquidStd-EventLoop`) that, every frame:

1. drains the `IMainThreadDispatcher` (deferred callbacks posted with `Post`), and
Expand Down Expand Up @@ -67,7 +67,7 @@ eventLoop:
### Event loop vs. timer-wheel pump

Both `EventLoopService` and `TimerWheelPumpService` advance the timer wheel, so they are **mutually
exclusive** register exactly one. The exclusivity is structural: both implement the
exclusive** - register exactly one. The exclusivity is structural: both implement the
`ITimerWheelDriver` marker, `RegisterEventLoop()` throws if a driver is already registered, and modules
that need the wheel (the worker manager, the mail poller) auto-register the pump only when no driver is
present. Use the pump for ordinary apps where a coarse periodic pump is enough; use the event loop when
Expand Down
4 changes: 2 additions & 2 deletions docs/articles/serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

SquidStd uses a single serialization abstraction across the framework, defined in `SquidStd.Core`:

- `IDataSerializer` `ReadOnlyMemory<byte> Serialize<T>(T value)`
- `IDataDeserializer` `T Deserialize<T>(ReadOnlyMemory<byte> data)`
- `IDataSerializer` - `ReadOnlyMemory<byte> Serialize<T>(T value)`
- `IDataDeserializer` - `T Deserialize<T>(ReadOnlyMemory<byte> data)`

The default implementation, `JsonDataSerializer`, uses `System.Text.Json` Web defaults and implements
both interfaces. It is registered by `RegisterCoreServices()` (via `RegisterDataSerializer()`), so both
Expand Down
16 changes: 8 additions & 8 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ _layout: landing

# SquidStd

A batteries-included, modular standard library for .NET 10 distilled from years of building
A batteries-included, modular standard library for .NET 10 - distilled from years of building
real-world server software. Each capability ships behind a small contract with an in-memory
implementation for tests and a production backend, published as a focused NuGet package.

Security & crypto, configuration, persistence, messaging, caching, storage, a virtual filesystem,
search, mail, workers, actors, telemetry, scripting take only what you need.
search, mail, workers, actors, telemetry, scripting - take only what you need.

## Start here

- **[Tutorials](tutorials/index.md)** learn by building: bootstrap, caching, messaging, workers,
- **[Tutorials](tutorials/index.md)** - learn by building: bootstrap, caching, messaging, workers,
crypto, persistence, and more.
- **[Guides](articles/guides/configuration.md)** task-focused how-to and "which provider" decision guides.
- **[Concepts](articles/concepts/architecture.md)** the architecture and the ideas behind it.
- **[Packages](articles/getting-started.md)** per-package reference.
- **[API reference](api/index.md)** full type/member documentation.
- **[Felix Network](articles/felix.md)** companion secure binary mesh-networking library (.NET + C/ESP32).
- **[Guides](articles/guides/configuration.md)** - task-focused how-to and "which provider" decision guides.
- **[Concepts](articles/concepts/architecture.md)** - the architecture and the ideas behind it.
- **[Packages](articles/getting-started.md)** - per-package reference.
- **[API reference](api/index.md)** - full type/member documentation.
- **[Felix Network](articles/felix.md)** - companion secure binary mesh-networking library (.NET + C/ESP32).
2 changes: 1 addition & 1 deletion docs/tutorials/caching.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ A host that resolves `ICacheService` (`SquidStd.Caching.Abstractions`) backed by

### 3. Switch to Redis

Replace the registration with the Redis backend the `ICacheService` usage is identical:
Replace the registration with the Redis backend - the `ICacheService` usage is identical:

```csharp
container.AddRedisCache("redis://localhost:6379");
Expand Down
6 changes: 3 additions & 3 deletions docs/tutorials/command-dispatcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Register typed command handlers, dispatch commands against a context, and read b

A `Container` with a `RegisterCommandDispatcher<Session>` and several handlers
(`SquidStd.Services.Core`), dispatching commands that carry a `Session` context. One command type
has two handlers both run on dispatch.
has two handlers - both run on dispatch.

## Prerequisites

Expand All @@ -19,14 +19,14 @@ has two handlers — both run on dispatch.

Register the dispatcher for the context type, then each handler. `EchoCommand` has two handlers
(`EchoHandler` and `AuditHandler`); both will run. The subscription loop is what
`CommandDispatcherActivator<Session>` does at runtime inlined here to keep the sample
`CommandDispatcherActivator<Session>` does at runtime - inlined here to keep the sample
self-contained.

[!code-csharp[](../../samples/SquidStd.Samples.Commands/Program.cs#step-1)]

### 2. Dispatch commands with a context

The context (here a `Session`) is passed explicitly at dispatch time in a server this is the
The context (here a `Session`) is passed explicitly at dispatch time - in a server this is the
session the message arrived on.

[!code-csharp[](../../samples/SquidStd.Samples.Commands/Program.cs#step-2)]
Expand Down
8 changes: 4 additions & 4 deletions docs/tutorials/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ keys survive a restart by reloading them from the armored `.asc` files on disk.

### 1. Register the PGP services and a file-backed key store

`RegisterPgp` wires the keyring and `IPgpService`; the factory chooses the key store here a
`RegisterPgp` wires the keyring and `IPgpService`; the factory chooses the key store - here a
`FilePgpKeyStore` that reads and writes armored `.asc` files in a directory.

[!code-csharp[](../../samples/SquidStd.Samples.Crypto/Program.cs#step-1)]
Expand Down Expand Up @@ -45,7 +45,7 @@ survives a restart.

## Password-based encryption

`PasswordCipher` encrypts a payload directly under a password no key management required. Argon2id
`PasswordCipher` encrypts a payload directly under a password - no key management required. Argon2id
derives the key, AES-256-GCM seals the data, and the result is a self-describing, versioned envelope
(salt, nonce, tag and KDF cost are embedded). Decryption needs only the password and the blob.

Expand All @@ -57,7 +57,7 @@ using SquidStd.Crypto.Password.Data;
byte[] blob = PasswordCipher.Encrypt(payloadBytes, "correct horse battery staple");
byte[] back = PasswordCipher.Decrypt(blob, "correct horse battery staple");

// Text round-trip the envelope is base64-encoded, safe to store in config or JSON.
// Text round-trip - the envelope is base64-encoded, safe to store in config or JSON.
string protectedText = PasswordCipher.EncryptString("a secret", "pw");
string clear = PasswordCipher.DecryptString(protectedText, "pw");
```
Expand All @@ -66,7 +66,7 @@ The cost of the Argon2id key derivation defaults to `PbkdfCost.Moderate`. Raise
long-lived secrets:

```csharp
// PbkdfCost.Sensitive slower derivation, stronger resistance to offline attacks.
// PbkdfCost.Sensitive - slower derivation, stronger resistance to offline attacks.
byte[] strong = PasswordCipher.Encrypt(payloadBytes, "pw", PbkdfCost.Sensitive);
```

Expand Down
6 changes: 3 additions & 3 deletions docs/tutorials/events-jobs-scheduling.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ A host that uses three core services from `SquidStd.Services.Core`: the `IEventB
- .NET 10 SDK
- `dotnet add package SquidStd.Services.Core`

The cron scheduler and timer wheel are opt-in enable them with `RegisterSchedulerServices()`:
The cron scheduler and timer wheel are opt-in - enable them with `RegisterSchedulerServices()`:

[!code-csharp[](../../samples/SquidStd.Samples.EventsJobsScheduling/Program.cs#step-1)]

Expand Down Expand Up @@ -43,7 +43,7 @@ occurrence.
dotnet run --project samples/SquidStd.Samples.EventsJobsScheduling
```

You'll see `received: hello`, `job ran on a worker thread`, andif you let it run across a 5-minute boundary
You'll see `received: hello`, `job ran on a worker thread`, and, if you let it run across a 5-minute boundary,
`cron tick`.

## How it works
Expand All @@ -53,7 +53,7 @@ scheduler is driven by the timer wheel (registered by `RegisterSchedulerServices

The timer wheel is advanced by a *driver*. `RegisterSchedulerServices()` uses `TimerWheelPumpService`, a
periodic background pump. Apps that need a frame-rate loop can instead call `RegisterEventLoop()`, which advances
the wheel and drains the main-thread dispatcher on a dedicated thread see
the wheel and drains the main-thread dispatcher on a dedicated thread - see
[Scheduler → Event loop](../articles/scheduler.md#event-loop). The two are mutually exclusive: register exactly one.

## See also
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/messaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Prints `queue handled order-1` and `topic saw order-2`.
## How it works

Queues use competing-consumers with retry and dead-lettering (`MessagingOptions`); topics use transient fan-out
(at-most-once). Swap `AddInMemoryMessaging()` for `AddRabbitMqMessaging(...)` for a durable broker the
(at-most-once). Swap `AddInMemoryMessaging()` for `AddRabbitMqMessaging(...)` for a durable broker - the
`IMessageQueue`/`IMessageTopic` code is unchanged.

## See also
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ survives a restart.
## What you'll build

A standalone demo of `SquidStd.Persistence`: a `Player` store that loads existing state on
startup, appends every change to a journal, and captures a snapshot. Run it twice the second run
startup, appends every change to a journal, and captures a snapshot. Run it twice - the second run
reloads what the first saved.

## Prerequisites
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/scaffolding.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Generate ready-to-run SquidStd projects from the command line with the `SquidStd

## What you'll build

Nothing by hand you'll install the template pack and scaffold a console host, an ASP.NET app, a worker
Nothing by hand - you'll install the template pack and scaffold a console host, an ASP.NET app, a worker
microservice, and a worker manager, each pre-wired to SquidStd.

## Prerequisites
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/secrets.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ set/get/list.
### 1. Register the KMS protector and Secrets Manager store

`RegisterKmsSecretProtector` and `RegisterAwsSecretsManagerStore` take the KMS key alias, the
secret name prefix, and the AWS endpoint pointed here at a LocalStack `ServiceUrl`.
secret name prefix, and the AWS endpoint - pointed here at a LocalStack `ServiceUrl`.

[!code-csharp[](../../samples/SquidStd.Samples.Secrets/Program.cs#step-1)]

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ A host that resolves `IObjectStorageService` (`SquidStd.Storage.Abstractions`) b

### 3. Switch to S3

Replace the registration with the S3 backend the `IObjectStorageService` usage is identical:
Replace the registration with the S3 backend - the `IObjectStorageService` usage is identical:

```csharp
container.AddS3Storage(/* endpoint, bucket and credentials */);
Expand Down
Loading
Loading