When designing options and callbacks for middleware/helpers, favor extensible, composable patterns over narrow, single-purpose additions.
Context (or relevant request data) into user-supplied callbacks whenever behavior may depend on the request, so users can implement custom logic without new options (e.g. onError: (remote, c: Context) => ..., generator: (c: Context) => string, ssgParams(async (c) => ...)).vary?: string | string[], or contentTypesAsBinary?: (contentType: string) => boolean instead of only string[].prefix?: 'host' | 'secure' over securePrefix?: boolean; hostPrefix?: boolean.usernameContextKey because onAuthSuccess: (c, username) => c.set(...) already solves it) — keep the public option surface minimal.{ ...defaultExtensionMap, 'application/foo': 'foo' }) instead of only allowing full replacement.verify(token, key, options: VerifyOptions) instead of verify(token, key, alg, issuer, audience, ...)).Applying these principles keeps public APIs predictable, avoids combinatorial option explosion, and gives consumers enough flexibility to handle edge cases without requiring new library changes.