| 1 | /** |
| 2 | * Typed request values for data loading with `Effect.request`. |
| 3 | * |
| 4 | * A request describes one logical piece of work without performing it. It |
| 5 | * records the success type, typed error, service requirements, and fields a |
| 6 | * resolver needs to complete the request. Requests are paired with |
| 7 | * `RequestResolver`, which performs backend-specific loading and completes each |
| 8 | * pending request entry with a success, failure, cause, exit, or effect. |
| 9 | * |
| 10 | * @since 2.0.0 |
| 11 | */ |
| 12 | import type * as Cause from "./Cause.ts" |
| 13 | import type * as Context from "./Context.ts" |
| 14 | import type * as Effect from "./Effect.ts" |
| 15 | import * as Equal from "./Equal.ts" |
| 16 | import type * as Exit from "./Exit.ts" |
| 17 | import { dual } from "./Function.ts" |
| 18 | import * as core from "./internal/core.ts" |
| 19 | import * as internalEffect from "./internal/effect.ts" |
| 20 | import * as InternalRecord from "./internal/record.ts" |
| 21 | import { hasProperty } from "./Predicate.ts" |
| 22 | import type * as Types from "./Types.ts" |
| 23 | |
| 24 | const TypeId = "~effect/Request" |
| 25 | |
| 26 | /** |
| 27 | * A `Request<A, E, R>` is a request from a data source for a value of type `A` |
| 28 | * that may fail with an `E` and have requirements of type `R`. |
| 29 | * |
| 30 | * **Example** (Defining typed requests) |
| 31 | * |
| 32 | * ```ts import.meta.vitest |
| 33 | * import type { Request } from "effect" |
| 34 | * |
| 35 | * // Define a request that fetches a user by ID |
| 36 | * interface GetUser extends Request.Request<string, Error> { |
| 37 | * readonly _tag: "GetUser" |
| 38 | * readonly id: number |
| 39 | * } |
| 40 | * |
| 41 | * // Define a request that fetches all users |
| 42 | * interface GetAllUsers extends Request.Request<ReadonlyArray<string>, Error> { |
| 43 | * readonly _tag: "GetAllUsers" |
| 44 | * } |
| 45 | * |
| 46 | * ``` |
| 47 | * |
| 48 | * @category models |
| 49 | * @since 2.0.0 |
| 50 | */ |
| 51 | export interface Request<out A, out E = never, out R = never> extends Variance<A, E, R> {} |
| 52 | |
| 53 | /** |
| 54 | * Alias for any `Request`, regardless of its success, error, or service |
| 55 | * requirements. |
| 56 | * |
| 57 | * **When to use** |
| 58 | * |
| 59 | * Use as a generic constraint for APIs that accept any request while preserving |
| 60 | * each concrete request's success, error, and service types. |
| 61 | * |
| 62 | * @see {@link Request} for the request interface |
| 63 | * @see {@link Success} for extracting a request's success type |
| 64 | * @see {@link Error} for extracting a request's error type |
| 65 | * @see {@link Services} for extracting a request's service requirements |
| 66 | * @see {@link Result} for the exit type produced by completing a request |
| 67 | * |
| 68 | * @category utility types |
| 69 | * @since 4.0.0 |
| 70 | */ |
| 71 | export type Any = Request<any, any, any> |
| 72 | |
| 73 | /** |
| 74 | * Variance marker carried by every `Request`. |
| 75 | * |
| 76 | * **Details** |
| 77 | * |
| 78 | * This marker preserves the success, error, and service requirement types for |
| 79 | * Effect's type-level machinery. Users normally get it by extending `Request`. |
| 80 | * |
| 81 | * @category models |
| 82 | * @since 2.0.0 |
| 83 | */ |
| 84 | export interface Variance<out A, out E, out R> { |
| 85 | readonly [TypeId]: { |
| 86 | readonly _A: Types.Covariant<A> |
| 87 | readonly _E: Types.Covariant<E> |
| 88 | readonly _R: Types.Covariant<R> |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * The constructor type returned by `Request.of` and `Request.tagged`. |
| 94 | * |
| 95 | * **Details** |
| 96 | * |
| 97 | * The constructor accepts the request's data fields, excluding request variance |
| 98 | * fields and any fields already supplied by the constructor such as `_tag`, and |
| 99 | * returns a value of the request type. |
| 100 | * |
| 101 | * **Example** (Using generated request constructors) |
| 102 | * |
| 103 | * ```ts import.meta.vitest |
| 104 | * import { Request } from "effect" |
| 105 | * |
| 106 | * interface GetUser extends Request.Request<string, Error> { |
| 107 | * readonly _tag: "GetUser" |
| 108 | * readonly id: number |
| 109 | * } |
| 110 | * |
| 111 | * // Constructor type is used internally by Request.of() and Request.tagged() |
| 112 | * const GetUser = Request.tagged<GetUser>("GetUser") |
| 113 | * const request = GetUser({ id: 123 }) |
| 114 | * |
| 115 | * request._tag // => "GetUser" |
| 116 | * request.id // => 123 |
| 117 | * ``` |
| 118 | * |
| 119 | * @category models |
| 120 | * @since 2.0.0 |
| 121 | */ |
| 122 | export interface Constructor<R extends Request<any, any, any>, T extends keyof R = never> { |
| 123 | (args: Types.VoidIfEmpty<Types.Simplify<Omit<R, T | keyof (Variance<any, any, any>)>>>): R |
| 124 | } |
| 125 | |
| 126 | /** |
| 127 | * A utility type to extract the error type from a `Request`. |
| 128 | * |
| 129 | * **Example** (Extracting a request error type) |
| 130 | * |
| 131 | * ```ts import.meta.vitest |
| 132 | * import type { Request } from "effect" |
| 133 | * |
| 134 | * interface GetUser extends Request.Request<string, Error> { |
| 135 | * readonly id: number |
| 136 | * } |
| 137 | * |
| 138 | * // Extract the error type from a Request using the utility |
| 139 | * type UserError = Request.Error<GetUser> // Error |
| 140 | * |
| 141 | * ``` |
| 142 | * |
| 143 | * @category utility types |
| 144 | * @since 2.0.0 |
| 145 | */ |
| 146 | export type Error<T extends Request<any, any, any>> = [T] extends [Request<infer _A, infer _E, infer _R>] ? _E : never |
| 147 | |
| 148 | /** |
| 149 | * A utility type to extract the value type from a `Request`. |
| 150 | * |
| 151 | * **Example** (Extracting a request success type) |
| 152 | * |
| 153 | * ```ts import.meta.vitest |
| 154 | * import type { Request } from "effect" |
| 155 | * |
| 156 | * interface GetUser extends Request.Request<string, Error> { |
| 157 | * readonly _tag: "GetUser" |
| 158 | * readonly id: number |
| 159 | * } |
| 160 | * |
| 161 | * // Extract the success type from a Request using the utility |
| 162 | * type UserSuccess = Request.Success<GetUser> // string |
| 163 | * |
| 164 | * ``` |
| 165 | * |
| 166 | * @category utility types |
| 167 | * @since 2.0.0 |
| 168 | */ |
| 169 | export type Success<T extends Request<any, any, any>> = [T] extends [Request<infer _A, infer _E, infer _R>] ? _A |
| 170 | : never |
| 171 | |
| 172 | /** |
| 173 | * A utility type to extract the requirements type from a `Request`. |
| 174 | * |
| 175 | * @category utility types |
| 176 | * @since 4.0.0 |
| 177 | */ |
| 178 | export type Services<T extends Request<any, any, any>> = [T] extends [Request<infer _A, infer _E, infer _R>] ? _R |
| 179 | : never |
| 180 | |
| 181 | /** |
| 182 | * A utility type to extract the result type from a `Request`. |
| 183 | * |
| 184 | * **Example** (Extracting a request result type) |
| 185 | * |
| 186 | * ```ts import.meta.vitest |
| 187 | * import type { Request } from "effect" |
| 188 | * |
| 189 | * interface GetUser extends Request.Request<string, Error> { |
| 190 | * readonly _tag: "GetUser" |
| 191 | * readonly id: number |
| 192 | * } |
| 193 | * |
| 194 | * // Extract the result type from a Request using the utility |
| 195 | * type UserResult = Request.Result<GetUser> // Exit.Exit<string, Error> |
| 196 | * |
| 197 | * ``` |
| 198 | * |
| 199 | * @category utility types |
| 200 | * @since 2.0.0 |
| 201 | */ |
| 202 | export type Result<T extends Request<any, any, any>> = T extends Request<infer A, infer E, infer _R> ? Exit.Exit<A, E> |
| 203 | : never |
| 204 | |
| 205 | const requestVariance = Equal.byReferenceUnsafe({ |
| 206 | /* c8 ignore next */ |
| 207 | _E: (_: never) => _, |
| 208 | /* c8 ignore next */ |
| 209 | _A: (_: never) => _, |
| 210 | /* c8 ignore next */ |
| 211 | _R: (_: never) => _ |
| 212 | }) |
| 213 | |
| 214 | /** |
| 215 | * Prototype used by Effect's request constructors. |
| 216 | * |
| 217 | * **Details** |
| 218 | * |
| 219 | * This low-level value provides the structural request marker for values |
| 220 | * created by `Request.of`, `Request.tagged`, `Request.Class`, and |
| 221 | * `Request.TaggedClass`. Most users should use those constructors instead of |
| 222 | * interacting with the prototype directly. |
| 223 | * |
| 224 | * @category prototypes |
| 225 | * @since 4.0.0 |
| 226 | */ |
| 227 | export const RequestPrototype: Request<any, any, any> = { |
| 228 | ...core.StructuralProto, |
| 229 | [TypeId]: requestVariance |
| 230 | } |
| 231 | |
| 232 | /** |
| 233 | * Checks whether a value is a `Request`. |
| 234 | * |
| 235 | * **Example** (Checking request values) |
| 236 | * |
| 237 | * ```ts import.meta.vitest |
| 238 | * import { Request } from "effect" |
| 239 | * |
| 240 | * declare const User: unique symbol |
| 241 | * declare const UserNotFound: unique symbol |
| 242 | * type User = typeof User |
| 243 | * type UserNotFound = typeof UserNotFound |
| 244 | * |
| 245 | * interface GetUser extends Request.Request<User, UserNotFound> { |
| 246 | * readonly _tag: "GetUser" |
| 247 | * readonly id: string |
| 248 | * } |
| 249 | * const GetUser = Request.tagged<GetUser>("GetUser") |
| 250 | * |
| 251 | * const request = GetUser({ id: "123" }) |
| 252 | * Request.isRequest(request) // => true |
| 253 | * Request.isRequest("not a request") // => false |
| 254 | * ``` |
| 255 | * |
| 256 | * @category guards |
| 257 | * @since 2.0.0 |
| 258 | */ |
| 259 | export const isRequest = (u: unknown): u is Request<unknown, unknown, unknown> => hasProperty(u, TypeId) |
| 260 | |
| 261 | /** |
| 262 | * Creates a constructor function for a specific Request type. |
| 263 | * |
| 264 | * **Example** (Creating untagged request constructors) |
| 265 | * |
| 266 | * ```ts import.meta.vitest |
| 267 | * import { Request } from "effect" |
| 268 | * |
| 269 | * declare const UserProfile: unique symbol |
| 270 | * declare const ProfileError: unique symbol |
| 271 | * type UserProfile = typeof UserProfile |
| 272 | * type ProfileError = typeof ProfileError |
| 273 | * |
| 274 | * interface GetUserProfile extends Request.Request<UserProfile, ProfileError> { |
| 275 | * readonly id: string |
| 276 | * readonly includeSettings: boolean |
| 277 | * } |
| 278 | * |
| 279 | * const GetUserProfile = Request.of<GetUserProfile>() |
| 280 | * |
| 281 | * const request = GetUserProfile({ |
| 282 | * id: "user-123", |
| 283 | * includeSettings: true |
| 284 | * }) |
| 285 | * |
| 286 | * request.id // => "user-123" |
| 287 | * request.includeSettings // => true |
| 288 | * ``` |
| 289 | * |
| 290 | * @category constructors |
| 291 | * @since 2.0.0 |
| 292 | */ |
| 293 | export const of = <R extends Request<any, any, any>>(): Constructor<R> => (args) => |
| 294 | Object.setPrototypeOf({ ...(args as R) }, RequestPrototype) |
| 295 | |
| 296 | /** |
| 297 | * Creates a constructor function for a tagged Request type. The tag is automatically |
| 298 | * added to the request, making it useful for discriminated unions. |
| 299 | * |
| 300 | * **Example** (Creating tagged request constructors) |
| 301 | * |
| 302 | * ```ts import.meta.vitest |
| 303 | * import { Request } from "effect" |
| 304 | * |
| 305 | * declare const User: unique symbol |
| 306 | * declare const UserNotFound: unique symbol |
| 307 | * declare const Post: unique symbol |
| 308 | * declare const PostNotFound: unique symbol |
| 309 | * type User = typeof User |
| 310 | * type UserNotFound = typeof UserNotFound |
| 311 | * type Post = typeof Post |
| 312 | * type PostNotFound = typeof PostNotFound |
| 313 | * |
| 314 | * interface GetUser extends Request.Request<User, UserNotFound> { |
| 315 | * readonly _tag: "GetUser" |
| 316 | * readonly id: string |
| 317 | * } |
| 318 | * |
| 319 | * interface GetPost extends Request.Request<Post, PostNotFound> { |
| 320 | * readonly _tag: "GetPost" |
| 321 | * readonly id: string |
| 322 | * } |
| 323 | * |
| 324 | * const GetUser = Request.tagged<GetUser>("GetUser") |
| 325 | * const GetPost = Request.tagged<GetPost>("GetPost") |
| 326 | * |
| 327 | * const userRequest = GetUser({ id: "user-123" }) |
| 328 | * const postRequest = GetPost({ id: "post-456" }) |
| 329 | * |
| 330 | * // _tag is automatically set |
| 331 | * Array.of(userRequest._tag, postRequest._tag) // => ["GetUser", "GetPost"] |
| 332 | * ``` |
| 333 | * |
| 334 | * @category constructors |
| 335 | * @since 2.0.0 |
| 336 | */ |
| 337 | export const tagged = <R extends Request<any, any, any> & { _tag: string }>( |
| 338 | tag: R["_tag"] |
| 339 | ): Constructor<R, "_tag"> => |
| 340 | (args) => { |
| 341 | return Object.setPrototypeOf({ ...(args as R), _tag: tag }, RequestPrototype) |
| 342 | } |
| 343 | |
| 344 | /** |
| 345 | * Defines request types with TypeScript classes. |
| 346 | * |
| 347 | * **Details** |
| 348 | * |
| 349 | * Subclasses pass their data fields to `super`, and instances are marked as |
| 350 | * `Request` values while retaining the provided readonly fields. |
| 351 | * |
| 352 | * **Example** (Defining request classes) |
| 353 | * |
| 354 | * ```ts import.meta.vitest |
| 355 | * import { Request } from "effect" |
| 356 | * |
| 357 | * class GetUser extends Request.Class<{ id: number }, string, Error> { |
| 358 | * constructor(readonly id: number) { |
| 359 | * super({ id }) |
| 360 | * } |
| 361 | * } |
| 362 | * |
| 363 | * const getUserRequest = new GetUser(123) |
| 364 | * getUserRequest.id // => 123 |
| 365 | * ``` |
| 366 | * |
| 367 | * @category constructors |
| 368 | * @since 2.0.0 |
| 369 | */ |
| 370 | export const Class: new<A extends Record<string, any>, Success, Error = never, Context = never>( |
| 371 | args: Types.Equals<Omit<A, keyof Request<unknown, unknown>>, {}> extends true ? void |
| 372 | : { readonly [P in keyof A as P extends keyof Request<any, any, any> ? never : P]: A[P] } |
| 373 | ) => Request<Success, Error, Context> & Readonly<A> = (function() { |
| 374 | function Class(this: object, args: object | undefined) { |
| 375 | if (args) { |
| 376 | InternalRecord.assignProperties(this, args) |
| 377 | } |
| 378 | } |
| 379 | Class.prototype = RequestPrototype |
| 380 | return Class as any |
| 381 | })() |
| 382 | |
| 383 | /** |
| 384 | * Creates a class constructor for requests with a fixed `_tag` field. |
| 385 | * |
| 386 | * **Details** |
| 387 | * |
| 388 | * Use this when defining class-based request types that should participate in |
| 389 | * tagged unions or tag-based request resolvers. |
| 390 | * |
| 391 | * **Example** (Defining tagged request classes) |
| 392 | * |
| 393 | * ```ts import.meta.vitest |
| 394 | * import { Request } from "effect" |
| 395 | * |
| 396 | * class GetUserById |
| 397 | * extends Request.TaggedClass("GetUserById")<{ id: number }, string, Error> |
| 398 | * {} |
| 399 | * |
| 400 | * const request = new GetUserById({ id: 123 }) |
| 401 | * |
| 402 | * request._tag // => "GetUserById" |
| 403 | * request.id // => 123 |
| 404 | * ``` |
| 405 | * |
| 406 | * @category constructors |
| 407 | * @since 2.0.0 |
| 408 | */ |
| 409 | export const TaggedClass = <Tag extends string>( |
| 410 | tag: Tag |
| 411 | ): new<A extends Record<string, any>, Success, Error = never, Services = never>( |
| 412 | args: Types.Equals<Omit<A, keyof Request<unknown, unknown>>, {}> extends true ? void |
| 413 | : { readonly [P in keyof A as P extends "_tag" | keyof Request<any, any, any> ? never : P]: A[P] } |
| 414 | ) => Request<Success, Error, Services> & Readonly<A> & { readonly _tag: Tag } => { |
| 415 | return class TaggedClass extends Class<any, any, any> { |
| 416 | readonly _tag = tag |
| 417 | } as any |
| 418 | } |
| 419 | |
| 420 | /** |
| 421 | * Completes a request entry with the provided result. |
| 422 | * |
| 423 | * **When to use** |
| 424 | * |
| 425 | * Use when you need to finish a `Request.Entry` with a prebuilt final `Exit` |
| 426 | * result. |
| 427 | * |
| 428 | * @see {@link completeEffect} for completing an entry from an effect that may succeed or fail |
| 429 | * @see {@link succeed} for completing an entry with a successful value |
| 430 | * @see {@link fail} for completing an entry with a typed failure |
| 431 | * @see {@link failCause} for completing an entry with a failure `Cause` |
| 432 | * |
| 433 | * @category completion |
| 434 | * @since 2.0.0 |
| 435 | */ |
| 436 | export const complete: { |
| 437 | <A extends Any>(result: Result<A>): (self: Entry<A>) => Effect.Effect<void> |
| 438 | <A extends Any>(self: Entry<A>, result: Result<A>): Effect.Effect<void> |
| 439 | } = dual( |
| 440 | 2, |
| 441 | <A extends Any>(self: Entry<A>, result: Result<A>): Effect.Effect<void> => |
| 442 | internalEffect.sync(() => self.completeUnsafe(result)) |
| 443 | ) |
| 444 | |
| 445 | /** |
| 446 | * Completes a request entry with the result of an effect. |
| 447 | * |
| 448 | * **When to use** |
| 449 | * |
| 450 | * Use to finish a `Request.Entry` by running an effect whose success or typed |
| 451 | * failure should become the request result. |
| 452 | * |
| 453 | * **Details** |
| 454 | * |
| 455 | * If the effect succeeds, the entry is completed successfully with its value. |
| 456 | * If the effect fails, the entry is completed with that failure. |
| 457 | * |
| 458 | * **Gotchas** |
| 459 | * |
| 460 | * The returned effect itself does not fail with the request error. |
| 461 | * |
| 462 | * @see {@link complete} for completing an entry with a prebuilt `Exit` |
| 463 | * @see {@link succeed} for completing an entry with a successful value |
| 464 | * @see {@link fail} for completing an entry with a typed failure |
| 465 | * @see {@link failCause} for completing an entry with a failure `Cause` |
| 466 | * |
| 467 | * @category completion |
| 468 | * @since 2.0.0 |
| 469 | */ |
| 470 | export const completeEffect: { |
| 471 | <A extends Any, R>(effect: Effect.Effect<Success<A>, Error<A>, R>): (self: Entry<A>) => Effect.Effect<void, never, R> |
| 472 | <A extends Any, R>(self: Entry<A>, effect: Effect.Effect<Success<A>, Error<A>, R>): Effect.Effect<void, never, R> |
| 473 | } = dual( |
| 474 | 2, |
| 475 | <A extends Any, R>(self: Entry<A>, effect: Effect.Effect<Success<A>, Error<A>, R>): Effect.Effect<void, never, R> => |
| 476 | internalEffect.matchEffect(effect, { |
| 477 | onFailure: (error) => complete(self, core.exitFail(error) as any), |
| 478 | onSuccess: (value) => complete(self, core.exitSucceed(value) as any) |
| 479 | }) |
| 480 | ) |
| 481 | |
| 482 | /** |
| 483 | * Completes a request entry with a typed failure. |
| 484 | * |
| 485 | * **When to use** |
| 486 | * |
| 487 | * Use to report a request-specific typed error while implementing a |
| 488 | * `RequestResolver`. |
| 489 | * |
| 490 | * @see {@link failCause} for completing an entry with a full `Cause` |
| 491 | * @see {@link complete} for completing an entry with an existing `Exit` |
| 492 | * @see {@link completeEffect} for completing an entry from an effect result |
| 493 | * @see {@link succeed} for completing an entry successfully |
| 494 | * |
| 495 | * @category completion |
| 496 | * @since 2.0.0 |
| 497 | */ |
| 498 | export const fail: { |
| 499 | <A extends Any>(error: Error<A>): (self: Entry<A>) => Effect.Effect<void> |
| 500 | <A extends Any>(self: Entry<A>, error: Error<A>): Effect.Effect<void> |
| 501 | } = dual( |
| 502 | 2, |
| 503 | <A extends Any>(self: Entry<A>, error: Error<A>): Effect.Effect<void> => complete(self, core.exitFail(error) as any) |
| 504 | ) |
| 505 | |
| 506 | /** |
| 507 | * Completes a request entry with a failure `Cause`. |
| 508 | * |
| 509 | * **When to use** |
| 510 | * |
| 511 | * Use when you need a `RequestResolver` to complete an entry with structured |
| 512 | * cause information rather than only the request's typed error value. |
| 513 | * |
| 514 | * @see {@link fail} for completing an entry with a typed error value |
| 515 | * @see {@link complete} for completing an entry with an existing `Exit` |
| 516 | * @see {@link completeEffect} for completing an entry from an effect result |
| 517 | * @see {@link succeed} for completing an entry successfully |
| 518 | * |
| 519 | * @category completion |
| 520 | * @since 2.0.0 |
| 521 | */ |
| 522 | export const failCause: { |
| 523 | <A extends Any>(cause: Cause.Cause<Error<A>>): (self: Entry<A>) => Effect.Effect<void> |
| 524 | <A extends Any>(self: Entry<A>, cause: Cause.Cause<Error<A>>): Effect.Effect<void> |
| 525 | } = dual( |
| 526 | 2, |
| 527 | <A extends Any>(self: Entry<A>, cause: Cause.Cause<Error<A>>): Effect.Effect<void> => |
| 528 | complete(self, core.exitFailCause(cause) as any) |
| 529 | ) |
| 530 | |
| 531 | /** |
| 532 | * Completes a request entry successfully with the supplied value. |
| 533 | * |
| 534 | * **When to use** |
| 535 | * |
| 536 | * Use when you need to finish a `Request.Entry` with a successful request |
| 537 | * value. |
| 538 | * |
| 539 | * @see {@link complete} for completing an entry with a prebuilt `Exit` |
| 540 | * @see {@link completeEffect} for completing an entry from an effect result |
| 541 | * @see {@link fail} for completing an entry with a typed failure |
| 542 | * @see {@link failCause} for completing an entry with a failure `Cause` |
| 543 | * |
| 544 | * @category completion |
| 545 | * @since 2.0.0 |
| 546 | */ |
| 547 | export const succeed: { |
| 548 | <A extends Any>(value: Success<A>): (self: Entry<A>) => Effect.Effect<void> |
| 549 | <A extends Any>(self: Entry<A>, value: Success<A>): Effect.Effect<void> |
| 550 | } = dual( |
| 551 | 2, |
| 552 | <A extends Any>(self: Entry<A>, value: Success<A>): Effect.Effect<void> => |
| 553 | complete(self, core.exitSucceed(value) as any) |
| 554 | ) |
| 555 | |
| 556 | /** |
| 557 | * A pending request handed to a `RequestResolver`. |
| 558 | * |
| 559 | * **Details** |
| 560 | * |
| 561 | * An entry contains the original request, the fiber context needed to run it, |
| 562 | * an `uninterruptible` flag used by batching and caching internals, and the |
| 563 | * `completeUnsafe` callback used by resolvers to supply the final `Exit`. |
| 564 | * |
| 565 | * @category models |
| 566 | * @since 2.0.0 |
| 567 | */ |
| 568 | export interface Entry<out R> { |
| 569 | readonly request: R |
| 570 | readonly context: Context.Context< |
| 571 | [R] extends [Request<infer _A, infer _E, infer _R>] ? _R : never |
| 572 | > |
| 573 | uninterruptible: boolean |
| 574 | completeUnsafe( |
| 575 | exit: Exit.Exit< |
| 576 | [R] extends [Request<infer _A, infer _E, infer _R>] ? _A : never, |
| 577 | [R] extends [Request<infer _A, infer _E, infer _R>] ? _E : never |
| 578 | > |
| 579 | ): void |
| 580 | } |
| 581 | |
| 582 | /** |
| 583 | * Creates a `Request.Entry` from its component fields. |
| 584 | * |
| 585 | * **Details** |
| 586 | * |
| 587 | * This is a low-level helper for request runtime and resolver infrastructure; |
| 588 | * most application code receives entries from a `RequestResolver` instead of |
| 589 | * constructing them directly. |
| 590 | * |
| 591 | * @category constructors |
| 592 | * @since 2.0.0 |
| 593 | */ |
| 594 | export const makeEntry = <R>(options: { |
| 595 | readonly request: R |
| 596 | readonly context: Context.Context< |
| 597 | [R] extends [Request<infer _A, infer _E, infer _R>] ? _R : never |
| 598 | > |
| 599 | readonly uninterruptible: boolean |
| 600 | readonly completeUnsafe: ( |
| 601 | exit: Exit.Exit< |
| 602 | [R] extends [Request<infer _A, infer _E, infer _R>] ? _A : never, |
| 603 | [R] extends [Request<infer _A, infer _E, infer _R>] ? _E : never |
| 604 | > |
| 605 | ) => void |
| 606 | }): Entry<R> => options |