@afora/core 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -25
- package/dist/adapters.d.ts +25 -0
- package/dist/adapters.js +56 -0
- package/dist/core/application/exceptions.d.ts +17 -0
- package/dist/core/application/migrate.d.ts +19 -0
- package/dist/core/application/schema.d.ts +30 -0
- package/dist/core/application/start.d.ts +7 -0
- package/dist/core/application/types/application.interface.d.ts +73 -2
- package/dist/core/auth/jwt.d.ts +30 -0
- package/dist/core/auth/types/jwt.interface.d.ts +66 -0
- package/dist/core/blueprint/exceptions.d.ts +5 -0
- package/dist/core/blueprint/optional.d.ts +3 -1
- package/dist/core/blueprint/types/blueprint.interface.d.ts +79 -5
- package/dist/core/blueprint/variant.d.ts +32 -0
- package/dist/core/command/types/command.interface.d.ts +7 -0
- package/dist/core/entity/abstract-entity.d.ts +33 -1
- package/dist/core/entity/entity.d.ts +1 -1
- package/dist/core/entity/event.d.ts +13 -2
- package/dist/core/entity/exceptions.d.ts +17 -0
- package/dist/core/entity/trust.d.ts +24 -0
- package/dist/core/entity/types/entity.interface.d.ts +96 -2
- package/dist/core/entity/version.d.ts +13 -0
- package/dist/core/event-policy/event-policy.d.ts +25 -0
- package/dist/core/event-policy/exceptions.d.ts +11 -0
- package/dist/core/event-policy/publish.d.ts +17 -0
- package/dist/core/event-policy/publishers.d.ts +18 -0
- package/dist/core/event-policy/types/event-policy.interface.d.ts +72 -0
- package/dist/core/output/access.d.ts +16 -0
- package/dist/core/output/coerce.d.ts +9 -0
- package/dist/core/output/exceptions.d.ts +16 -0
- package/dist/core/output/http.d.ts +36 -0
- package/dist/core/output/openapi-sink.d.ts +160 -39
- package/dist/core/output/stage.d.ts +7 -2
- package/dist/core/output/status.d.ts +2 -2
- package/dist/core/output/types/http.interface.d.ts +130 -0
- package/dist/core/output/types/output.interface.d.ts +25 -5
- package/dist/core/parse/issue.d.ts +28 -3
- package/dist/core/parse/parse.d.ts +19 -0
- package/dist/core/parse/strip.d.ts +13 -0
- package/dist/core/property/abstract-property.d.ts +9 -0
- package/dist/core/property/define-property.d.ts +34 -6
- package/dist/core/property/types/property-options.interface.d.ts +10 -0
- package/dist/core/property/types/property-type.interface.d.ts +4 -0
- package/dist/core/record/abstract-record.d.ts +7 -0
- package/dist/core/record/types/record.interface.d.ts +12 -1
- package/dist/core/repository/exceptions.d.ts +43 -0
- package/dist/core/repository/in-memory.d.ts +16 -3
- package/dist/core/repository/migrate.d.ts +20 -0
- package/dist/core/repository/plan.d.ts +20 -0
- package/dist/core/repository/provider.d.ts +1 -1
- package/dist/core/repository/query.d.ts +9 -2
- package/dist/core/repository/repository.d.ts +40 -8
- package/dist/core/repository/state.d.ts +32 -2
- package/dist/core/repository/types/query.interface.d.ts +106 -5
- package/dist/core/repository/types/repository.interface.d.ts +139 -7
- package/dist/core/repository/types/schema.interface.d.ts +126 -0
- package/dist/core/repository/upcast.d.ts +64 -0
- package/dist/core/schema/schema.d.ts +28 -0
- package/dist/core/symbols/kind.d.ts +1 -1
- package/dist/core/use-case/access.d.ts +12 -0
- package/dist/core/use-case/decorators.d.ts +40 -0
- package/dist/core/use-case/route.d.ts +18 -0
- package/dist/core/use-case/steps/types/check.interface.d.ts +214 -0
- package/dist/core/use-case/types/access.interface.d.ts +39 -0
- package/dist/core/use-case/types/route.interface.d.ts +66 -0
- package/dist/core/use-case/use-case.d.ts +52 -2
- package/dist/experimental.d.ts +13 -1
- package/dist/experimental.js +64 -26
- package/dist/index-3aae5jfq.js +2997 -0
- package/dist/index-hg1z2s2v.js +1055 -0
- package/dist/index-ny3as79r.js +4567 -0
- package/dist/index-xegv6a1p.js +4291 -0
- package/dist/index-y280ew0k.js +396 -0
- package/dist/index.d.ts +55 -48
- package/dist/index.js +141 -169
- package/dist/std/blueprint-plugin.d.ts +6 -2
- package/dist/std/blueprint.d.ts +3 -0
- package/dist/std/entity.d.ts +2 -1
- package/dist/std/event-policies.d.ts +2 -0
- package/dist/std/properties/exceptions.d.ts +11 -0
- package/dist/std/properties/json.d.ts +54 -0
- package/dist/std/properties/password.d.ts +0 -2
- package/dist/std/properties/time.d.ts +4 -0
- package/dist/std/record-plugins.d.ts +2 -2
- package/dist/std/resource.d.ts +31 -0
- package/dist/std/runtime.d.ts +6 -0
- package/dist/std/use-cases/auth.d.ts +5 -1
- package/dist/std/use-cases/crud.d.ts +6 -4
- package/dist/std/use-cases/index.d.ts +1 -1
- package/dist/std/use-cases/shared.d.ts +34 -6
- package/dist/std/use-cases/types.d.ts +197 -22
- package/dist/testing/http-provider-contract.d.ts +32 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +839 -3
- package/dist/testing/memory-publisher.d.ts +16 -0
- package/dist/testing/provider-contract.d.ts +31 -1
- package/package.json +17 -3
- package/dist/index-q6hggpzw.js +0 -6667
- package/dist/index-r78dsvtc.js +0 -1721
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { EntityUpgrades } from "../entity/types/entity.interface.js";
|
|
2
|
+
import type { RepositoryState } from "./state.js";
|
|
3
|
+
import type { RepositoryData } from "./types/repository.interface.js";
|
|
4
|
+
/** What happens to the value of one key of a collection. */
|
|
5
|
+
type FieldStep = {
|
|
6
|
+
readonly kind: "property";
|
|
7
|
+
readonly fill?: unknown;
|
|
8
|
+
readonly renamedFrom?: string;
|
|
9
|
+
} | {
|
|
10
|
+
readonly kind: "collection";
|
|
11
|
+
readonly fields: CollectionSteps;
|
|
12
|
+
} | {
|
|
13
|
+
readonly kind: "list";
|
|
14
|
+
readonly item: FieldStep;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: "opaque";
|
|
17
|
+
};
|
|
18
|
+
/** The steps of the keys of a blueprint, and whether any of them does something. */
|
|
19
|
+
interface CollectionSteps {
|
|
20
|
+
readonly fields: ReadonlyMap<string, FieldStep>;
|
|
21
|
+
}
|
|
22
|
+
/** How the rows of an entity are brought up to its current shape. */
|
|
23
|
+
export interface UpcastPlan {
|
|
24
|
+
readonly versioned: boolean;
|
|
25
|
+
readonly version: number;
|
|
26
|
+
/** Whether the entity lists `previousNames`: its moved rows may hold old keys. */
|
|
27
|
+
readonly renamed: boolean;
|
|
28
|
+
readonly upgrade: EntityUpgrades;
|
|
29
|
+
readonly fields: CollectionSteps;
|
|
30
|
+
}
|
|
31
|
+
/** What `upcast` did to a row, for `app.migrate`. */
|
|
32
|
+
export interface UpcastReport {
|
|
33
|
+
/** The version the row was stored at (1 without the version key). */
|
|
34
|
+
from: number;
|
|
35
|
+
/** Paths of the keys moved from their `renamedFrom`. */
|
|
36
|
+
readonly renamed: string[];
|
|
37
|
+
/** Paths of the keys given their `fill`. */
|
|
38
|
+
readonly filled: string[];
|
|
39
|
+
/** Paths of the keys the blueprint no longer declares. */
|
|
40
|
+
readonly removed: string[];
|
|
41
|
+
}
|
|
42
|
+
/** The plan of `entity`, even when it changes nothing but the keys it no longer declares. */
|
|
43
|
+
export declare function fullUpcastPlanOf(entity: object): UpcastPlan;
|
|
44
|
+
/**
|
|
45
|
+
* `data`, a row of an entity of `plan` as a provider gave it, in the current
|
|
46
|
+
* shape: without the version key, through each `upgrade` step from the
|
|
47
|
+
* version after the stored one up to `schemaVersion`, then the automatic
|
|
48
|
+
* steps of the current blueprint (`renamedFrom`, `fill`, and, with `drop`,
|
|
49
|
+
* leaving out keys it no longer declares). The steps run first because each
|
|
50
|
+
* is written against the shape of the version before it, which the
|
|
51
|
+
* automatic steps would already have changed. Throws
|
|
52
|
+
* `InvalidStoredSchemaVersion` for a version that is not a positive integer
|
|
53
|
+
* or is above `schemaVersion`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function upcast(source: string, plan: UpcastPlan, data: RepositoryData, drop?: boolean, report?: UpcastReport): RepositoryData;
|
|
56
|
+
/**
|
|
57
|
+
* `rows` of `state`'s entity in its current shape (see `upcast`); `rows`
|
|
58
|
+
* itself when the entity needs nothing. Throws `InvalidRepositoryData`
|
|
59
|
+
* caused by `InvalidStoredSchemaVersion` for a row it cannot bring up.
|
|
60
|
+
*/
|
|
61
|
+
export declare function upcastRows(state: RepositoryState, rows: readonly RepositoryData[]): readonly RepositoryData[];
|
|
62
|
+
/** `data` with the version key of `state`'s entity, when it declares `schemaVersion`. */
|
|
63
|
+
export declare function withSchemaVersion(entity: object, data: RepositoryData): RepositoryData;
|
|
64
|
+
export {};
|
|
@@ -5,6 +5,34 @@ export declare function describeError(error: {
|
|
|
5
5
|
instancePath: string;
|
|
6
6
|
message: string;
|
|
7
7
|
}): string;
|
|
8
|
+
/** One TypeBox error, as `Errors` gives it. */
|
|
9
|
+
export interface SchemaError {
|
|
10
|
+
readonly keyword: string;
|
|
11
|
+
readonly schemaPath: string;
|
|
12
|
+
readonly instancePath: string;
|
|
13
|
+
readonly params: object;
|
|
14
|
+
readonly message: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The errors of `value`, which `schema` rejects. For every schema but one
|
|
18
|
+
* they are what `schema.type.Errors(value)` gives: same errors, same order,
|
|
19
|
+
* same messages. The one is a discriminated union given an object, told by
|
|
20
|
+
* the variant its key names (see `errorsOfVariant`). TypeBox is only asked
|
|
21
|
+
* about a schema with a keyword that has no explanation here (`explainerOf`).
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export declare function errorsOfSchema(schema: ISchema<TSchema>, value: unknown): readonly SchemaError[];
|
|
25
|
+
/** The two checks of a schema, as functions. */
|
|
26
|
+
export interface SchemaChecks {
|
|
27
|
+
match(value: unknown): boolean;
|
|
28
|
+
matchShape(value: unknown): boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* `schema.match` and `schema.matchShape`, compiled now, for who checks many
|
|
32
|
+
* values with one schema; those of a schema not made by `schemaOf` call it.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function checksOfSchema(schema: ISchema<TSchema>): SchemaChecks;
|
|
8
36
|
/** A schema class declared with `schemaOf`. */
|
|
9
37
|
export interface SchemaClass<SchemaType extends TSchema> {
|
|
10
38
|
new (type?: SchemaType): ISchema<SchemaType>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** Brands blueprints, lists and records, so none is told apart by its shape. */
|
|
1
|
+
/** Brands blueprints, lists, variants and records, so none is told apart by its shape. */
|
|
2
2
|
export declare const Kind: unique symbol;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AnyBlueprint } from "../blueprint/types/blueprint.interface.js";
|
|
2
|
+
import type { AccessDeclaration } from "./types/access.interface.js";
|
|
3
|
+
/** Whether `access` lets anyone in. */
|
|
4
|
+
export declare function isPublicAccess(access: AccessDeclaration): access is {
|
|
5
|
+
readonly public: true;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* The frozen declaration of `access` for a use case whose input is
|
|
9
|
+
* `blueprint`, or the reason it is not valid. The keys of `context` are
|
|
10
|
+
* checked where the context is known: when the use case becomes an operation.
|
|
11
|
+
*/
|
|
12
|
+
export declare function accessDeclarationOf(access: unknown, blueprint: AnyBlueprint): AccessDeclaration | string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AccessDeclaration } from "./types/access.interface.js";
|
|
2
|
+
import type { RouteSettings } from "./types/route.interface.js";
|
|
3
|
+
/** What a decorator of this module is given besides the class: nothing it reads. */
|
|
4
|
+
type ClassContext = {
|
|
5
|
+
readonly kind: string;
|
|
6
|
+
};
|
|
7
|
+
/** A class decorator for use cases, in the standard form and in the legacy one of TypeScript. */
|
|
8
|
+
export type UseCaseDecorator = <UseCase extends abstract new (...args: any[]) => unknown>(value: UseCase, context?: ClassContext) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Says where a use case is served over HTTP, on the class itself:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* @Route("GET", "/posts/{slug}", { query: ["page"], cookie: { session: "sid" } })
|
|
14
|
+
* class ListPosts extends useCaseOf({ name: "ListPosts", blueprint, response }) {}
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* The same as the `route` setting of `useCaseOf` (see `RouteDeclaration`), so
|
|
18
|
+
* `describe()`, the sinks and `afora.json` see one declaration. It names no
|
|
19
|
+
* server: the sink of an output does. Throws `InvalidUseCaseDeclaration` on
|
|
20
|
+
* a class that is not a use case, on one that already has another route
|
|
21
|
+
* (the same one again is accepted), and for a route that does not fit the
|
|
22
|
+
* input of the use case.
|
|
23
|
+
*/
|
|
24
|
+
export declare function Route(method: RouteSettings["method"], path?: string, options?: Omit<RouteSettings, "method" | "path">): UseCaseDecorator;
|
|
25
|
+
export declare function Route(method: RouteSettings["method"], options?: Omit<RouteSettings, "method" | "path">): UseCaseDecorator;
|
|
26
|
+
/**
|
|
27
|
+
* Says who may call a use case, on the class itself:
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* @Access({ scopes: ["posts:write"], context: { userId: "subject" } })
|
|
31
|
+
* class PublishPost extends useCaseOf({ name: "PublishPost", blueprint, response, context }) {}
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* The same as the `access` setting of `useCaseOf` (see `AccessDeclaration`).
|
|
35
|
+
* Throws `InvalidUseCaseDeclaration` on a class that is not a use case, on
|
|
36
|
+
* one that already declares another access (the same one again is accepted),
|
|
37
|
+
* and for a declaration that does not fit the input of the use case.
|
|
38
|
+
*/
|
|
39
|
+
export declare function Access(access: AccessDeclaration): UseCaseDecorator;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AnyBlueprint } from "../blueprint/types/blueprint.interface.js";
|
|
2
|
+
import type { OpenAPISchema } from "../openapi/types/openapi.interface.js";
|
|
3
|
+
import type { RouteDeclaration } from "./types/route.interface.js";
|
|
4
|
+
/** A header name (an HTTP token), which a cookie name is too. */
|
|
5
|
+
export declare const HEADER_NAME: RegExp;
|
|
6
|
+
/** A path such as `/entries/{slug}`: `{name}` only as a whole segment, no `:`, `*`, query or spaces. */
|
|
7
|
+
export declare function isRoutePath(value: unknown, parameters?: boolean): value is string;
|
|
8
|
+
/** The names of the `{name}` segments of `path`, in order. */
|
|
9
|
+
export declare function parametersOfPath(path: string): string[];
|
|
10
|
+
/** Whether a JSON Schema describes a value that is neither an object nor a list. */
|
|
11
|
+
export declare function isScalarSchema(schema: OpenAPISchema): boolean;
|
|
12
|
+
/** Whether `name` is a key of `blueprint` that is a scalar property (no object, no list). */
|
|
13
|
+
export declare function isScalarKey(blueprint: AnyBlueprint, name: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The frozen, normalized declaration of `route` for a use case whose input is
|
|
16
|
+
* `blueprint` (the method in lower case), or the reason it is not valid.
|
|
17
|
+
*/
|
|
18
|
+
export declare function routeDeclarationOf(route: unknown, blueprint: AnyBlueprint, response: AnyBlueprint): RouteDeclaration | string;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compile-time checking of `useCaseOf({ steps })`: the steps are inferred
|
|
3
|
+
* as a tuple and folded in order. Each step sees the values in scope (the
|
|
4
|
+
* input, the context, the environments and the names bound by the earlier
|
|
5
|
+
* steps with `as`); its references must name a path of one of them, and its
|
|
6
|
+
* `args`, `values`, `value` or `input` must fit what the called function,
|
|
7
|
+
* record, repository or use case takes. A reference that does not fit is
|
|
8
|
+
* replaced by the references that would, which is the error TypeScript shows
|
|
9
|
+
* and what the editor offers inside a `"$…"` string.
|
|
10
|
+
*
|
|
11
|
+
* The list of the paths of the scope is computed only for a reference that
|
|
12
|
+
* does not fit, so that right steps cost little to check. The conditionals on
|
|
13
|
+
* the steps are not distributive (`[Step] extends [...]`): TypeScript then
|
|
14
|
+
* never evaluates them with the constraint of the steps while it infers them.
|
|
15
|
+
*/
|
|
16
|
+
import type { BlueprintValue, IBlueprint, IBlueprintCollection } from "../../../blueprint/types/blueprint.interface.js";
|
|
17
|
+
import type { AnyEnvironment, EnvironmentValue } from "../../../environment/environment.js";
|
|
18
|
+
import type { Meta } from "../../../symbols/meta.js";
|
|
19
|
+
import type { AnyUseCaseClass, UseCaseInput, UseCaseResponse } from "../../use-case.js";
|
|
20
|
+
/** The values the first step can reference: the input, the context (if declared) and the environments. */
|
|
21
|
+
export type StepsInitialScope<Input extends IBlueprintCollection, Context extends IBlueprintCollection | undefined, Dependencies> = {
|
|
22
|
+
readonly input: BlueprintValue<Input>;
|
|
23
|
+
readonly env: {
|
|
24
|
+
readonly [Key in keyof Dependencies as Dependencies[Key] extends AnyEnvironment ? Key : never]: Dependencies[Key] extends AnyEnvironment ? EnvironmentValue<Dependencies[Key]> : never;
|
|
25
|
+
};
|
|
26
|
+
} & (Context extends IBlueprintCollection ? {
|
|
27
|
+
readonly context: BlueprintValue<Context>;
|
|
28
|
+
} : unknown);
|
|
29
|
+
type Split<Path extends string> = Path extends `${infer Head}.${infer Tail}` ? [Head, ...Split<Tail>] : [Path];
|
|
30
|
+
/** `Value[Key]` for a value that is not `null` or `undefined`: by index (or `length`) in a list; `never` when absent. */
|
|
31
|
+
type GetDefined<Value, Key extends string> = Value extends readonly unknown[] ? Key extends `${number}` ? Key extends keyof Value ? Value[Key] : Value[number] : Key extends "length" ? number : never : Key extends keyof Value ? Value[Key] : never;
|
|
32
|
+
/**
|
|
33
|
+
* `Value[Key]` as `followPath` reads it: `undefined` through a value that
|
|
34
|
+
* may be `undefined` or `null`, and `never` when no value of the type has
|
|
35
|
+
* the key; `unknown` stays `unknown`.
|
|
36
|
+
*/
|
|
37
|
+
type Get<Value, Key extends string> = unknown extends Value ? unknown : [GetDefined<NonNullable<Value>, Key>] extends [infer Found] ? [Found] extends [never] ? never : Found | (Value extends null | undefined ? undefined : never) : never;
|
|
38
|
+
type Walk<Value, Path extends readonly string[]> = Path extends readonly [
|
|
39
|
+
infer Key extends string,
|
|
40
|
+
...infer Rest extends string[]
|
|
41
|
+
] ? Walk<Get<Value, Key>, Rest> : Value;
|
|
42
|
+
/** The type of the value the reference `$root.a.b` stands for in `Scope`; `never` when it names nothing. */
|
|
43
|
+
export type StepReferenceType<Scope, Reference> = [Reference] extends [
|
|
44
|
+
`$${infer Path}`
|
|
45
|
+
] ? Split<Path> extends [
|
|
46
|
+
infer Root extends string,
|
|
47
|
+
...infer Rest extends string[]
|
|
48
|
+
] ? Root extends "env" ? Rest extends [string, ...string[]] ? Walk<Get<Scope, Root>, Rest> : never : Walk<Get<Scope, Root>, Rest> : never : never;
|
|
49
|
+
/** What a path walks into: the value of a record, not its methods. */
|
|
50
|
+
type DataOf<Value> = Value extends {
|
|
51
|
+
readonly [Meta]: {
|
|
52
|
+
readonly blueprint: IBlueprint<infer Properties>;
|
|
53
|
+
};
|
|
54
|
+
} ? BlueprintValue<Properties> : Value;
|
|
55
|
+
type Leaf = string | number | boolean | bigint | symbol | null | undefined | Date | readonly unknown[] | ((...args: any[]) => unknown);
|
|
56
|
+
type Below<Value, Prefix extends string, Expected, Depth extends unknown[]> = Depth["length"] extends 3 ? never : DataOf<NonNullable<Value>> extends infer Data ? Data extends Leaf ? never : {
|
|
57
|
+
[Key in keyof Data & string]-?: PathsFrom<Data[Key] | (Value extends null | undefined ? undefined : never), `${Prefix}.${Key}`, Expected, [
|
|
58
|
+
...Depth,
|
|
59
|
+
0
|
|
60
|
+
]>;
|
|
61
|
+
}[keyof Data & string] : never;
|
|
62
|
+
type PathsFrom<Value, Path extends string, Expected, Depth extends unknown[]> = Path extends unknown ? ([Value] extends [Expected] ? Path : never) | Below<Value, Path, Expected, Depth> : never;
|
|
63
|
+
/** Every reference of `Scope` whose value fits `Expected` (three keys deep at most). */
|
|
64
|
+
export type StepReferencesOf<Scope, Expected = unknown> = Scope extends unknown ? {
|
|
65
|
+
[Root in keyof Scope & string]-?: Root extends "env" ? Below<Scope[Root], `$${Root}`, Expected, [0]> : PathsFrom<Scope[Root], `$${Root}`, Expected, []>;
|
|
66
|
+
}[keyof Scope & string] : never;
|
|
67
|
+
/** `Reference` when it names a value of `Scope` that fits `Expected`; else the references that would. */
|
|
68
|
+
type CheckReference<Reference, Expected, Scope> = [
|
|
69
|
+
StepReferenceType<Scope, Reference>
|
|
70
|
+
] extends [infer Type] ? [Type] extends [never] ? StepReferencesOf<Scope, Expected> : [Type] extends [Expected] ? Reference : StepReferencesOf<Scope, Expected> : never;
|
|
71
|
+
type Primitive = string | number | boolean | null;
|
|
72
|
+
/** The type of the key `Key` in what `Expected` takes, over each object of it. */
|
|
73
|
+
type ExpectedAt<Expected, Key> = Expected extends object ? Key extends keyof Expected ? Expected[Key] : never : never;
|
|
74
|
+
/** The keys `Expected` takes in a mapping. */
|
|
75
|
+
type KnownKeys<Expected> = Expected extends object ? keyof Expected : never;
|
|
76
|
+
/** The keys the plain objects of `Expected` require (a record instance is not built from a mapping). */
|
|
77
|
+
type RequiredKeys<Expected> = Expected extends {
|
|
78
|
+
readonly [Meta]: unknown;
|
|
79
|
+
} ? never : Expected extends object ? {
|
|
80
|
+
[Key in keyof Expected]-?: undefined extends Expected[Key] ? never : Key;
|
|
81
|
+
}[keyof Expected] : never;
|
|
82
|
+
/** The keys of `Value` that `Expected` takes, each checked; the others are excess properties. */
|
|
83
|
+
type CheckKeys<Value, Expected, Scope> = Value extends unknown ? {
|
|
84
|
+
readonly [Key in keyof Value as Key extends KnownKeys<Expected> ? Key : never]: StepValueCheck<Value[Key], ExpectedAt<Expected, Key>, Scope>;
|
|
85
|
+
} : never;
|
|
86
|
+
type CheckMapping<Value, Expected, Scope> = unknown extends Expected ? {
|
|
87
|
+
readonly [Key in keyof Value]: StepValueCheck<Value[Key], unknown, Scope>;
|
|
88
|
+
} : [Exclude<RequiredKeys<Expected>, keyof Value>] extends [never] ? CheckKeys<Value, Expected, Scope> : CheckKeys<Value, Expected, Scope> & {
|
|
89
|
+
readonly [Key in Exclude<RequiredKeys<Expected>, keyof Value>]: ExpectedAt<Expected, Key>;
|
|
90
|
+
};
|
|
91
|
+
type ElementAt<Expected, Index> = unknown extends Expected ? unknown : Expected extends readonly unknown[] ? Index extends keyof Expected ? Expected[Index] : Expected[number] : never;
|
|
92
|
+
/**
|
|
93
|
+
* What the step value `Value` must be where `Expected` is taken: itself when
|
|
94
|
+
* it fits; else, for a reference, the references that would fit, and for a
|
|
95
|
+
* literal, `Expected`. A mapping is checked key by key, a list item by item.
|
|
96
|
+
*/
|
|
97
|
+
export type StepValueCheck<Value, Expected, Scope> = [Value] extends [
|
|
98
|
+
`$${string}`
|
|
99
|
+
] ? CheckReference<Value, Expected, Scope> : [Value] extends [Primitive] ? [Value] extends [Expected] ? Value : Expected : [Value] extends [{
|
|
100
|
+
readonly literal: unknown;
|
|
101
|
+
}] ? Value : [Value] extends [readonly unknown[]] ? {
|
|
102
|
+
readonly [Index in keyof Value]: StepValueCheck<Value[Index], ElementAt<Expected, Index>, Scope>;
|
|
103
|
+
} : [Value] extends [object] ? CheckMapping<Value, Expected, Scope> : Value;
|
|
104
|
+
/** The parameter `Index` of a function whose parameters are `Parameters`. */
|
|
105
|
+
type ParameterAt<Parameters extends readonly unknown[], Index> = Index extends keyof Parameters ? Parameters[Index] : number extends Parameters["length"] ? Parameters[number] : undefined;
|
|
106
|
+
/** What the `args` of a call must be: each against its parameter, or one reference to a list. */
|
|
107
|
+
type CheckArgs<Args, Parameters extends readonly unknown[], Scope> = [
|
|
108
|
+
Args
|
|
109
|
+
] extends [`$${string}`] ? CheckReference<Args, readonly unknown[], Scope> : {
|
|
110
|
+
readonly [Index in keyof Args]: StepValueCheck<Args[Index], ParameterAt<Parameters, Index>, Scope>;
|
|
111
|
+
};
|
|
112
|
+
type Fn = (...args: any[]) => unknown;
|
|
113
|
+
type ParametersOf<Value> = [Value] extends [Fn] ? Parameters<Value> : unknown[];
|
|
114
|
+
type FirstParameter<Value> = [Value] extends [never] ? unknown : [Value] extends [Fn] ? Parameters<Value>[0] : unknown;
|
|
115
|
+
type ResultOf<Value> = [Value] extends [Fn] ? Awaited<ReturnType<Value>> : unknown;
|
|
116
|
+
/** `Dependencies[Key][Member]`, or `unknown`. */
|
|
117
|
+
type MemberOf<Dependencies, Key, Member> = Key extends keyof Dependencies ? Member extends keyof Dependencies[Key] ? Dependencies[Key][Member] : unknown : unknown;
|
|
118
|
+
/** The method `"users.findByEmail"` names among `Dependencies`. */
|
|
119
|
+
type FindMethod<Dependencies, Target> = Target extends `${infer Repository}.${infer Action}` ? MemberOf<Dependencies, Repository, Action> : unknown;
|
|
120
|
+
/** The members of a record no `invoke` may call. */
|
|
121
|
+
type ForbiddenMethod = "set" | "emit" | "constructor" | "toLocaleString" | "valueOf" | "hasOwnProperty" | "isPrototypeOf" | "propertyIsEnumerable";
|
|
122
|
+
/** The public methods of the record `Record`: what `invoke.method` names. */
|
|
123
|
+
type StepInvokeMethod<Record> = Record extends unknown ? {
|
|
124
|
+
[Key in keyof Record & string]-?: Record[Key] extends Fn ? Key : never;
|
|
125
|
+
}[Exclude<keyof Record & string, ForbiddenMethod>] : never;
|
|
126
|
+
type ChangeOf<Record> = Record extends {
|
|
127
|
+
readonly change: infer Change;
|
|
128
|
+
} ? Change : never;
|
|
129
|
+
type UseCaseOf<Dependencies, Key> = Key extends keyof Dependencies ? Dependencies[Key] extends AnyUseCaseClass ? Dependencies[Key] : never : never;
|
|
130
|
+
/** A step that calls `Method` with its `args`: `[checked step, result]`. */
|
|
131
|
+
type CallStep<Step, Method, Scope> = [
|
|
132
|
+
{
|
|
133
|
+
readonly [Key in keyof Step]: Key extends "args" ? CheckArgs<Step[Key], ParametersOf<Method>, Scope> : Step[Key];
|
|
134
|
+
},
|
|
135
|
+
ResultOf<Method>
|
|
136
|
+
];
|
|
137
|
+
/** A step whose `Field` is checked against `Expected`: `[checked step, result]`. */
|
|
138
|
+
type ValueStep<Step, Field, Expected, Result, Scope> = [
|
|
139
|
+
{
|
|
140
|
+
readonly [Key in keyof Step]: Key extends Field ? StepValueCheck<Step[Key], Expected, Scope> : Step[Key];
|
|
141
|
+
},
|
|
142
|
+
Result
|
|
143
|
+
];
|
|
144
|
+
type InvokeStep<Step, Record, Scope> = [Record] extends [never] ? ValueStep<Step, "invoke", object, unknown, Scope> : [Step] extends [{
|
|
145
|
+
readonly method: infer Method;
|
|
146
|
+
}] ? Method extends keyof Record ? CallStep<Step, Record[Method], Scope> : [
|
|
147
|
+
{
|
|
148
|
+
readonly [Key in keyof Step]: Key extends "method" ? StepInvokeMethod<Record> : Step[Key];
|
|
149
|
+
},
|
|
150
|
+
unknown
|
|
151
|
+
] : [Step, unknown];
|
|
152
|
+
type ChangeStep<Step, Record, Scope> = [Record] extends [never] ? ValueStep<Step, "change", object, unknown, Scope> : [Step] extends [{
|
|
153
|
+
readonly key: infer Name;
|
|
154
|
+
}] ? Name extends keyof ChangeOf<Record> ? ValueStep<Step, "value", FirstParameter<ChangeOf<Record>[Name]>, Record, Scope> : [
|
|
155
|
+
{
|
|
156
|
+
readonly [Key in keyof Step]: Key extends "key" ? keyof ChangeOf<Record> & string : Step[Key];
|
|
157
|
+
},
|
|
158
|
+
Record
|
|
159
|
+
] : [Step, Record];
|
|
160
|
+
/** `[what Step must be, what it gives to its as]`, read against `Scope`. */
|
|
161
|
+
type CheckStep<Step, Dependencies, Scope> = [Step] extends [
|
|
162
|
+
{
|
|
163
|
+
readonly find: infer Target;
|
|
164
|
+
}
|
|
165
|
+
] ? CallStep<Step, FindMethod<Dependencies, Target>, Scope> : [Step] extends [{
|
|
166
|
+
readonly run: unknown;
|
|
167
|
+
readonly fn: infer Run;
|
|
168
|
+
}] ? CallStep<Step, Run, Scope> : [Step] extends [{
|
|
169
|
+
readonly invoke: infer Reference;
|
|
170
|
+
}] ? InvokeStep<Step, NonNullable<StepReferenceType<Scope, Reference>>, Scope> : [Step] extends [{
|
|
171
|
+
readonly change: infer Reference;
|
|
172
|
+
}] ? ChangeStep<Step, NonNullable<StepReferenceType<Scope, Reference>>, Scope> : [Step] extends [
|
|
173
|
+
{
|
|
174
|
+
readonly build: abstract new (value: infer Input) => infer Built;
|
|
175
|
+
}
|
|
176
|
+
] ? ValueStep<Step, "values", Input, Built, Scope> : [Step] extends [{
|
|
177
|
+
readonly call: infer Name;
|
|
178
|
+
}] ? ValueStep<Step, "input", UseCaseInput<UseCaseOf<Dependencies, Name>>, UseCaseResponse<UseCaseOf<Dependencies, Name>>, Scope> : [Step] extends [{
|
|
179
|
+
readonly create: infer Repository;
|
|
180
|
+
}] ? WriteStep<Step, MemberOf<Dependencies, Repository, "create">, Scope> : [Step] extends [{
|
|
181
|
+
readonly update: infer Repository;
|
|
182
|
+
}] ? WriteStep<Step, MemberOf<Dependencies, Repository, "update">, Scope> : [Step] extends [{
|
|
183
|
+
readonly delete: infer Repository;
|
|
184
|
+
}] ? WriteStep<Step, MemberOf<Dependencies, Repository, "delete">, Scope> : [Step] extends [{
|
|
185
|
+
readonly restore: infer Repository;
|
|
186
|
+
}] ? WriteStep<Step, MemberOf<Dependencies, Repository, "restore">, Scope> : ValueStep<Step, "value" | "other" | "details" | "return", unknown, unknown, Scope>;
|
|
187
|
+
type WriteStep<Step, Method, Scope> = ValueStep<Step, "value", FirstParameter<Method>, ResultOf<Method>, Scope>;
|
|
188
|
+
/** The scope after `Step`: its result bound to its `as`, or a value it ensures exists. */
|
|
189
|
+
type ScopeAfter<Step, Result, Scope> = [Step] extends [
|
|
190
|
+
{
|
|
191
|
+
readonly as: infer Name extends string;
|
|
192
|
+
}
|
|
193
|
+
] ? Scope & {
|
|
194
|
+
readonly [Key in Name]: Result;
|
|
195
|
+
} : [Step] extends [
|
|
196
|
+
{
|
|
197
|
+
readonly ensure: "exists";
|
|
198
|
+
readonly value: `$${infer Name}`;
|
|
199
|
+
}
|
|
200
|
+
] ? Name extends keyof Scope ? Scope & {
|
|
201
|
+
readonly [Key in Name]: NonNullable<Scope[Name]>;
|
|
202
|
+
} : Scope : Scope;
|
|
203
|
+
/** The steps folded in order, each checked against the scope the earlier ones built. */
|
|
204
|
+
type CheckSteps<Steps extends readonly unknown[], Dependencies, Scope, Checked extends readonly unknown[] = []> = [Steps] extends [readonly [infer Step, ...infer Rest]] ? CheckStep<Step, Dependencies, Scope> extends [infer Current, infer Result] ? CheckSteps<Rest, Dependencies, ScopeAfter<Step, Result, Scope>, [
|
|
205
|
+
...Checked,
|
|
206
|
+
Current
|
|
207
|
+
]> : never : readonly [...Checked];
|
|
208
|
+
/**
|
|
209
|
+
* What `useCaseOf` takes as `steps`: the steps, inferred as a tuple, each
|
|
210
|
+
* checked against the values in scope. Steps that are not a tuple (built at
|
|
211
|
+
* run time) are checked only when the use case is declared.
|
|
212
|
+
*/
|
|
213
|
+
export type CheckedSteps<Steps, Input extends IBlueprintCollection, Context extends IBlueprintCollection | undefined, Dependencies> = [Steps] extends [readonly [unknown, ...unknown[]]] ? CheckSteps<Steps, Dependencies, StepsInitialScope<Input, Context, Dependencies>> : Steps;
|
|
214
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { JsonValue } from "../../json.js";
|
|
2
|
+
/**
|
|
3
|
+
* Who is calling: what an authenticator made of the credentials of a request.
|
|
4
|
+
* `subject` identifies the caller (a user id), `scopes` is what it may do.
|
|
5
|
+
*/
|
|
6
|
+
export interface Principal {
|
|
7
|
+
readonly subject: string;
|
|
8
|
+
readonly scopes: readonly string[];
|
|
9
|
+
/** Anything else the credentials say (a tenant, a role). */
|
|
10
|
+
readonly claims?: Readonly<Record<string, JsonValue>>;
|
|
11
|
+
}
|
|
12
|
+
/** A value of the principal: its subject, its scopes or one of its claims. */
|
|
13
|
+
type PrincipalValue = "subject" | "scopes" | `claims.${string}`;
|
|
14
|
+
/**
|
|
15
|
+
* Who may call a use case, as data: declared with the `access` setting of
|
|
16
|
+
* `useCaseOf` or with `@Access`, and enforced by every output before the use
|
|
17
|
+
* case runs. `{ public: true }` lets anyone in. Any other declaration needs
|
|
18
|
+
* an authenticated caller (`{}` asks for nothing more), and may add:
|
|
19
|
+
*
|
|
20
|
+
* - `scopes`: the caller has all of them;
|
|
21
|
+
* - `owner`: the input key `input` equals the subject of the caller, or its
|
|
22
|
+
* claim `claim`;
|
|
23
|
+
* - `context`: keys of the context of the call filled from the caller, over
|
|
24
|
+
* whatever the request sent.
|
|
25
|
+
*/
|
|
26
|
+
export type AccessDeclaration = {
|
|
27
|
+
readonly public: true;
|
|
28
|
+
} | {
|
|
29
|
+
readonly public?: false;
|
|
30
|
+
readonly scopes?: readonly string[];
|
|
31
|
+
readonly owner?: {
|
|
32
|
+
readonly input: string;
|
|
33
|
+
readonly claim?: string;
|
|
34
|
+
};
|
|
35
|
+
readonly context?: {
|
|
36
|
+
readonly [contextKey: string]: PrincipalValue;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** An HTTP method an operation can be routed to. */
|
|
2
|
+
export type RouteMethod = "get" | "post" | "put" | "patch" | "delete";
|
|
3
|
+
/** The status of a successful call of a route; `204` has no body. */
|
|
4
|
+
export type RouteSuccessStatus = 200 | 201 | 202 | 204;
|
|
5
|
+
/** How a cookie a route sets is sent. The defaults are the safe ones for a session. */
|
|
6
|
+
export interface RouteCookie {
|
|
7
|
+
/** The name of the cookie. */
|
|
8
|
+
readonly name: string;
|
|
9
|
+
/** Not readable by scripts of the page. `true` by default. */
|
|
10
|
+
readonly httpOnly?: boolean;
|
|
11
|
+
/** Sent over HTTPS only. `true` by default. */
|
|
12
|
+
readonly secure?: boolean;
|
|
13
|
+
/** `"lax"` by default. */
|
|
14
|
+
readonly sameSite?: "strict" | "lax" | "none";
|
|
15
|
+
/** `"/"` by default. */
|
|
16
|
+
readonly path?: string;
|
|
17
|
+
readonly domain?: string;
|
|
18
|
+
/** The seconds the cookie lives; without it, until the browser closes. */
|
|
19
|
+
readonly maxAge?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Where a use case is served over HTTP, as data: declared with the `route`
|
|
23
|
+
* setting of `useCaseOf` or with `@Route`, and read by the sinks that serve
|
|
24
|
+
* or document HTTP. The blueprint of the use case stays the only description
|
|
25
|
+
* of its input: a route only says where each key comes from.
|
|
26
|
+
*/
|
|
27
|
+
export interface RouteDeclaration {
|
|
28
|
+
readonly method: RouteMethod;
|
|
29
|
+
/**
|
|
30
|
+
* The path, after the `basePath` of the sink, e.g. `"/posts/{slug}"`. A
|
|
31
|
+
* `{name}` segment fills the scalar input key `name`. Without it, the path
|
|
32
|
+
* is the default of the sink: `/{kebab(command)}/{kebab(operation)}`.
|
|
33
|
+
*/
|
|
34
|
+
readonly path?: string;
|
|
35
|
+
/** `200` by default. */
|
|
36
|
+
readonly status?: RouteSuccessStatus;
|
|
37
|
+
/**
|
|
38
|
+
* Scalar input keys read from the query string. A `get` or `delete` route
|
|
39
|
+
* reads from the query every key that has no other place, so this is for
|
|
40
|
+
* the routes with a body.
|
|
41
|
+
*/
|
|
42
|
+
readonly query?: readonly string[];
|
|
43
|
+
/** Scalar input keys read from request headers: `{ locale: "accept-language" }`. */
|
|
44
|
+
readonly headers?: {
|
|
45
|
+
readonly [inputKey: string]: string;
|
|
46
|
+
};
|
|
47
|
+
/** Scalar input keys read from cookies: `{ session: "sid" }`. */
|
|
48
|
+
readonly cookie?: {
|
|
49
|
+
readonly [inputKey: string]: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Scalar keys of the response sent as cookies instead of in the body:
|
|
53
|
+
* `{ token: { name: "sid" } }`. An empty text removes the cookie, and an
|
|
54
|
+
* absent value sets none.
|
|
55
|
+
*/
|
|
56
|
+
readonly setCookie?: {
|
|
57
|
+
readonly [responseKey: string]: RouteCookie;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* What the `route` setting and `@Route` take: a {@link RouteDeclaration}
|
|
62
|
+
* whose method may be written in upper case.
|
|
63
|
+
*/
|
|
64
|
+
export interface RouteSettings extends Omit<RouteDeclaration, "method"> {
|
|
65
|
+
readonly method: RouteMethod | Uppercase<RouteMethod>;
|
|
66
|
+
}
|
|
@@ -5,7 +5,10 @@ import { type DeclaredExceptionClass } from "../exception/exception.js";
|
|
|
5
5
|
import { type ILogger, type LoggerDeclaration } from "../logger/logger.js";
|
|
6
6
|
import type { AnyRepository } from "../repository/types/repository.interface.js";
|
|
7
7
|
import { Kind } from "../symbols/kind.js";
|
|
8
|
+
import type { CheckedSteps } from "./steps/types/check.interface.js";
|
|
8
9
|
import type { UseCaseStep } from "./steps/types/steps.interface.js";
|
|
10
|
+
import type { AccessDeclaration } from "./types/access.interface.js";
|
|
11
|
+
import type { RouteDeclaration, RouteSettings } from "./types/route.interface.js";
|
|
9
12
|
/** A concrete UseCase declaration, usable as a dependency. */
|
|
10
13
|
export interface AnyUseCaseClass {
|
|
11
14
|
readonly [Kind]: "use-case";
|
|
@@ -18,6 +21,10 @@ export interface AnyUseCaseClass {
|
|
|
18
21
|
readonly tags: readonly string[];
|
|
19
22
|
readonly deprecated: boolean;
|
|
20
23
|
readonly errors: readonly AnyExceptionClass[];
|
|
24
|
+
/** Where it is served over HTTP, if it says so (see `RouteDeclaration`). */
|
|
25
|
+
readonly route: RouteDeclaration | undefined;
|
|
26
|
+
/** Who may call it, if it says so (see `AccessDeclaration`). */
|
|
27
|
+
readonly access: AccessDeclaration | undefined;
|
|
21
28
|
new (input: any, ...options: any[]): {
|
|
22
29
|
execute(): Promise<unknown>;
|
|
23
30
|
pullEvents(): EntityEvent[];
|
|
@@ -81,6 +88,22 @@ export interface UseCaseSettings<Input extends IBlueprintCollection, Output exte
|
|
|
81
88
|
readonly deprecated?: boolean;
|
|
82
89
|
/** The exceptions (made by `exceptionOf`) a caller should expect; documentation only. */
|
|
83
90
|
readonly errors?: readonly AnyExceptionClass[];
|
|
91
|
+
/**
|
|
92
|
+
* Where the use case is served over HTTP: method, path and where each
|
|
93
|
+
* input key is read from (see `RouteDeclaration`). A decorated class says
|
|
94
|
+
* the same with `@Route`. Read by the sinks that serve or document HTTP;
|
|
95
|
+
* the `route` option of a sink overrides the method, path and status.
|
|
96
|
+
*/
|
|
97
|
+
readonly route?: RouteSettings;
|
|
98
|
+
/**
|
|
99
|
+
* Who may call the use case through an output: anyone (`{ public: true }`),
|
|
100
|
+
* or an authenticated caller with these `scopes`, that is the `owner`
|
|
101
|
+
* named by an input key, and whose values fill the `context` (see
|
|
102
|
+
* `AccessDeclaration`). A decorated class says the same with `@Access`.
|
|
103
|
+
* Enforced before the use case runs; a call made in process, with
|
|
104
|
+
* `execute` or `command.run`, is trusted and not checked.
|
|
105
|
+
*/
|
|
106
|
+
readonly access?: AccessDeclaration;
|
|
84
107
|
}
|
|
85
108
|
/** `UseCaseSettings` with the `steps` that are its `execute`. */
|
|
86
109
|
export interface UseCaseStepsSettings<Input extends IBlueprintCollection, Output extends IBlueprintCollection, Dependencies extends UseCaseCollection, Context extends IBlueprintCollection | undefined = undefined> extends UseCaseSettings<Input, Output, Dependencies, Context> {
|
|
@@ -89,6 +112,30 @@ export interface UseCaseStepsSettings<Input extends IBlueprintCollection, Output
|
|
|
89
112
|
* interpreted by its `execute`, and described by `describe()`.
|
|
90
113
|
*/
|
|
91
114
|
readonly steps: readonly UseCaseStep<NoInfer<Dependencies>>[];
|
|
115
|
+
/** Checks the references and values of the steps at compile time (see `CheckedSteps`). */
|
|
116
|
+
readonly strictSteps?: boolean;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* What `useCaseOf` takes: `UseCaseSettings`, and the `steps` that make the
|
|
120
|
+
* class concrete, if any.
|
|
121
|
+
*/
|
|
122
|
+
export interface UseCaseDeclaration<Input extends IBlueprintCollection, Output extends IBlueprintCollection, Dependencies extends UseCaseCollection, Context extends IBlueprintCollection | undefined = undefined, Steps extends readonly UseCaseStep<Dependencies>[] | undefined = undefined, Strict extends boolean = false> extends UseCaseSettings<Input, Output, Dependencies, Context> {
|
|
123
|
+
/**
|
|
124
|
+
* What the use case does, as data (see `UseCaseStep`), which makes the
|
|
125
|
+
* class concrete: validated here, interpreted by its `execute`, and
|
|
126
|
+
* described by `describe()`. TypeScript checks the kinds of the steps and
|
|
127
|
+
* the names of dependencies and actions; with `strictSteps`, also their
|
|
128
|
+
* references and values (see `CheckedSteps`).
|
|
129
|
+
*/
|
|
130
|
+
readonly steps?: [Strict] extends [true] ? CheckedSteps<Steps, NoInfer<Input>, NoInfer<Context>, NoInfer<Dependencies>> : Steps;
|
|
131
|
+
/**
|
|
132
|
+
* `true` checks the steps, written inline, at compile time: each reference
|
|
133
|
+
* must name a value in scope (the input, the context, an environment or the
|
|
134
|
+
* result of an earlier step, at any depth), and the `args`, `values`,
|
|
135
|
+
* `value` and `input` of a step must fit what it calls or builds. It costs
|
|
136
|
+
* the editor more than the default checks. Without effect at run time.
|
|
137
|
+
*/
|
|
138
|
+
readonly strictSteps?: Strict;
|
|
92
139
|
}
|
|
93
140
|
export declare const InvalidUseCaseDeclaration: DeclaredExceptionClass<{
|
|
94
141
|
reason: string;
|
|
@@ -119,6 +166,10 @@ type UseCaseStatics<Input extends IBlueprintCollection, Output extends IBlueprin
|
|
|
119
166
|
readonly deprecated: boolean;
|
|
120
167
|
/** The exceptions a caller should expect. */
|
|
121
168
|
readonly errors: readonly AnyExceptionClass[];
|
|
169
|
+
/** Where it is served over HTTP, from the `route` setting or `@Route`. */
|
|
170
|
+
readonly route: RouteDeclaration | undefined;
|
|
171
|
+
/** Who may call it, from the `access` setting or `@Access`. */
|
|
172
|
+
readonly access: AccessDeclaration | undefined;
|
|
122
173
|
};
|
|
123
174
|
/** What a use case instance carries beyond `AbstractUseCase`. */
|
|
124
175
|
type UseCaseInstanceContext<Context extends IBlueprintCollection | undefined> = {
|
|
@@ -138,8 +189,7 @@ export type StepsUseCaseConstructor<Input extends IBlueprintCollection, Output e
|
|
|
138
189
|
* interprets them. Without, it is abstract: extend it and implement an async
|
|
139
190
|
* execute method.
|
|
140
191
|
*/
|
|
141
|
-
export declare function useCaseOf<Input extends IBlueprintCollection, Output extends IBlueprintCollection, const Dependencies extends UseCaseCollection = Record<never, never>, Context extends IBlueprintCollection | undefined = undefined>(settings:
|
|
142
|
-
export declare function useCaseOf<Input extends IBlueprintCollection, Output extends IBlueprintCollection, const Dependencies extends UseCaseCollection = Record<never, never>, Context extends IBlueprintCollection | undefined = undefined>(settings: UseCaseSettings<Input, Output, Dependencies, Context>): UseCaseConstructor<Input, Output, Dependencies, Context>;
|
|
192
|
+
export declare function useCaseOf<Input extends IBlueprintCollection, Output extends IBlueprintCollection, const Dependencies extends UseCaseCollection = Record<never, never>, Context extends IBlueprintCollection | undefined = undefined, const Steps extends readonly UseCaseStep<NoInfer<Dependencies>>[] | undefined = undefined, Strict extends boolean = false>(settings: UseCaseDeclaration<Input, Output, Dependencies, Context, Steps, Strict>): [Steps] extends [undefined] ? UseCaseConstructor<Input, Output, Dependencies, Context> : StepsUseCaseConstructor<Input, Output, Dependencies, Context>;
|
|
143
193
|
export declare function isUseCaseClass(value: unknown): value is AnyUseCaseClass;
|
|
144
194
|
export declare function isUseCase(value: unknown): value is AbstractUseCase<IBlueprintCollection, IBlueprintCollection, UseCaseCollection>;
|
|
145
195
|
export {};
|
package/dist/experimental.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@afora/core/experimental`: features that may change in any release. Not
|
|
3
|
-
* covered by the compatibility policy in `VERSIONING.md`.
|
|
3
|
+
* covered by the compatibility policy in `VERSIONING.md`. See
|
|
4
|
+
* `docs/api-tiers.md`.
|
|
4
5
|
*/
|
|
6
|
+
export { InvalidJwtOptions, jwtOf } from "./core/auth/jwt.js";
|
|
7
|
+
export type { DescribedJwtOptions, Jwt, JwtAlgorithm, JwtOptions, JwtSubject, JwtTokenOptions, } from "./core/auth/types/jwt.interface.js";
|
|
5
8
|
export { sliceOf, sliceValue } from "./core/blueprint/slice.js";
|
|
6
9
|
export type { SlicedBlueprint, SlicedValue, SliceMask, ValueMask, } from "./core/blueprint/types/slice.interface.js";
|
|
10
|
+
export { eventPolicyCatalogOf, eventPolicyDescriptionOf, } from "./core/event-policy/event-policy.js";
|
|
11
|
+
export { stageDescriptionOf } from "./core/output/stage.js";
|
|
12
|
+
export { type PropertyLineage, propertyLineageOf, } from "./core/property/lineage.js";
|
|
13
|
+
export { providerDescriptionOf } from "./core/repository/provider.js";
|
|
14
|
+
export { matchesQuery, prepareQuery, sameValue, selectRows, } from "./core/repository/query.js";
|
|
15
|
+
export { useCaseOriginOf } from "./core/use-case/plugin.js";
|
|
16
|
+
export { useCaseTargetOf } from "./core/use-case/target.js";
|
|
17
|
+
export type { UseCaseOriginInfo } from "./core/use-case/types/plugin.interface.js";
|
|
18
|
+
export type { StdTokenOptions } from "./std/use-cases/types.js";
|