EdgeAIG's picture
download
raw
4.58 kB
/**
* Declares middleware for schema-driven HTTP APIs.
*
* HTTP API middleware wraps endpoint execution on the server and, when the API
* requires it, can also wrap requests made by generated clients. It is used for
* cross-cutting behavior that belongs to the API contract, such as
* authentication, authorization, logging, tracing, rate limiting,
* request-scoped services, schema-error handling, and client request
* decoration. This module defines the middleware service keys and helpers used
* by `HttpApi` declarations.
*
* @since 4.0.0
*/
/** @effect-diagnostics floatingEffect:skip-file */
/** @effect-diagnostics classSelfMismatch:off */
import * as Context from "../../Context.js";
import * as Effect from "../../Effect.js";
import * as Layer from "../../Layer.js";
import { hasProperty } from "../../Predicate.js";
import { Scope } from "../../Scope.js";
import { HttpApiSchemaError } from "./HttpApiError.js";
const TypeId = "~effect/httpapi/HttpApiMiddleware";
const SecurityTypeId = "~effect/httpapi/HttpApiMiddleware/Security";
/**
* Returns `true` when an HTTP API middleware service is security middleware.
*
* @category guards
* @since 4.0.0
*/
export const isSecurity = u => hasProperty(u, SecurityTypeId);
/**
* Creates a `Context.Service` class for an HTTP API middleware implementation.
*
* **When to use**
*
* Use when you need an HTTP API middleware service whose configuration declares
* required services, provided services, typed error schemas, security schemes,
* client errors, or a matching client middleware requirement.
*
* @category schemas
* @since 4.0.0
*/
export const Service = () => (id, options) => {
const Err = globalThis.Error;
const limit = Err.stackTraceLimit;
Err.stackTraceLimit = 2;
const creationError = new Err();
Err.stackTraceLimit = limit;
class Service extends Context.Service()(id) {}
const self = Service;
Object.defineProperty(Service, "stack", {
get() {
return creationError.stack;
}
});
self[TypeId] = TypeId;
self.error = getError(options?.error);
self.requiredForClient = options?.requiredForClient ?? false;
if (options?.security !== undefined) {
if (Object.keys(options.security).length === 0) {
throw new Error("HttpApiMiddleware.Service: security object must not be empty");
}
self[SecurityTypeId] = SecurityTypeId;
self.security = options.security;
}
return self;
};
function getError(error) {
if (error === undefined) return new Set();
return new Set(Array.isArray(error) ? error : [error]);
}
/**
* Creates a middleware layer that transforms `HttpApiSchemaError` failures.
*
* **Details**
*
* The middleware catches schema errors produced while running an endpoint and uses
* the supplied `transform` function to convert them into the middleware's declared
* error schema.
*
* **Example** (Mapping schema errors to custom errors)
*
* ```ts
* import { Effect, Schema } from "effect"
* import { HttpApiMiddleware } from "effect/unstable/httpapi"
*
* export class CustomError extends Schema.TaggedErrorClass<CustomError>()("CustomError", {}) {}
*
* export class ErrorHandler extends HttpApiMiddleware.Service<ErrorHandler>()("api/ErrorHandler", {
* error: CustomError
* }) {}
*
* export const ErrorHandlerLayer = HttpApiMiddleware.layerSchemaErrorTransform(
* ErrorHandler,
* (schemaError) =>
* Effect.log("Got SchemaError", schemaError).pipe(
* Effect.andThen(Effect.fail(new CustomError()))
* )
* )
* ```
*
* @category SchemaError transform
* @since 4.0.0
*/
export const layerSchemaErrorTransform = (service, transform) => Layer.succeed(service, (httpEffect, options) => Effect.catch(httpEffect, e => HttpApiSchemaError.is(e) ? transform(e, options) : Effect.fail(e)));
/**
* Provides a client-side middleware implementation for a middleware that is required by generated clients.
*
* **Details**
*
* The layer captures the surrounding services and makes the middleware available
* through the `ForClient` service marker used by HTTP API clients.
*
* @category client
* @since 4.0.0
*/
export const layerClient = (tag, service) => Layer.effectContext(Effect.gen(function* () {
const services = (yield* Effect.context()).pipe(Context.omit(Scope));
const middleware = Effect.isEffect(service) ? yield* service : service;
return Context.makeUnsafe(new Map([[`${tag.key}/Client`, options => Effect.updateContext(middleware(options), requestContext => Context.merge(services, requestContext))]]));
}));
//# sourceMappingURL=HttpApiMiddleware.js.map

Xet Storage Details

Size:
4.58 kB
·
Xet hash:
3528bc8e72963900454839c1f778a558ce5d263c4fd4d86cee8eb447355ce934

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.