Releases: SharkableIO/Sharkable
Releases · SharkableIO/Sharkable
Release list
v0.7.0
feat
- Plugin system:
ISharkPlugininterface with three lifecycle hooks —ConfigureServices(AddShark),ConfigurePipeline(UseShark),ConfigureOpenApi. Three discovery paths: NuGet/assembly auto-scanning, hot-plug folder scanning (opt.ConfigurePlugins(p => { p.ScanOnStartup = true; })), and manualopt.RegisterPlugin(). Per-folder AssemblyLoadContext isolation.opt.DisablePlugin("name")for opt-out. AOT-safe for NuGet/manual paths; folder scanning is JIT-only.
fix
- P1.1 — Dispose
AuditLogBufferafterFlushRemaining()during shutdown — CTS leak eliminated - P1.2 — Dispose
CronSchedulerrenewCtsafter lock renewal task completes - P1.3 — Unify
ResponseSizeExceededException— single shared type instead of two duplicate inner-class definitions in ETag and Idempotency middleware - P1.4 — Move exception handler to end of pipeline (just before
MapEndpoints) — catches exceptions from ALL middleware, not just auth and beyond - P1.5 — Guard
AutoCrudExtensiondynamic assembly loading behindAotModecheck — prevents reflection-based plugin discovery in AOT
refactor
- P2.1 — Extract
ISagaExecutorinterface; register viaTryAddSingleton<ISagaExecutor, SagaExecutor>; addSagaExecutorFactoryonSharkOption - P2.2 — Expose
CronLockTtlonICronSchedulerinterface (was only on concreteCronScheduler) - P2.3 — Normalize
ConfigureJwttoConfigureJwt(Action<JwtOptions>)pattern (consistent with every otherConfigureXxxmethod). OldConfigureJwt(string, string[], Action<JwtBearerOptions>?)marked[Obsolete]. - P2.4 — Normalize
ConfigureAuthorizationfrom property to methodConfigureAuthorization(Action<AuthorizationOptions>)(consistent withConfigureRateLimiter,ConfigureOutputCache, etc.) - P2.5 —
ICronJobStore.RenewJobLockAsynchas default implementation=> Task.CompletedTask(matchingISagaStore.RenewLockAsyncpattern) - P2.6 — Seal
SqlSugarOptions,Shark,AssemblyContext,UnifiedResult<T>— public classes not designed for inheritance - P2.7 — Remove dead code:
Utils.SetupModules()(never called), obsolete.SharkRequestTimeout(int, string?)DSL overload
feat
- P3.1 — Health checks enabled by default (
EnableHealthChecks = true) — every deployed app gets/healthzout of the box - P3.2 — Cron job concurrency default changed to
SkipIfRunning(wasAllowConcurrent) — safer default, prevents overlapping runs - P3.3 — Startup warning when
UnifiedResultFactoryis set withoutWrapSchemaFactory— prevents OpenAPI schema mismatch - P3.4 —
IUnifiedResultXML docs cross-referenceUnifiedResult<T>andIUnifiedResultFactorywith usage guidance andWrapSchemaFactorytip
feat
- FEAT-01 — Security headers middleware (
ConfigureSecurityHeaders()) — opt-in support forX-Content-Type-Options,X-Frame-Options,Referrer-Policy,Content-Security-Policy,Permissions-Policy,Strict-Transport-Security,Cross-Origin-Resource-Policy,Cross-Origin-Opener-Policy,Cross-Origin-Embedder-Policy - FEAT-02 — Framework metrics via
System.Diagnostics.Metrics—ISharkMetricsinterface withMetricsFactoryonSharkOption(consistent with existingIdempotencyStoreFactory/RateLimitStoreFactorypatterns); defaultSharkMetricsusesMeter("Sharkable")with counters for requests, rate-limit rejections, idempotency hit/miss/conflict, auth failures, audit drops, cron runs/failures, saga completed/compensated. Configurable viaConfigureMetrics(). Zero dependencies, AOT-compatible. - FEAT-03 —
IAuditSinkabstraction — pluggable audit sink for shipping entries to Seq/Elastic/Kafka.AuditSinkFactoryonSharkOption, defaultLoggingAuditSinkpreserves the current structured-logging behavior.AuditLogEntryrecord made public. - FEAT-05 — Per-endpoint distributed rate-limit policies —
[SharkRateLimit(limit, windowSeconds)]attribute onISharkEndpointclasses,.SharkRateLimit(limit, windowSeconds)DSL,SharkRateLimitMetadataread bySharkRateLimiterMiddlewareoverriding global defaults. - FEAT-06 — Per-endpoint idempotency via
[SharkIdempotent(ttlSeconds)]attribute — opt-in idempotency per endpoint when global is disabled.[SharkNoIdempotency]attribute unscoped (already supported per-class). Middleware now checksSharkIdempotentMetadata. - FEAT-07 — Response cache profile via
[SharkCacheProfile(durationSeconds, varyByHeader, privateOnly)]attribute — emitsCache-Controland optionalVaryheaders per endpoint group viaSharkCacheProfileFilter. Composes with ETag and Output Cache. - FEAT-08 — Request-timeout DSL —
opt.RequestTimeoutsConfigure+.SharkRequestTimeout(policyName)+.SharkRequestTimeout(ms)DSL. Thin wrapper over ASP.NET CoreAddRequestTimeouts.DefaultRequestTimeoutPolicyfor global fallback. - FEAT-09 — Unified validation error shape —
ValidationErrorMode.Messages(default, joins with"; ") andValidationErrorMode.ProblemDetails(RFC 7807 witherrorsobject mapping field → messages). Configurable viaSharkOption.ValidationErrorMode. - FEAT-10 — Parallel warmup services —
ConfigureWarmup<T>()now callable multiple times; all registeredIWarmupServiceinstances run in parallel with individual timeouts during startup. Aggregate failures propagated viaAggregateException. - FEAT-11 —
Sharkable.TestingNuGet package —SharkTestFactory<TEntryPoint>baseWebApplicationFactory,FakeIdempotencyStore,FakeRateLimitStore,UnifiedResultAssertionsfor fluent test assertions. Separate package. - FEAT-12 —
SharkOption.GroupConvention(per-group) +EndpointConvention(per-endpoint) — single place for auth policies, filters,ProducesResponseTypeconventions. - FEAT-13 — OpenAPI ergonomics —
AddOpenApiOperationTransformer()/AddOpenApiSchemaTransformer()methods onSharkOption(no need to touchOpenApiOptionsdirectly).OpenApiExampleFactoryhook for example generation. - FEAT-15 —
IApiKeyValidatorinterface withApiKeyValidationResult— carries claims/roles + optional per-keyRateLimitMultiplier.DefaultApiKeyValidatorwraps the existing static-array behavior.ApiKeyFilternow accepts the custom validator via DI. - FEAT-14 — Source generator for discovery (tracked as separate RFC; not yet implemented)
- Add
ISingleton,IScoped,ITransientmarker interfaces — classes implementing these are auto-registered in DI (same as[SingletonService]etc.)
perf
- PERF-01 —
DefaultUnifiedResultFactory.Instancesingleton;UnifiedResultFactoryHelper.ResolveFactory()caches configured factory at 5 hot-path call sites (P1) - PERF-02 — Source-generated JSON context defaults to
WriteIndented=falsefor compact production output (P1) - PERF-04 — Audit middleware caches
_redactQueryParamsHashSet in ctor instead of allocating per request (P2) - PERF-05 — Audit middleware checks
_logger.IsEnabled()before building log strings, avoiding allocations when the category is filtered out (P2) - PERF-06 — Shared
ApiKeyValidatorservice caches stored-key hashes and invalidates viaIOptionsMonitor.OnChange, replacing O(keys) SHA-256 per request (P2) - PERF-07 — Validation filter caches
ConcurrentDictionary<Type, Func<IServiceProvider, IValidator?>>per argument type, avoidingMakeGenericType+ DI lookup per request (P2) - PERF-08 — ETag middleware uses
Convert.ToHexString()instead of per-byteStringBuilder+ToString("x2")— one allocation instead of 33 (P3) - PERF-09 — Idempotency middleware uses
HashSet<string>for method check andTryGetBuffer()to avoid double body copy (P3) - PERF-10 — Profiler
TrackMemoryoption (defaultfalse) gates per-requestGC.GetTotalMemory(false)calls (P3) - PERF-11 —
HttpResponseExtension.WriteJsonAsynccaches staticJsonSerializerOptionsinstead of allocating per call (P3)
fix (memory & lifetime)
- MEM-01 —
MemoryIdempotencyStorenow owns a privateMemoryCacheinstead of hijacking the app-wideIMemoryCacheregistration (P1) - MEM-02 —
AdaptiveLimitMonitorregistered as singleton in DI withautoStart:true; DI handles disposal of the timer + process handle (P2) - MEM-03 —
AuditLogBufferconsumer survives flush failures with try/catch +Interlocked-tracked dropped-entry counter (P2) - MEM-04 —
MemoryRateLimitStoreandMemoryIdempotencyStoreimplementIDisposablesoMemoryCacheexpiration-scan timers are properly disposed (P2) - MEM-07 — ETag
CountingResponseBodydisposes its internalMemoryStreamspool;using var countingin middleware (P3)
security
- SEC-01 —
HealthCheckDetailLevelenum (StatusOnly/Description/Full);/healthzdefaults toStatusOnlyin non-Development, never leakingException.Message(P1) - SEC-02 —
ExceptionHandlerOptions.IncludeExceptionMessage(defaultfalse); production error responses return generic"An error occurred."(P2) - SEC-03 — Startup warning when OpenAPI/Scalar is enabled outside Development (P2)
- SEC-04 — Admin endpoints (
/_sharkable/jobs, profiler gate) unified on sharedApiKeyValidatorservice with hot-reload support (P3) - SEC-05 — Configuration validator warns when rate limiting is enabled without proxy ForwardedHeaders configuration (P3)
- SEC-06 —
JwtHealthCheckcaches result for 30 seconds to avoid hammering OIDC discovery endpoint on k8s probes (P3)
fix
UnifiedResultExtensionandUnifiedResultstatic methods now respectUnifiedResultFactory— custom factory implementations are used for all.AsNotFound(),UnifiedResult.Ok(), etc.- BUG-01 — Cron shutdown cancellation token wired into
ExecuteJobAsyncso in-flight jobs are cancelled onapp.StopAsync()(P1) - BUG-02 — Exception handler no longer logs client disconnects as errors and avoids writin...
v0.6.1
feat
- EnableAutoWrap defaults to true — all plain return values wrapped in UnifiedResult out of the box
- Custom IResult (UnifiedResultResult) eliminates one allocation per wrapped response and syncs HTTP status code
- Per-endpoint opt-out via [SharkDontWrap] attribute (class-level) and .DisableAutoWrap() fluent API (route-level)
refactor
- UnifiedResultWrapFilter checks endpoint metadata for DisableAutoWrapMetadata before wrapping
- ProblemDetailsResult reuses UnifiedResultResult for consistent error response writing
Full Changelog: v0.6.0...v0.6.1
v0.6.0
feat
- Add unified result extension methods and static factories for 20 HTTP status codes (202, 405, 406, 410, 415, 422, 429, 500–504)
- Add generic
AsStatus()extension andUnifiedResult.Status<T>()static factory for customHttpStatusCode— covers any status code not explicitly enumerated - Add parameterless
ConfigureAuditTrail()overload — enables audit trail with default options without requiring a callback - Add
AuditTrailFormatenum withDefault,DotnetLogger,JsonStyle, andCompactpresets — configurable viaAuditTrailOptions.LogFormat - Add
SharkOption.ShowStartupBanner(defaulttrue) — allows disabling the startup banner
feat (Phase 5 — Lifecycle & startup integrity)
- #25 Startup banner: Sharkable now prints a formatted banner (version, environment, UTC timestamp) to the console at the end of
UseShark() - #20 Lifecycle hooks:
SharkOption.ConfigureOnStarted()/ConfigureOnStopped()— register callbacks that fire onIHostApplicationLifetime.ApplicationStarted/ApplicationStopping - #22 Readiness gate:
InternalShark.StartupCompletedopens after all wiring completes;/healthzreturns 503 until then - #23 Warmup:
IWarmupServiceinterface +SharkOption.ConfigureWarmup<T>()— resolves and runs a warmup task synchronously before the readiness gate opens (30s timeout) - #27 Eager singleton:
[SingletonService(Eager = true)]— eagerly resolves the singleton from DI duringUseShark(), before the server accepts requests - #26 Pipeline injection points:
UseSharkOptions.AddBeforeAuth()/AddAfterAuth()/AddAfterEndpoints()— inject custom middleware at specific pipeline positions - #21 Liveness probe:
/livezendpoint mapped alongside/healthz— returns{"status":"alive"}unconditionally, not blocked by readiness/shutdown gates - #24 DI validation:
SharkOption.ValidateOnStart<T>()— callsGetRequiredService<T>()duringUseShark(), fails fast on missing registrations
docs
- Document all unified result extension methods and static factories in EN + ZH
- Add service registration guide covering
[ScopedService],[TransientService],[SingletonService]attributes (EN + ZH) - Add lifecycle hooks, startup banner, warmup, eager singleton, pipeline injection, DI validation guide (EN + ZH)
- Update health checks guide with readiness gate and liveness probe details (EN + ZH)
Full Changelog: v0.5.7...v0.6.0
v0.5.5
security
- Add
MaxFingerprintBodySize(default 64 KiB) toSharkIdempotencyOptions— prevent OOM via attacker-controlledContent-Lengthheader in idempotency middleware fingerprinting. Fixed chunked-transfer bypass where allTransfer-Encoding: chunkedrequests hashed to the same fingerprint (now hashes body incrementally with-1sentinel for unknown length); setter rejects<= 0 - Replace
Thread.Sleeppolling withawait Task.Delayin graceful shutdown drain — prevent ApplicationStopping thread block (SHARK-SEC-003). Initial fix used.GetAwaiter().GetResult()on the drain task which still blocked the callback; corrected to true fire-and-forget soApplicationStoppingreturns immediately. - Make
SagaExecutor.LockTtlconfigurable; addLockRenewalIntervalwith periodic lock extension — prevent split-brain sagas when step duration exceeds lock TTL (SHARK-SEC-004, cross-repo withSharkable.Cache.Redis).ISagaStore.RenewLockAsyncconverted from a required interface member to a default interface method (DIM) so existing third-party implementations keep compiling unchanged. - Replace unconditional
KeyDeleteinRedisSagaStore.ReleaseLockAsyncandRedisCronJobStore.ReleaseJobLockAsyncwith check-and-delete Lua script — prevent split-brain when LockTtl expires mid-work (SHARK-SEC-005, cross-repo withSharkable.Cache.Redis) - Add
ICronJobStore.RenewJobLockAsyncplusCronScheduler.CronLockTtl(default 10 min) and a background renewal task mirroringSagaExecutor— prevent split-brain cron jobs when job duration exceeds lock TTL (SHARK-SEC-005 follow-up, cross-repo withSharkable.Cache.Redis) - BREAKING: Add
[CrudAllow]attribute for explicit field allowlist on AutoCrud insertable/updateable — endpoints withCreate | Updateenabled and zero[CrudAllow]properties now throwInvalidOperationExceptionat startup. Existing entities must mark every writable field with[CrudAllow]. Prevents mass-assignment privilege escalation (SHARK-SEC-006) - BREAKING (SHARK-SEC-006 follow-up): Exclude the configured soft-delete column (
SqlSugarOptions.SoftDeleteFieldName, default"IsDeleted") from the[CrudAllow]allow-list even when explicitly marked — otherwise an attacker can revive soft-deleted rows by sending the field in a PUT body. Honors[SugarColumn(ColumnName = "...")]renames - BREAKING (SHARK-SEC-006 follow-up): AutoCrud
POST /andPUT /{id}now return the persisted row re-read from the database instead of the user-controlled request body — previous behavior silently hid server-side defaults (timestamps, identity-generated PK, server-set soft-delete state) from the client - Require API key on profiler endpoint
/_sharkable/profilerby default; return 404 if no API keys configured (SHARK-SEC-015). AddsSharkOption.ProfilerRequireApiKey(defaulttrue); also caps thetopslow-requests surface at 50 to bound data exposure - Require API key on cron admin endpoint
/_sharkable/jobs; redactLastErrorfield to its first 100 characters +...to prevent business-logic leakage (SHARK-SEC-016). AddsSharkOption.CronAdminRequireApiKey(defaulttrue); returns 404 if no API keys are configured - BREAKING: Make
CronScheduler.Registerasync — eliminate sync-over-async deadlock risk with distributed stores (SHARK-SEC-017).ICronScheduler.Registeris replaced byRegisterAsyncreturningTask;SharkOption.ConfigureCronJobscallback type changes fromAction<ICronScheduler>toFunc<ICronScheduler, Task>so the hosted service can await it without blocking on startup. Internalawait _store.LoadStateAsync(...)replaces.GetAwaiter().GetResult(). - Add
SharkOption.RequireAuthenticatedByDefaultopt-in flag — enforce auth on framework endpoints via fallback policy (SHARK-SEC-011, closes both H-4 and H-6) - Add
ETagOptions.MaxResponseSize(default 10 MiB) + counting stream + incremental hashing — prevent OOM via huge response bodies (SHARK-SEC-012) - Add
IMemoryCacheSizeLimit (100k) + periodic eviction sweep toMemoryRateLimitStore— prevent slow-loris DoS via unique path explosion (SHARK-SEC-013) - Add
IMemoryCacheSizeLimit (10k) + entry.Size tracking toMemoryIdempotencyStore— prevent TB-DoS via unique idempotency keys (SHARK-SEC-014) - Add JWT algorithm allowlist +
RequireSignedTokens+RequireExpirationTime+ reduceClockSkewto 30s — prevent algorithm confusion attacks (SHARK-SEC-007) - Use
CryptographicOperations.FixedTimeEqualsfor API key comparison — prevent timing oracle (SHARK-SEC-008) - Gate
ScalarJwtToken/ScalarApiKeyValuetoIHostEnvironment.IsDevelopment()— prevent token leakage to public/scalar/v1UI (SHARK-SEC-009) - Implement
AuditTrailMiddlewareheader redaction perRedactHeaderslist — credential-bearing headers (Authorization,X-Api-Key,Cookieby default) have their values replaced with***in audit log output. Header names preserved so reviewers see which credentials were presented (SHARK-SEC-010) - Redact RedisHealthCheck description — never expose topology or exception messages on public
/healthz(SHARK-SEC-018) - Validate connection string at AddSharkableRedis — null-check + default
abortConnect=false+ optional TLS enforcement (SHARK-SEC-019) - Replace
JsonSerializer.Serialize<T>with source-generatedJsonSerializerContextinRedisIdempotencyStore— Cache.Redis is now AOT-compatible (SHARK-SEC-020 follow-up, cross-repo withSharkable.Cache.Redis) - Remove auto-registration of
RedisHealthCheckasIHealthCheckinAddSharkableRedis—UseSharkableRedisHealthCheck()is the only way to wire it (SHARK-SEC-021 follow-up, cross-repo withSharkable.Cache.Redis) - Connection string: only override
abortConnect=falsewhen the key is absent — respect an explicitabortConnect=true(SHARK-SEC-019 follow-up, cross-repo withSharkable.Cache.Redis) - Replace empty catch in RedisIdempotencyStore deserialization with typed exception handling + tombstone record — prevent silent double-execution on corruption (SHARK-SEC-020)
- Add
UseSharkableRedisHealthCheck()extension — explicit opt-in to wire health check into/healthz(SHARK-SEC-021) - Set TTL on RedisSagaStore progress records via
RedisStoreOptions.SagaProgressTtl(default 7d) — prevent unbounded memory growth (SHARK-SEC-022) - Add
AutoCrudSqlSugar.AutoCrudRequireAuthorizationopt-in flag — auto-attach.RequireAuthorization()to generated CRUD endpoints. Defaultfalsefor backward compat; production deployments MUST enable. (SHARK-SEC-023, cross-repo withSharkable.AutoCrud.SqlSugar) - Defense-in-depth: also exclude
SafeSoftDeleteFieldfrom[CrudAllow]allow-list by case-insensitive name match — protects against entities whose C# property name matches the configured soft-delete column but lacks[SugarColumn]rename (SHARK-SEC-024, cross-repo withSharkable.AutoCrud.SqlSugar) - Add
AutoCrudSqlSugar.MaxPageNumber(default 1M) + overflow check on(page - 1) * pageSize— prevent pagination DoS viapage=int.MaxValueproducing a negative OFFSET (SHARK-SEC-025, cross-repo withSharkable.AutoCrud.SqlSugar) - Redact
SqlSugarHealthCheckdescription — never exposedbTypeorex.Messageon public/healthz; full diagnostic detail logged atLogWarningfor operators only (SHARK-SEC-026, cross-repo withSharkable.AutoCrud.SqlSugar) - Escape SQL
LIKEwildcards + cap filter value length (200) + capINarray size (100) in AutoCrud search — prevent LIKE wildcard DoS and large-IN clause DoS (SHARK-SEC-027, cross-repo withSharkable.AutoCrud.SqlSugar) - Fix ETag
CountingResponseBody.FlushAsyncduplicate body write on over-cap responses (SHARK-SEC-012 follow-up) - Fix
MemoryRateLimitStore.IncrementAsyncnon-atomic increment allowing concurrent bypass (SHARK-SEC-013 follow-up) - Replace
AuditTrailMiddleware.CaptureHeadersJsonSerializer.Serializewith hand-rolled formatter — AOT-compatible (SHARK-SEC-010 follow-up) - Make JWT audience validation mandatory when
ConfigureJwtis called — reject empty audience list at config time (SHARK-SEC-007 follow-up) - Strip assembly-qualified type name from
ExceptionHandlerOptions.GetErrorMessagedev output — prevent fingerprinting ofSharkable.X.Y, Version=1.0.0.0over the wire (SHARK-SEC-M003) - Redact
JwtHealthCheckdescription on/healthz— replace authority URL +ex.Messageechoes with generic descriptions; full URL + exception now surface viaILogger.LogWarningfor operators only (SHARK-SEC-M004) - Pin
CultureInfo.InvariantCultureforstring.FormatinHttpContext.Localize(key, args)— prevent culture-dependent format-string growth attacks via malicious translations (SHARK-SEC-M005) - Implement
IDisposableonAdaptiveLimitMonitor+ wrapAdjust()in try/catch — prevent timer-callback exception tearing the process down + close theProcesshandle leak (SHARK-SEC-M010) - Cap
CronExpression.GetNextiteration count at 2.2 M — bound CPU on non-matching patterns (e.g.0 0 30 2 *) that previously looped 2.1 M times per hosted-service tick (SHARK-SEC-M011) - Link
SharkCronHostedServicehost stoppingToken to a per-jobCancellationTokenSource— prevent orphaned long-running cron jobs survivingapp.StopAsync()and tripping k8s termination grace periods (SHARK-SEC-M012) - Collapse
CronSchedulerthree correlated dictionaries (_jobs/_states/_expressions) into oneDictionary<string, JobEntry>under a single lock — eliminate TOCTOU betweenRegisterandGetDueJobsAsync(SHARK-SEC-M013) - Bound
/healthzaggregateHealthCheckService.CheckHealthAsyncwith a 10 sCancellationTokenSource— prevent a single hung check from keeping the endpoint open and tripping k8s probes (SHARK-SEC-M015) JwtHealthChecknow acceptsIHttpClientFactoryvia DI — reuse a pooledHttpMessageHandlerinstead of opening a new socket per probe (SHARK-SEC-M016)- Default rate-...
v0.5.4
security
- Add 100ms regex timeout to FormatAsGroupName / GetVersionFormat — prevent ReDoS via malicious GroupNameSuffixPattern / VersionFormatPattern
- Add SafeSoftDeleteField validation in AutoCrudGenerator — reject non-alphanumeric field names to prevent SQL injection
Full Changelog: v0.5.3...v0.5.4
v0.5.3
feat
- Add
HttpContext.Localize(string key, params object[] args)overload — format args in localized strings - Add
HttpContext.GetCulture()extension — resolve client culture fromAccept-Languageheader ApiKeyFilterautomatically skipped whenAuthorizationInterceptorFactoryis set — interceptor owns auth entirely- Add
SqlSugarOptions.MaxPageSize/DefaultPageSize— configurable AutoCrud pagination limits (defaults: 100 / 20) - Add
SqlSugarOptions.SoftDeleteFieldName— configurable soft delete field (default:"IsDeleted") - Add
SharkOption.ETagOptions.CacheableMethods/CacheControlHeader/ShouldSkipStatus— ETag method set, cache header, and cacheable status logic are now configurable - Add
SharkOption.ApiKeyHeaderName— configurable API key request header - Add
GracefulShutdownOptions.ShutdownStatusCode/DrainPollingInterval— configurable 503 status code and drain polling interval - Add
SharkOption.ProblemDetailsTypeFactory/ProblemDetailsTitleFactory— delegates for customizing RFC 7807typeURI andtitle - Add
SharkOption.DefaultCulture— configurable default locale for error localizer - Add
SharkRateLimiterOptions.AdaptiveGcHighThreshold/AdaptiveGcLowThreshold/AdaptiveReductionDivisor— GC pressure thresholds and reduction factor for adaptive rate limiting - Add
ProfilerOptions.MaxEntries— configurable profiler ring buffer size - Add
SharkIdempotencyOptions.RetryAfterSeconds/ShouldCacheStatus— configurable Retry-After and cacheable status predicate - Add
SharkOption.HealthCheckPath— configurable health check endpoint path - Add
TracingOptions.ActivitySourceName— configurableActivitySourcename (separate fromServiceName) - Add
SharkOption.GroupNameSuffixPattern/VersionFormatPattern/VersionFormatReplacement— customizable endpoint URL naming regexes - Remove hardcoded
"Sharkable"ActivitySourceName inTracingMiddleware— now usesTracingOptions.ActivitySourceName - Add
HttpContext.Localize(string key)extension method — easy localization in user endpoints - Add
LocalizationExtensions— public scaffolding for endpoint-level error translation - Add
SharkOption.EnableAuthorization(defaulttrue) — allows users to opt out of authorization service registration - Add
SharkOption.ConfigureAuthorization— delegate for customizingAuthorizationOptions(policies, fallback, etc.) - Add
SharkOption.ScalarJwtToken/SharkOption.ScalarApiKeyValue— configure pre-filled credentials in Scalar UI
docs
- Add complete error localization guide with
IErrorLocalizerimplementation example,HttpContext.Localize()usage, and middleware integration pattern (EN + ZH)
fix
- Fix
InvalidOperationExceptionwhenUseAuthorizationis called withoutAddAuthorization— registerAddAuthorizationby default (configurable viaEnableAuthorization), with factory support viaConfigureAuthorizationdelegate - Fix
UnifiedResultWrapFilteralways wrapping with status 200 — now uses actualHttpContext.Response.StatusCode - Fix
AuditTrailMiddlewareresponse header hardcoded to"X-Correlation-Id"— now respectsAuditTrailOptions.CorrelationIdHeader
v0.5.1
v0.3.2
v0.3.1
v0.3.0
What's Changed
- fix: correct license expression, add README.md and packaging items by @charleypeng in #71
- docs: comprehensive README.md update with all features by @charleypeng in #72
- feat: add test project + NativeTest demo improvements by @charleypeng in #73
- Feat/tests and native test demo by @charleypeng in #75
- Feat/tests and native test demo by @charleypeng in #76
- add built-in middleware (E) and security (F) features by @charleypeng in #77
- chore: bump version to 0.2.0 by @charleypeng in #78
- feat: add audit trail / request logging middleware by @charleypeng in #79
- Feat/idempotency middleware by @charleypeng in #80
Full Changelog: https://github.com/SharkableIO/Sharkable/blob/main/CHANGELOG.md