@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,31 @@
|
|
|
1
|
+
import type { AnyRepository } from "../core/repository/types/repository.interface.js";
|
|
2
|
+
import type { ResourceAction, ResourceOptions, ResourceUseCases, StdUseCaseContext } from "./use-cases/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* The use cases of a CRUD resource over `repository`, for the `useCases` of
|
|
5
|
+
* `commandOf`: the standard `create`, `get`, `list`, `update` and `delete`,
|
|
6
|
+
* each with the route of a REST resource at `path`.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const Blog = commandOf({
|
|
10
|
+
* name: "Blog",
|
|
11
|
+
* useCases: resourceOf(Posts, { path: "/posts" }),
|
|
12
|
+
* });
|
|
13
|
+
* // POST /posts (201), GET /posts, GET /posts/{id}, PATCH /posts/{id}, DELETE /posts/{id}
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* It is only a shortcut for
|
|
17
|
+
* `(ctx) => ({ create: ctx.create(Posts, { route }), ... })`: the command it
|
|
18
|
+
* goes into is an ordinary one, and `describe()` shows the same standard use
|
|
19
|
+
* cases. `actions` picks some of the operations, and `access` says who may
|
|
20
|
+
* call them. A repository that lacks the action of an operation throws
|
|
21
|
+
* `UseCaseUnavailable` when the command is declared. For anything else an
|
|
22
|
+
* operation needs (`omit`, `owner`, hooks), write that one with `ctx` and
|
|
23
|
+
* spread the rest: `(ctx) => ({ ...resourceOf(Posts, options)(ctx), create: ctx.create(Posts, { ... }) })`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resourceOf<Repository extends AnyRepository, const Actions extends readonly ResourceAction[] = readonly [
|
|
26
|
+
"create",
|
|
27
|
+
"get",
|
|
28
|
+
"list",
|
|
29
|
+
"update",
|
|
30
|
+
"delete"
|
|
31
|
+
]>(repository: Repository, options: ResourceOptions<Actions>): (ctx: StdUseCaseContext) => Pick<ResourceUseCases<Repository>, Actions[number]>;
|
package/dist/std/runtime.d.ts
CHANGED
|
@@ -78,6 +78,12 @@ export declare function configure(services: RuntimeServices): void;
|
|
|
78
78
|
export declare function resetRuntime(): void;
|
|
79
79
|
/** The hasher in use; the default is chosen on first call, not at import. */
|
|
80
80
|
export declare function currentHasher(): PasswordHasher;
|
|
81
|
+
/**
|
|
82
|
+
* Whether the generator in use is the default one, whose ids `Id` accepts as
|
|
83
|
+
* they are; one that `configure` put in its place is checked as any value.
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
export declare function makesDefaultIds(): boolean;
|
|
81
87
|
/** Makes an id with the generator in use. */
|
|
82
88
|
export declare function generateId(): string;
|
|
83
89
|
/** `verifySync` of the hasher in use, or throws `SyncVerifyUnsupported`. */
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import type { LoginMaker, RegisterMaker } from "./types.js";
|
|
1
|
+
import type { LoginMaker, LogoutMaker, RefreshMaker, RegisterMaker } from "./types.js";
|
|
2
2
|
/** Stores an authenticatable entity, unless its email is taken. */
|
|
3
3
|
export declare const register: import("../../index.js").IUseCasePlugin<"register", RegisterMaker>;
|
|
4
4
|
/** Gives the authenticatable entity of an email, when the password matches. */
|
|
5
5
|
export declare const login: import("../../index.js").IUseCasePlugin<"login", LoginMaker>;
|
|
6
|
+
/** Exchanges a refresh token for new tokens. */
|
|
7
|
+
export declare const refresh: import("../../index.js").IUseCasePlugin<"refresh", RefreshMaker>;
|
|
8
|
+
/** Gives empty tokens, for a route that keeps them in cookies to remove them. */
|
|
9
|
+
export declare const logout: import("../../index.js").IUseCasePlugin<"logout", LogoutMaker>;
|
|
@@ -3,11 +3,13 @@ import type { AnyExceptionClass } from "../../core/use-case/use-case.js";
|
|
|
3
3
|
import { type Options, type Step } from "./shared.js";
|
|
4
4
|
import type { CreateMaker, DeleteMaker, GetMaker, ListMaker, RestoreMaker, UpdateMaker } from "./types.js";
|
|
5
5
|
/**
|
|
6
|
-
* The declaration of `create` and of `register`, which adds `
|
|
7
|
-
*
|
|
8
|
-
* and stored.
|
|
6
|
+
* The declaration of `create` and of `register`, which adds `checks` and
|
|
7
|
+
* their errors: an input of the keys of the entity, the entity built from
|
|
8
|
+
* it and stored. The option `before` runs first, and the steps after it read
|
|
9
|
+
* the input it gives; `checks` read it under `$input` all the same, rooted
|
|
10
|
+
* by the function given.
|
|
9
11
|
*/
|
|
10
|
-
export declare function createCompilation(target: UseCaseTargetInfo, options: Options, verb: string,
|
|
12
|
+
export declare function createCompilation(target: UseCaseTargetInfo, options: Options, verb: string, checks?: (input: string) => readonly Step[], errors?: readonly AnyExceptionClass[]): UseCaseCompilation;
|
|
11
13
|
/** Builds an entity from the input and stores it. */
|
|
12
14
|
export declare const create: import("../../index.js").IUseCasePlugin<"create", CreateMaker>;
|
|
13
15
|
/** Gives the entity of an id. */
|
|
@@ -6,6 +6,6 @@ import type { StdUseCasePlugins } from "./types.js";
|
|
|
6
6
|
* `list`, `update`, `delete` and `restore` for any entity; `publish`,
|
|
7
7
|
* `unpublish`, `archive`, `unarchive`, `tag` and `untag` for the entities
|
|
8
8
|
* with those record plugins; `register` and `login` for the
|
|
9
|
-
* authenticatable ones
|
|
9
|
+
* authenticatable ones, and `refresh` and `logout` for the tokens of `login`. `StdUseCases.context` is that `ctx`.
|
|
10
10
|
*/
|
|
11
11
|
export declare const StdUseCases: IUseCaseCatalog<StdUseCasePlugins>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BlueprintField } from "../../core/blueprint/types/blueprint.interface.js";
|
|
2
2
|
import type { UseCaseCompilation, UseCaseFieldPlan, UseCaseTargetInfo } from "../../core/use-case/types/plugin.interface.js";
|
|
3
|
-
import type { AnyExceptionClass } from "../../core/use-case/use-case.js";
|
|
3
|
+
import type { AnyExceptionClass, UseCaseDependency } from "../../core/use-case/use-case.js";
|
|
4
4
|
/** A blueprint of the fields given, with no context of properties. */
|
|
5
5
|
export declare const fields: import("../../index.js").BlueprintBuilder<readonly []>;
|
|
6
6
|
export type Options = Readonly<Record<string, unknown>>;
|
|
@@ -10,8 +10,10 @@ export declare const capitalize: (key: string) => string;
|
|
|
10
10
|
export declare function literal(value: unknown): unknown;
|
|
11
11
|
/** The option `key`, checked to be one of the `allowed` options of the use case. */
|
|
12
12
|
export declare function checkOptions(target: UseCaseTargetInfo, options: Options, allowed: readonly string[]): void;
|
|
13
|
-
/** The
|
|
14
|
-
export declare
|
|
13
|
+
/** The options of the use cases that write: `before`, `after`, `dependencies`, `throws`. */
|
|
14
|
+
export declare const HOOKS: readonly ["before", "after", "dependencies", "throws"];
|
|
15
|
+
/** The name, description, tags, `deprecated`, route and access of the use case. */
|
|
16
|
+
export declare function metaOf(target: UseCaseTargetInfo, options: Options, verb: string): Pick<UseCaseCompilation, "name" | "description" | "tags" | "deprecated" | "route" | "access">;
|
|
15
17
|
/** The key of the response that holds the entity: the option `as`, `item` by default. */
|
|
16
18
|
export declare function asOf(target: UseCaseTargetInfo, options: Options): string;
|
|
17
19
|
/** The error of `kind` the options give, else `fallback`. */
|
|
@@ -43,18 +45,44 @@ export declare function contextOf(owner: Owner | undefined): Pick<UseCaseCompila
|
|
|
43
45
|
* when there is none, and when it is not the caller's.
|
|
44
46
|
*/
|
|
45
47
|
export declare function loadSteps(owner: Owner | undefined, notFound: AnyExceptionClass): Step[];
|
|
48
|
+
/** What the options `before`, `after`, `dependencies` and `throws` add to a use case. */
|
|
49
|
+
export interface Hooks {
|
|
50
|
+
/** The root of the input the steps read: `$input`, or `$prepared` after `before`. */
|
|
51
|
+
readonly input: string;
|
|
52
|
+
/** The dependencies the options give, joined to those the use case makes. */
|
|
53
|
+
readonly dependencies: Readonly<Record<string, UseCaseDependency>>;
|
|
54
|
+
readonly throws: readonly AnyExceptionClass[];
|
|
55
|
+
/** The step of `before`, if any: it binds `prepared`, the input it gives back or the one it got. */
|
|
56
|
+
before(entity?: string): Step[];
|
|
57
|
+
/** The step of `after`, if any, over the entity written. */
|
|
58
|
+
after(entity: string): Step[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The options `before`, `after`, `dependencies` and `throws`, checked: each
|
|
62
|
+
* hook becomes a `run` step, whose function gets `{ input, entity?,
|
|
63
|
+
* dependencies, context }` (the bound dependencies of the call, overrides
|
|
64
|
+
* included).
|
|
65
|
+
*/
|
|
66
|
+
export declare function hooksOf(target: UseCaseTargetInfo, options: Options): Hooks;
|
|
67
|
+
/**
|
|
68
|
+
* The dependencies a use case makes, joined to those of the option
|
|
69
|
+
* `dependencies`; a name taken by both is unavailable.
|
|
70
|
+
*/
|
|
71
|
+
export declare function joinDependencies(target: UseCaseTargetInfo, made: Readonly<Record<string, UseCaseDependency>>, hooks: Hooks): Readonly<Record<string, UseCaseDependency>>;
|
|
46
72
|
/** The id field of the entity of `target`. */
|
|
47
73
|
export declare const idOf: (target: UseCaseTargetInfo) => BlueprintField;
|
|
48
74
|
/** The classes of `errors`, each once. */
|
|
49
75
|
export declare const distinct: (...errors: readonly AnyExceptionClass[]) => AnyExceptionClass[];
|
|
50
76
|
/**
|
|
51
77
|
* A use case over one entity found by id: `{ id }` in, `{ [as]: entity }`
|
|
52
|
-
* out; loads it, checks the owner, runs `
|
|
53
|
-
* give under `result`) and gives it.
|
|
78
|
+
* out; loads it, checks the owner, runs `before` (with `hooks`), `steps`
|
|
79
|
+
* (which leave the entity to give under `result`) and `after`, and gives it.
|
|
80
|
+
* `steps` read the input under `input`: `$input`, or what `before` gave.
|
|
54
81
|
*/
|
|
55
82
|
export declare function entityUseCase(target: UseCaseTargetInfo, options: Options, verb: string, allowed: readonly string[], steps: (context: {
|
|
56
83
|
readonly owner: Owner | undefined;
|
|
84
|
+
readonly input: string;
|
|
57
85
|
}) => {
|
|
58
86
|
readonly steps: readonly Step[];
|
|
59
87
|
readonly result: string;
|
|
60
|
-
}): UseCaseCompilation;
|
|
88
|
+
}, hooks?: boolean): UseCaseCompilation;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DescribedJwtOptions } from "../../core/auth/types/jwt.interface.js";
|
|
2
|
+
import type { AnyBlueprint, AnyBlueprintList, AnyRecordClass, BlueprintField, BlueprintValue, IBlueprint, IBlueprintCollection, IBlueprintList, OptionalBlueprint, OptionalBlueprintList, OptionalRecord } from "../../core/blueprint/types/blueprint.interface.js";
|
|
2
3
|
import type { EntityIdentityKey } from "../../core/entity/types/entity.interface.js";
|
|
4
|
+
import type { EntityVersion } from "../../core/entity/version.js";
|
|
3
5
|
import type { OptionalProperty } from "../../core/property/types/optional-property.type.js";
|
|
4
6
|
import type { AnyPropertyConstructor } from "../../core/property/types/property-collection.type.js";
|
|
5
7
|
import type { AnyRepository, AnyRepositoryEntity, EntityInstanceOf } from "../../core/repository/types/repository.interface.js";
|
|
8
|
+
import type { AccessDeclaration } from "../../core/use-case/types/access.interface.js";
|
|
6
9
|
import type { IUseCasePlugin, UseCaseTarget } from "../../core/use-case/types/plugin.interface.js";
|
|
7
|
-
import type {
|
|
10
|
+
import type { RouteSettings } from "../../core/use-case/types/route.interface.js";
|
|
11
|
+
import type { AnyExceptionClass, DependencyFunctions, StepsUseCaseConstructor, UseCaseCollection } from "../../core/use-case/use-case.js";
|
|
8
12
|
import type { Integer, StringProperty } from "../properties/primitives.js";
|
|
9
13
|
type EntityOf<Repository> = Repository extends {
|
|
10
14
|
readonly entity: infer Entity extends AnyRepositoryEntity;
|
|
@@ -43,7 +47,41 @@ export interface StdUseCaseOptions {
|
|
|
43
47
|
readonly tags?: readonly string[];
|
|
44
48
|
readonly deprecated?: boolean;
|
|
45
49
|
readonly errors?: StdUseCaseErrors;
|
|
50
|
+
/** Where the use case is served over HTTP: the `route` of `useCaseOf`. */
|
|
51
|
+
readonly route?: RouteSettings;
|
|
52
|
+
/** Who may call it: the `access` of `useCaseOf`. */
|
|
53
|
+
readonly access?: AccessDeclaration;
|
|
46
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* The tokens `login` and `refresh` issue: the options of `jwtOf`, plus what
|
|
57
|
+
* a token says of the entity. JSON, so it lives in an `afora.json`: the
|
|
58
|
+
* secret is named by its environment variable (`{ env: "JWT_SECRET" }`).
|
|
59
|
+
* Experimental: it may change in any release.
|
|
60
|
+
*/
|
|
61
|
+
export interface StdTokenOptions extends DescribedJwtOptions {
|
|
62
|
+
/** Also issues a refresh token, which `refresh` exchanges; `expiresIn` is its life in seconds. */
|
|
63
|
+
readonly refresh?: {
|
|
64
|
+
readonly expiresIn: number;
|
|
65
|
+
};
|
|
66
|
+
/** Scopes every token gets. */
|
|
67
|
+
readonly scopes?: readonly string[];
|
|
68
|
+
/** A key of the entity that holds a list of scopes, added to `scopes`. */
|
|
69
|
+
readonly scopesFrom?: string;
|
|
70
|
+
/** Claims of the token, each from a key of the entity: `{ tenant: "tenantId" }`. */
|
|
71
|
+
readonly claims?: {
|
|
72
|
+
readonly [claim: string]: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** The response keys the `token` option adds. */
|
|
76
|
+
type TokenResponse<Options> = Options extends {
|
|
77
|
+
readonly token: infer Token;
|
|
78
|
+
} ? {
|
|
79
|
+
readonly token: typeof StringProperty;
|
|
80
|
+
} & (Token extends {
|
|
81
|
+
readonly refresh: object;
|
|
82
|
+
} ? {
|
|
83
|
+
readonly refreshToken: typeof StringProperty;
|
|
84
|
+
} : unknown) : unknown;
|
|
47
85
|
/** Who owns the entities: the caller, whose id the context gives. */
|
|
48
86
|
export interface StdOwnerOption<Repository> {
|
|
49
87
|
/**
|
|
@@ -88,6 +126,79 @@ export interface StdListOptions<Repository> extends StdUseCaseOptions, StdOwnerO
|
|
|
88
126
|
}[];
|
|
89
127
|
}
|
|
90
128
|
type None = Record<never, never>;
|
|
129
|
+
/** What `before` and `after` get of the call. */
|
|
130
|
+
export interface StdHookArgs<Input, Dependencies, Context> {
|
|
131
|
+
/** The input of the call, parsed; for `after`, the one `before` gave back. */
|
|
132
|
+
readonly input: Input;
|
|
133
|
+
/**
|
|
134
|
+
* The dependencies of the call, as `execute` resolved them (overrides
|
|
135
|
+
* included): `repository`, those the use case makes to load what the
|
|
136
|
+
* input names, and those of the option `dependencies`.
|
|
137
|
+
*/
|
|
138
|
+
readonly dependencies: Dependencies;
|
|
139
|
+
/** The context of the call: the id of the caller with `owner`, else `undefined`. */
|
|
140
|
+
readonly context: Context;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The options of a standard use case that writes: `before` runs before the
|
|
144
|
+
* write and may give back the input to write in place of the one given;
|
|
145
|
+
* `after` runs after it, within the transaction of the command; both get the
|
|
146
|
+
* dependencies of the use case and those of `dependencies`, and `throws` adds
|
|
147
|
+
* the exceptions they may throw to its errors (for `describe()` and statuses).
|
|
148
|
+
*/
|
|
149
|
+
export interface StdHookOptions<Input, Entity, Dependencies extends UseCaseCollection, Bound, Context, Loaded extends boolean> {
|
|
150
|
+
/** Repositories, use cases or environments the hooks use, by name, beside those the use case makes. */
|
|
151
|
+
readonly dependencies?: Dependencies;
|
|
152
|
+
/**
|
|
153
|
+
* Runs before the write (after the entity is loaded and its owner
|
|
154
|
+
* checked, for a use case over one entity, which gets it as `entity`);
|
|
155
|
+
* what it gives back, if anything, is the input the use case goes on with.
|
|
156
|
+
*/
|
|
157
|
+
readonly before?: (args: StdHookArgs<Input, Bound, Context> & (Loaded extends true ? {
|
|
158
|
+
readonly entity: Entity;
|
|
159
|
+
} : unknown)) => Input | void | Promise<Input | void>;
|
|
160
|
+
/** Runs after the write, with the entity written, before the response is given. */
|
|
161
|
+
readonly after?: (args: StdHookArgs<Input, Bound, Context> & {
|
|
162
|
+
readonly entity: Entity;
|
|
163
|
+
}) => unknown;
|
|
164
|
+
/** Exceptions (made by `exceptionOf`) `before` or `after` may throw: added to the errors of the use case. */
|
|
165
|
+
readonly throws?: readonly AnyExceptionClass[];
|
|
166
|
+
}
|
|
167
|
+
/** What `get`, `list` and `login` take in place of the hooks: none. */
|
|
168
|
+
export interface StdNoHookOptions {
|
|
169
|
+
readonly before?: never;
|
|
170
|
+
readonly after?: never;
|
|
171
|
+
readonly dependencies?: never;
|
|
172
|
+
readonly throws?: never;
|
|
173
|
+
}
|
|
174
|
+
type ContextValue<Repository, Options> = OwnerContext<Repository, Options> extends infer Context extends IBlueprintCollection ? Readonly<BlueprintValue<Context>> : undefined;
|
|
175
|
+
/** `Options` as `Hookable` infers them. */
|
|
176
|
+
type Shape<Omitted, Values, Owner> = {
|
|
177
|
+
readonly omit: readonly Omitted[];
|
|
178
|
+
readonly values: Values;
|
|
179
|
+
} & ([Owner] extends [undefined] ? unknown : {
|
|
180
|
+
readonly owner: Owner;
|
|
181
|
+
});
|
|
182
|
+
/** `StdHookOptions` for a use case over `Repository` that takes `Input`. */
|
|
183
|
+
type HookOptionsOf<Repository extends AnyRepository, Options, Input extends IBlueprintCollection, Dependencies extends UseCaseCollection, Loaded extends boolean> = StdHookOptions<BlueprintValue<Input>, EntityInstanceOf<EntityOf<Repository>>, Dependencies, DependencyFunctions<{
|
|
184
|
+
readonly repository: Repository;
|
|
185
|
+
} & Dependencies>, ContextValue<Repository, Options>, Loaded>;
|
|
186
|
+
/**
|
|
187
|
+
* The options of a use case that writes, as its maker reads them: those that
|
|
188
|
+
* type its input and context, inferred one by one (`Options` is inferred from
|
|
189
|
+
* the whole object only once the hooks are typed), and the hooks, typed by
|
|
190
|
+
* them and not inferred from. The types of `before` and `after` are only
|
|
191
|
+
* worked out for a call that gives them.
|
|
192
|
+
*/
|
|
193
|
+
interface Hookable<Repository extends AnyRepository, Input extends IBlueprintCollection, Omitted, Values, Owner, Dependencies extends UseCaseCollection, Loaded extends boolean> {
|
|
194
|
+
readonly omit?: readonly Omitted[];
|
|
195
|
+
readonly values?: Values;
|
|
196
|
+
readonly owner?: Owner;
|
|
197
|
+
readonly dependencies?: Dependencies;
|
|
198
|
+
readonly throws?: readonly AnyExceptionClass[];
|
|
199
|
+
readonly before?: NoInfer<HookOptionsOf<Repository, Shape<Omitted, Values, Owner>, Input, Dependencies, Loaded>["before"]>;
|
|
200
|
+
readonly after?: NoInfer<HookOptionsOf<Repository, Shape<Omitted, Values, Owner>, Input, Dependencies, Loaded>["after"]>;
|
|
201
|
+
}
|
|
91
202
|
type AsOf<Options> = Options extends {
|
|
92
203
|
readonly as: infer Key extends string;
|
|
93
204
|
} ? Key : "item";
|
|
@@ -111,9 +222,13 @@ type LeftOut<Options> = EntityIdentityKey | OwnerKey<Options> | (Options extends
|
|
|
111
222
|
} ? Key : never) | (Options extends {
|
|
112
223
|
readonly values: infer Values;
|
|
113
224
|
} ? keyof Values : never);
|
|
225
|
+
/** `"version"` for a versioned entity, whose `version` is part of its identity. */
|
|
226
|
+
type VersionKey<Repository> = Props<Repository> extends {
|
|
227
|
+
readonly version: typeof EntityVersion;
|
|
228
|
+
} ? "version" : never;
|
|
114
229
|
/** The input of `create`: the keys of the entity, an entity it holds by `<key>Id`. */
|
|
115
230
|
type CreateInput<Repository, Options> = {
|
|
116
|
-
readonly [Key in KeyOf<Repository> as Key extends LeftOut<Options> ? never : Props<Repository>[Key] extends AnyRepositoryEntity ? `${Key}Id` : HoldsEntity<Props<Repository>[Key]> extends true ? never : Key]: Props<Repository>[Key] extends AnyRepositoryEntity ? FieldAt<PropertiesOf<Props<Repository>[Key]>, "id"> : Props<Repository>[Key];
|
|
231
|
+
readonly [Key in KeyOf<Repository> as Key extends LeftOut<Options> | VersionKey<Repository> ? never : Props<Repository>[Key] extends AnyRepositoryEntity ? `${Key}Id` : HoldsEntity<Props<Repository>[Key]> extends true ? never : Key]: Props<Repository>[Key] extends AnyRepositoryEntity ? FieldAt<PropertiesOf<Props<Repository>[Key]>, "id"> : Props<Repository>[Key];
|
|
117
232
|
};
|
|
118
233
|
type ChangeKey<Repository> = EntityInstanceOf<EntityOf<Repository>> extends {
|
|
119
234
|
readonly change: infer Changes;
|
|
@@ -122,18 +237,18 @@ type ChangeKey<Repository> = EntityInstanceOf<EntityOf<Repository>> extends {
|
|
|
122
237
|
type UpdateInput<Repository> = {
|
|
123
238
|
readonly [Key in "id" | ChangeKey<Repository> as Key extends "id" ? Key : HoldsEntity<Props<Repository>[Key]> extends true ? never : Key]: Key extends "id" ? IdField<Repository> : Optional<Props<Repository>[Key]>;
|
|
124
239
|
};
|
|
125
|
-
type EntityUseCase<Repository extends AnyRepository, Options, Input extends IBlueprintCollection> = StepsUseCaseConstructor<Input, EntityResponse<Repository, Options>, {
|
|
240
|
+
type EntityUseCase<Repository extends AnyRepository, Options, Input extends IBlueprintCollection, Dependencies extends UseCaseCollection = None> = StepsUseCaseConstructor<Input, EntityResponse<Repository, Options>, {
|
|
126
241
|
readonly repository: Repository;
|
|
127
|
-
}, OwnerContext<Repository, Options>>;
|
|
242
|
+
} & Dependencies, OwnerContext<Repository, Options>>;
|
|
128
243
|
type ById<Repository> = {
|
|
129
244
|
readonly id: IdField<Repository>;
|
|
130
245
|
};
|
|
131
246
|
/** `create`: for a repository with the `create` action. */
|
|
132
|
-
export type CreateMaker = <Repository extends AnyRepository, const Options extends StdCreateOptions<Repository> = None>(repository: Repository & UseCaseTarget<Repository, "create">, options?: Options) => EntityUseCase<Repository, Options, CreateInput<Repository, Options
|
|
247
|
+
export type CreateMaker = <Repository extends AnyRepository, const Options extends StdCreateOptions<Repository> = None, const Omitted extends KeyOf<Repository> = never, const Values = None, const Owner = undefined, const Dependencies extends UseCaseCollection = None>(repository: Repository & UseCaseTarget<Repository, "create">, options?: Options & Hookable<Repository, CreateInput<Repository, Shape<Omitted, Values, Owner>>, Omitted, Values, Owner, Dependencies, false>) => EntityUseCase<Repository, Options, CreateInput<Repository, Options>, Dependencies>;
|
|
133
248
|
/** `get`: for a repository with `findById`. */
|
|
134
|
-
export type GetMaker = <Repository extends AnyRepository, const Options extends StdEntityOptions<Repository> = None>(repository: Repository & UseCaseTarget<Repository, "findById">, options?: Options) => EntityUseCase<Repository, Options, ById<Repository>>;
|
|
249
|
+
export type GetMaker = <Repository extends AnyRepository, const Options extends StdEntityOptions<Repository> & StdNoHookOptions = None>(repository: Repository & UseCaseTarget<Repository, "findById">, options?: Options) => EntityUseCase<Repository, Options, ById<Repository>>;
|
|
135
250
|
/** `list`: for a repository with `findPage`. */
|
|
136
|
-
export type ListMaker = <Repository extends AnyRepository, const Options extends StdListOptions<Repository> = None>(repository: Repository & UseCaseTarget<Repository, "findPage">, options?: Options) => StepsUseCaseConstructor<{
|
|
251
|
+
export type ListMaker = <Repository extends AnyRepository, const Options extends StdListOptions<Repository> & StdNoHookOptions = None>(repository: Repository & UseCaseTarget<Repository, "findPage">, options?: Options) => StepsUseCaseConstructor<{
|
|
137
252
|
readonly limit: OptionalProperty<typeof Integer>;
|
|
138
253
|
readonly offset: OptionalProperty<typeof Integer>;
|
|
139
254
|
}, {
|
|
@@ -145,46 +260,69 @@ export type ListMaker = <Repository extends AnyRepository, const Options extends
|
|
|
145
260
|
readonly repository: Repository;
|
|
146
261
|
}, OwnerContext<Repository, Options>>;
|
|
147
262
|
/** `update`: for a repository with `findById` and `update`. */
|
|
148
|
-
export type UpdateMaker = <Repository extends AnyRepository, const Options extends StdEntityOptions<Repository> = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "update">, options?: Options) => EntityUseCase<Repository, Options, UpdateInput<Repository
|
|
263
|
+
export type UpdateMaker = <Repository extends AnyRepository, const Options extends StdEntityOptions<Repository> = None, const Owner = undefined, const Dependencies extends UseCaseCollection = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "update">, options?: Options & Hookable<Repository, UpdateInput<Repository>, never, None, Owner, Dependencies, true>) => EntityUseCase<Repository, Options, UpdateInput<Repository>, Dependencies>;
|
|
149
264
|
/** `delete`: for a repository with `findById` and `delete`. */
|
|
150
|
-
export type DeleteMaker = <Repository extends AnyRepository, const Options extends StdEntityOptions<Repository> = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "delete">, options?: Options) => EntityUseCase<Repository, Options, ById<Repository
|
|
265
|
+
export type DeleteMaker = <Repository extends AnyRepository, const Options extends StdEntityOptions<Repository> = None, const Owner = undefined, const Dependencies extends UseCaseCollection = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "delete">, options?: Options & Hookable<Repository, ById<Repository>, never, None, Owner, Dependencies, true>) => EntityUseCase<Repository, Options, ById<Repository>, Dependencies>;
|
|
151
266
|
/** `restore`: for a repository with soft deletion and the `restore` action. */
|
|
152
267
|
export type RestoreMaker = <Repository extends AnyRepository, const Options extends StdUseCaseOptions & {
|
|
153
268
|
readonly as?: string;
|
|
154
|
-
} = None>(repository: Repository & UseCaseTarget<Repository, "restore">, options?: Options) => StepsUseCaseConstructor<ById<Repository>, EntityResponse<Repository, Options>, {
|
|
269
|
+
} = None, const Dependencies extends UseCaseCollection = None>(repository: Repository & UseCaseTarget<Repository, "restore">, options?: Options & Hookable<Repository, ById<Repository>, never, None, undefined, Dependencies, false>) => StepsUseCaseConstructor<ById<Repository>, EntityResponse<Repository, Options>, {
|
|
155
270
|
readonly repository: Repository;
|
|
156
|
-
}>;
|
|
271
|
+
} & Dependencies>;
|
|
157
272
|
/** `publish` and `unpublish`: for a publishable entity. */
|
|
158
|
-
export type PublishMaker = <Repository extends AnyRepository, const Options extends StdLifecycleOptions<Repository> = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "update", {
|
|
273
|
+
export type PublishMaker = <Repository extends AnyRepository, const Options extends StdLifecycleOptions<Repository> = None, const Owner = undefined, const Dependencies extends UseCaseCollection = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "update", {
|
|
159
274
|
publish(at?: string): unknown;
|
|
160
275
|
unpublish(): unknown;
|
|
161
|
-
}, "publishable">, options?: Options) => EntityUseCase<Repository, Options, ById<Repository
|
|
276
|
+
}, "publishable">, options?: Options & Hookable<Repository, ById<Repository>, never, None, Owner, Dependencies, true>) => EntityUseCase<Repository, Options, ById<Repository>, Dependencies>;
|
|
162
277
|
/** `archive` and `unarchive`: for an archivable entity. */
|
|
163
|
-
export type ArchiveMaker = <Repository extends AnyRepository, const Options extends StdLifecycleOptions<Repository> = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "update", {
|
|
278
|
+
export type ArchiveMaker = <Repository extends AnyRepository, const Options extends StdLifecycleOptions<Repository> = None, const Owner = undefined, const Dependencies extends UseCaseCollection = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "update", {
|
|
164
279
|
archive(at?: string): unknown;
|
|
165
280
|
readonly isArchived: boolean;
|
|
166
|
-
}, "archivable">, options?: Options) => EntityUseCase<Repository, Options, ById<Repository
|
|
281
|
+
}, "archivable">, options?: Options & Hookable<Repository, ById<Repository>, never, None, Owner, Dependencies, true>) => EntityUseCase<Repository, Options, ById<Repository>, Dependencies>;
|
|
167
282
|
/** `tag` and `untag`: for a taggable entity. */
|
|
168
|
-
export type TagMaker = <Repository extends AnyRepository, const Options extends StdEntityOptions<Repository> = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "update", {
|
|
283
|
+
export type TagMaker = <Repository extends AnyRepository, const Options extends StdEntityOptions<Repository> = None, const Owner = undefined, const Dependencies extends UseCaseCollection = None>(repository: Repository & UseCaseTarget<Repository, "findById" | "update", {
|
|
169
284
|
tag(...tags: string[]): unknown;
|
|
170
285
|
untag(...tags: string[]): unknown;
|
|
171
|
-
}, "taggable">, options?: Options) => EntityUseCase<Repository, Options,
|
|
286
|
+
}, "taggable">, options?: Options & Hookable<Repository, TagInput<Repository>, never, None, Owner, Dependencies, true>) => EntityUseCase<Repository, Options, TagInput<Repository>, Dependencies>;
|
|
287
|
+
type TagInput<Repository> = ById<Repository> & {
|
|
172
288
|
readonly tags: IBlueprintList<typeof StringProperty>;
|
|
173
|
-
}
|
|
289
|
+
};
|
|
174
290
|
type Authenticatable = {
|
|
175
291
|
verifyPassword(plain: string): Promise<boolean>;
|
|
176
292
|
};
|
|
177
293
|
/** `register`: for an authenticatable entity, with `findByEmail` and `create`. */
|
|
178
|
-
export type RegisterMaker = <Repository extends AnyRepository, const Options extends StdCreateOptions<Repository> = None>(repository: Repository & UseCaseTarget<Repository, "findByEmail" | "create", Authenticatable, "authenticatable">, options?: Options) => EntityUseCase<Repository, Options, CreateInput<Repository, Options
|
|
294
|
+
export type RegisterMaker = <Repository extends AnyRepository, const Options extends StdCreateOptions<Repository> = None, const Omitted extends KeyOf<Repository> = never, const Values = None, const Owner = undefined, const Dependencies extends UseCaseCollection = None>(repository: Repository & UseCaseTarget<Repository, "findByEmail" | "create", Authenticatable, "authenticatable">, options?: Options & Hookable<Repository, CreateInput<Repository, Shape<Omitted, Values, Owner>>, Omitted, Values, Owner, Dependencies, false>) => EntityUseCase<Repository, Options, CreateInput<Repository, Options>, Dependencies>;
|
|
179
295
|
/** `login`: for an authenticatable entity, with `findByEmail`. */
|
|
180
296
|
export type LoginMaker = <Repository extends AnyRepository, const Options extends StdUseCaseOptions & {
|
|
181
297
|
readonly as?: string;
|
|
182
|
-
|
|
298
|
+
/** Issues a token for the entity (and a refresh token, with `refresh`), in the response. */
|
|
299
|
+
readonly token?: StdTokenOptions;
|
|
300
|
+
} & StdNoHookOptions = None>(repository: Repository & UseCaseTarget<Repository, "findByEmail", Authenticatable, "authenticatable">, options?: Options) => StepsUseCaseConstructor<{
|
|
183
301
|
readonly email: FieldAt<Props<Repository>, "email">;
|
|
184
302
|
readonly password: typeof StringProperty;
|
|
185
|
-
}, EntityResponse<Repository, Options>, {
|
|
303
|
+
}, EntityResponse<Repository, Options> & TokenResponse<Options>, {
|
|
186
304
|
readonly repository: Repository;
|
|
187
305
|
}>;
|
|
306
|
+
/** `refresh`: exchanges a refresh token of `login` for new tokens; needs `findById`. */
|
|
307
|
+
export type RefreshMaker = <Repository extends AnyRepository>(repository: Repository & UseCaseTarget<Repository, "findById">, options: StdUseCaseOptions & {
|
|
308
|
+
readonly token: StdTokenOptions & {
|
|
309
|
+
readonly refresh: {
|
|
310
|
+
readonly expiresIn: number;
|
|
311
|
+
};
|
|
312
|
+
};
|
|
313
|
+
} & StdNoHookOptions) => StepsUseCaseConstructor<{
|
|
314
|
+
readonly refreshToken: typeof StringProperty;
|
|
315
|
+
}, {
|
|
316
|
+
readonly token: typeof StringProperty;
|
|
317
|
+
readonly refreshToken: typeof StringProperty;
|
|
318
|
+
}, {
|
|
319
|
+
readonly repository: Repository;
|
|
320
|
+
}>;
|
|
321
|
+
/** `logout`: gives empty tokens, which a route with `setCookie` turns into removed cookies. */
|
|
322
|
+
export type LogoutMaker = <Repository extends AnyRepository>(repository: Repository, options?: StdUseCaseOptions & StdNoHookOptions) => StepsUseCaseConstructor<Record<never, never>, {
|
|
323
|
+
readonly token: typeof StringProperty;
|
|
324
|
+
readonly refreshToken: typeof StringProperty;
|
|
325
|
+
}, Record<never, never>>;
|
|
188
326
|
/**
|
|
189
327
|
* The standard use cases, by name: what the `useCases` of `commandOf` gets
|
|
190
328
|
* to pick from, each called with a repository and its options.
|
|
@@ -204,9 +342,46 @@ export interface StdUseCaseContext {
|
|
|
204
342
|
readonly untag: TagMaker;
|
|
205
343
|
readonly register: RegisterMaker;
|
|
206
344
|
readonly login: LoginMaker;
|
|
345
|
+
readonly refresh: RefreshMaker;
|
|
346
|
+
readonly logout: LogoutMaker;
|
|
207
347
|
}
|
|
208
348
|
/** The plugins of `StdUseCases`, by name. */
|
|
209
349
|
export type StdUseCasePlugins = {
|
|
210
350
|
readonly [Name in keyof StdUseCaseContext]: IUseCasePlugin<Name, StdUseCaseContext[Name]>;
|
|
211
351
|
};
|
|
352
|
+
/** The operations `resourceOf` can give. */
|
|
353
|
+
export type ResourceAction = "create" | "get" | "list" | "update" | "delete";
|
|
354
|
+
/** The use cases of `resourceOf`, by operation: the standard ones, with no option but their route and access. */
|
|
355
|
+
export interface ResourceUseCases<Repository extends AnyRepository> {
|
|
356
|
+
readonly create: EntityUseCase<Repository, None, CreateInput<Repository, None>>;
|
|
357
|
+
readonly get: EntityUseCase<Repository, None, ById<Repository>>;
|
|
358
|
+
readonly list: StepsUseCaseConstructor<{
|
|
359
|
+
readonly limit: OptionalProperty<typeof Integer>;
|
|
360
|
+
readonly offset: OptionalProperty<typeof Integer>;
|
|
361
|
+
}, {
|
|
362
|
+
readonly items: IBlueprintList<EntityOf<Repository>>;
|
|
363
|
+
readonly total: typeof Integer;
|
|
364
|
+
readonly limit: typeof Integer;
|
|
365
|
+
readonly offset: typeof Integer;
|
|
366
|
+
}, {
|
|
367
|
+
readonly repository: Repository;
|
|
368
|
+
}>;
|
|
369
|
+
readonly update: EntityUseCase<Repository, None, UpdateInput<Repository>>;
|
|
370
|
+
readonly delete: EntityUseCase<Repository, None, ById<Repository>>;
|
|
371
|
+
}
|
|
372
|
+
/** The options of `resourceOf`. */
|
|
373
|
+
export interface ResourceOptions<Actions extends readonly ResourceAction[] = readonly ResourceAction[]> {
|
|
374
|
+
/** The path of the collection, e.g. `"/posts"`; one entity is at `{path}/{id}`. */
|
|
375
|
+
readonly path: string;
|
|
376
|
+
/** The operations to give; all five by default. Each needs its repository action. */
|
|
377
|
+
readonly actions?: Actions;
|
|
378
|
+
/**
|
|
379
|
+
* Who may call: one declaration for every operation, or one per operation
|
|
380
|
+
* (`{ create: { scopes: ["posts:write"] }, get: { public: true } }`; an
|
|
381
|
+
* operation left out declares none).
|
|
382
|
+
*/
|
|
383
|
+
readonly access?: AccessDeclaration | {
|
|
384
|
+
readonly [Action in ResourceAction]?: AccessDeclaration;
|
|
385
|
+
};
|
|
386
|
+
}
|
|
212
387
|
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Authenticator, HttpOptions, SinkStage } from "../adapters.js";
|
|
2
|
+
import type { ContractRunner } from "./provider-contract.js";
|
|
3
|
+
/** What the kit needs of a sink that serves HTTP. */
|
|
4
|
+
export interface HttpProviderContractSettings<Server> {
|
|
5
|
+
/** The sink under test, made with these options and this authenticator. */
|
|
6
|
+
sink(options: HttpOptions, hooks: {
|
|
7
|
+
readonly authenticator?: Authenticator;
|
|
8
|
+
}): SinkStage<Server, HttpOptions>;
|
|
9
|
+
/** Sends a request to the server the sink built, and gives its response. */
|
|
10
|
+
fetch(server: Server, request: Request): Response | Promise<Response>;
|
|
11
|
+
/** Releases the server (a listening socket), after each case. */
|
|
12
|
+
close?(server: Server): void | Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The cases every sink that serves HTTP must pass, whatever its server: the
|
|
16
|
+
* routes use cases declare, where each input key is read from, the context,
|
|
17
|
+
* access, statuses, problems, cookies, the request id and the document. A
|
|
18
|
+
* sink built on `compileRoutes` passes when it routes each method and path
|
|
19
|
+
* to `handle` and sends the result as is.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { describe, expect, it } from "bun:test";
|
|
23
|
+
* import { httpProviderContract } from "@afora/core/testing";
|
|
24
|
+
*
|
|
25
|
+
* httpProviderContract(
|
|
26
|
+
* "hono",
|
|
27
|
+
* { sink: (options, hooks) => hono(options, hooks), fetch: (app, request) => app.fetch(request) },
|
|
28
|
+
* { describe, it, expect },
|
|
29
|
+
* );
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function httpProviderContract<Server>(name: string, settings: HttpProviderContractSettings<Server>, runner: ContractRunner): void;
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
+
export type { HttpProviderContractSettings } from "./http-provider-contract.js";
|
|
2
|
+
export { httpProviderContract } from "./http-provider-contract.js";
|
|
3
|
+
export type { MemoryPublisher } from "./memory-publisher.js";
|
|
4
|
+
export { memoryPublisher } from "./memory-publisher.js";
|
|
1
5
|
export type { ContractRunner, ProviderContractOptions, } from "./provider-contract.js";
|
|
2
6
|
export { providerContract } from "./provider-contract.js";
|