@afora/core 0.0.5 → 0.0.7
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 +4 -1
- package/dist/core/application/types/application.interface.d.ts +56 -11
- package/dist/core/blueprint/types/slice.interface.d.ts +5 -2
- package/dist/core/command/command.d.ts +11 -4
- package/dist/core/command/types/command.interface.d.ts +19 -0
- package/dist/core/entity/abstract-entity.d.ts +1 -1
- package/dist/core/entity/types/entity.interface.d.ts +13 -7
- package/dist/core/exception/exception.d.ts +10 -1
- package/dist/core/output/status.d.ts +4 -3
- package/dist/core/property/input.d.ts +20 -0
- package/dist/core/property/property.d.ts +4 -4
- package/dist/core/property/types/optional-property.type.d.ts +2 -2
- package/dist/core/property/types/property-type.interface.d.ts +17 -0
- package/dist/core/record/abstract-record.d.ts +4 -4
- package/dist/core/record/exceptions.d.ts +2 -0
- package/dist/core/record/name.d.ts +16 -0
- package/dist/core/record/plugin.d.ts +6 -2
- package/dist/core/record/record.d.ts +4 -3
- package/dist/core/record/types/plugin.interface.d.ts +11 -0
- package/dist/core/record/types/record.interface.d.ts +71 -10
- package/dist/core/repository/cursor.d.ts +13 -0
- package/dist/core/repository/exceptions.d.ts +10 -0
- package/dist/core/repository/query.d.ts +4 -4
- package/dist/core/repository/repository.d.ts +2 -2
- package/dist/core/repository/state.d.ts +9 -0
- package/dist/core/repository/types/query.interface.d.ts +37 -0
- package/dist/core/repository/types/repository.interface.d.ts +17 -6
- package/dist/core/use-case/exceptions.d.ts +36 -0
- package/dist/core/use-case/plugin-catalog.d.ts +11 -0
- package/dist/core/use-case/plugin.d.ts +25 -0
- package/dist/core/use-case/steps/types/steps.interface.d.ts +24 -7
- package/dist/core/use-case/target.d.ts +9 -0
- package/dist/core/use-case/types/plugin.interface.d.ts +185 -0
- package/dist/experimental.js +4 -3
- package/dist/{index-8m80wjzf.js → index-q6hggpzw.js} +1210 -85
- package/dist/{index-hn82hm31.js → index-r78dsvtc.js} +136 -66
- package/dist/index.d.ts +22 -12
- package/dist/index.js +47 -5
- package/dist/std/command.d.ts +11 -0
- package/dist/std/properties/password.d.ts +21 -2
- package/dist/std/record-plugins.d.ts +5 -5
- package/dist/std/use-cases/auth.d.ts +5 -0
- package/dist/std/use-cases/crud.d.ts +23 -0
- package/dist/std/use-cases/index.d.ts +11 -0
- package/dist/std/use-cases/lifecycle.d.ts +13 -0
- package/dist/std/use-cases/shared.d.ts +60 -0
- package/dist/std/use-cases/types.d.ts +212 -0
- package/dist/testing/index.js +99 -2
- package/dist/testing/provider-contract.d.ts +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ afora is not a general-purpose validator. It is for code that models a domain, a
|
|
|
11
11
|
- **Exceptions that know their layer.** Each error carries a layer (`Property`, `Record`, `UseCase`, `Output`...) and a `trace` that grows as it goes up.
|
|
12
12
|
- **Standard Schema V1 on every field.** Properties, blueprints, lists and record classes work as is in Hono, tRPC and TanStack Form, and `safeParse` never throws for an invalid value.
|
|
13
13
|
- **Commands and outputs.** `commandOf` groups use cases behind one execution boundary (context, transactions, event policies); `outputOf` turns commands into operations and pipes them to a sink: an HTTP API with `@afora/hono`, an OpenAPI 3.1 document, or MCP tools, with problem+json errors and masked responses.
|
|
14
|
+
- **Standard use cases.** `commandOf({ useCases: (ctx) => ({ create: ctx.create(Posts), publish: ctx.publish(Posts) }) })` picks ready-made use cases that follow the repository and its entity: the actions it declares, its record plugins and the properties of its keys ([docs](docs/std-use-cases.md)).
|
|
14
15
|
- **The whole application in JSON.** An `afora.json` generates the code (`@afora/codegen`), use cases included, as data (steps), and `extractSpec(app)` gives back the `afora.json` of an application written by hand.
|
|
15
16
|
- **Repositories on any store.** A provider contract with typed queries, soft deletion and transactions, a runner-agnostic kit to test one (`@afora/core/testing`), in memory by default and on Drizzle ORM with `@afora/drizzle`.
|
|
16
17
|
|
|
@@ -304,7 +305,7 @@ Every field (a property, blueprint, list or record class) implements Standard Sc
|
|
|
304
305
|
|
|
305
306
|
## Example
|
|
306
307
|
|
|
307
|
-
`examples/blog` is a blog (users with the `authenticatable` plugin, posts with soft deletion, use
|
|
308
|
+
`examples/blog` is a blog (users with the `authenticatable` plugin, posts with soft deletion, every use case a [standard one](docs/std-use-cases.md), a Hono API on Drizzle and SQLite) whose whole `src/domain` is generated from one `afora.json` by `@afora/codegen`. Only the database, the schema, the provider (made from a `Database` environment with `providerFrom` when the server calls `App.start()`, and named `database` in the `providers` of the spec) and the server are hand-written. Its tests check that the committed code is what the spec generates, drive the API end to end and extract the spec back from the application: `bun run test:blog`.
|
|
308
309
|
|
|
309
310
|
## Performance
|
|
310
311
|
|
|
@@ -335,6 +336,8 @@ Where the others win: Zod and Valibot are faster, have far larger ecosystems and
|
|
|
335
336
|
|
|
336
337
|
## Contributing
|
|
337
338
|
|
|
339
|
+
Issues open from a template: bug report, feature request, or feedback from building on afora. Questions go to [Discussions](https://github.com/afora-framework/core/discussions). Pull requests follow [the PR template](.github/PULL_REQUEST_TEMPLATE.md).
|
|
340
|
+
|
|
338
341
|
Commits follow [Conventional Commits](https://www.conventionalcommits.org) (`feat(repository): …`, `fix: …`), checked by commitlint in a Husky `commit-msg` hook; the `pre-commit` hook runs Biome and Knip. CI runs lint, Knip, type checks, unit and interop tests, the build and the Node smoke test on every push and pull request. Pushing a `v*` tag that matches `package.json` publishes to npm with provenance.
|
|
339
342
|
|
|
340
343
|
Scripts:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AnyBlueprint, BlueprintInput, IBlueprint } from "../../blueprint/types/blueprint.interface.js";
|
|
1
2
|
import type { AnyCommand } from "../../command/types/command.interface.js";
|
|
2
3
|
import type { AnyEnvironment, EnvironmentValue } from "../../environment/environment.js";
|
|
3
4
|
import type { ExceptionLayers } from "../../exception/enums/exception-layers.js";
|
|
@@ -8,10 +9,32 @@ import type { ProviderDescription } from "../../repository/types/query.interface
|
|
|
8
9
|
import type { AnyRepository, IRepositoryProvider } from "../../repository/types/repository.interface.js";
|
|
9
10
|
import type { Kind } from "../../symbols/kind.js";
|
|
10
11
|
import type { UseCaseStepDescription } from "../../use-case/steps/types/steps.interface.js";
|
|
11
|
-
import type { AnyExceptionClass, AnyUseCaseClass } from "../../use-case/use-case.js";
|
|
12
|
+
import type { AnyExceptionClass, AnyUseCaseClass, UseCaseInput, UseCaseResponse } from "../../use-case/use-case.js";
|
|
12
13
|
import type { ProviderSlot, ProviderStorage } from "../providers.js";
|
|
13
14
|
import type { LogFactory, ProviderFactory } from "../start.js";
|
|
14
15
|
type Named<Value> = Readonly<Record<string, Value>>;
|
|
16
|
+
/**
|
|
17
|
+
* The options of `app.run`: the `context` of the use case, required when it
|
|
18
|
+
* declares one, and `dependencies`, what its `execute` takes to replace them.
|
|
19
|
+
*/
|
|
20
|
+
export type ApplicationRunOptions<UseCase extends AnyUseCaseClass> = (UseCase["context"] extends IBlueprint<infer Properties> ? {
|
|
21
|
+
readonly context: BlueprintInput<Properties>;
|
|
22
|
+
} : {
|
|
23
|
+
readonly context?: undefined;
|
|
24
|
+
}) & {
|
|
25
|
+
readonly dependencies?: Parameters<InstanceType<UseCase>["execute"]>[0];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* What `app.run` takes after the use case: its input, optional when no key
|
|
29
|
+
* of it is required, and the options, required when it declares a context.
|
|
30
|
+
*/
|
|
31
|
+
export type ApplicationRunArgs<UseCase extends AnyUseCaseClass> = UseCase["context"] extends AnyBlueprint ? [input: UseCaseInput<UseCase>, options: ApplicationRunOptions<UseCase>] : {} extends UseCaseInput<UseCase> ? [
|
|
32
|
+
input?: UseCaseInput<UseCase>,
|
|
33
|
+
options?: ApplicationRunOptions<UseCase>
|
|
34
|
+
] : [
|
|
35
|
+
input: UseCaseInput<UseCase>,
|
|
36
|
+
options?: ApplicationRunOptions<UseCase>
|
|
37
|
+
];
|
|
15
38
|
/** The declarations of an application, by name, one collection for each kind. */
|
|
16
39
|
export interface ApplicationCollections {
|
|
17
40
|
readonly properties: Named<unknown>;
|
|
@@ -115,25 +138,29 @@ export interface IApplication<Name extends string, Collections extends Applicati
|
|
|
115
138
|
readonly entities: Collections["entities"];
|
|
116
139
|
readonly environments: Collections["environments"];
|
|
117
140
|
/**
|
|
118
|
-
* Its repositories, inherited ones included. With a `provider`
|
|
119
|
-
* bound to it: they share the declaration of the
|
|
120
|
-
* write through that provider (unless they declared
|
|
141
|
+
* Its repositories, inherited ones included. With a `provider` (or
|
|
142
|
+
* `providers`) they are bound to it: they share the declaration of the
|
|
143
|
+
* original but read and write through that provider (unless they declared
|
|
144
|
+
* their own).
|
|
121
145
|
*/
|
|
122
146
|
readonly repositories: Collections["repositories"];
|
|
123
147
|
/**
|
|
124
|
-
* Its use cases. With a `provider` they are
|
|
125
|
-
* are the bound ones, through child use
|
|
126
|
-
* time. Without
|
|
148
|
+
* Its use cases. With a `provider`, `providers` or `log` they are
|
|
149
|
+
* subclasses whose repositories are the bound ones, through child use
|
|
150
|
+
* cases too; the same subclass every time. Without any of them they are
|
|
151
|
+
* the declared classes.
|
|
127
152
|
*/
|
|
128
153
|
readonly useCases: Collections["useCases"];
|
|
129
154
|
/**
|
|
130
|
-
* Its commands. With a `provider` they are rebuilt
|
|
131
|
-
* cases (same settings), memoized; without
|
|
155
|
+
* Its commands. With a `provider`, `providers` or `log` they are rebuilt
|
|
156
|
+
* over the bound use cases (same settings), memoized; without any of them,
|
|
157
|
+
* the declared commands.
|
|
132
158
|
*/
|
|
133
159
|
readonly commands: Collections["commands"];
|
|
134
160
|
/**
|
|
135
|
-
* Its outputs. With a `provider` they are rebuilt
|
|
136
|
-
* (same name, statuses and stages), memoized;
|
|
161
|
+
* Its outputs. With a `provider`, `providers` or `log` they are rebuilt
|
|
162
|
+
* over the bound commands (same name, statuses and stages), memoized;
|
|
163
|
+
* without any of them, the declared outputs.
|
|
137
164
|
*/
|
|
138
165
|
readonly outputs: Collections["outputs"];
|
|
139
166
|
/** Its exceptions. */
|
|
@@ -142,6 +169,13 @@ export interface IApplication<Name extends string, Collections extends Applicati
|
|
|
142
169
|
repository<Repository extends AnyRepository>(repository: Repository): Repository;
|
|
143
170
|
/** The bound version of a use case registered in the application. */
|
|
144
171
|
useCase<UseCase extends AnyUseCaseClass>(useCase: UseCase): UseCase;
|
|
172
|
+
/**
|
|
173
|
+
* Runs a use case registered in the application over its bound
|
|
174
|
+
* repositories: `new (app.useCase(UseCase))(input, { context }).execute(dependencies)`.
|
|
175
|
+
* It rejects with what the constructor or `execute` throw. The events the
|
|
176
|
+
* use case collected are not handled; a command is what dispatches them.
|
|
177
|
+
*/
|
|
178
|
+
run<UseCase extends AnyUseCaseClass>(useCase: UseCase, ...args: ApplicationRunArgs<UseCase>): Promise<UseCaseResponse<UseCase>>;
|
|
145
179
|
/** The bound version of a command registered in the application. */
|
|
146
180
|
command<Command extends AnyCommand>(command: Command): Command;
|
|
147
181
|
/** The bound version of an output registered in the application. */
|
|
@@ -306,6 +340,17 @@ export interface UseCaseDescription {
|
|
|
306
340
|
} | {
|
|
307
341
|
readonly kind: "opaque";
|
|
308
342
|
};
|
|
343
|
+
/**
|
|
344
|
+
* The use case plugin that made it, the registered repository it was made
|
|
345
|
+
* for and the options given, with classes by name as in the steps; absent
|
|
346
|
+
* for a use case declared by hand.
|
|
347
|
+
*/
|
|
348
|
+
readonly generic?: {
|
|
349
|
+
readonly name: string;
|
|
350
|
+
readonly version: string;
|
|
351
|
+
readonly repository: string;
|
|
352
|
+
readonly options: Readonly<Record<string, unknown>>;
|
|
353
|
+
};
|
|
309
354
|
}
|
|
310
355
|
/** A command: its metadata, context, operations and policies. */
|
|
311
356
|
export interface CommandDescription {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RecordUniqueKeys } from "../../record/types/plugin.interface.js";
|
|
1
|
+
import type { RecordSensitiveKeys, RecordUniqueKeys } from "../../record/types/plugin.interface.js";
|
|
2
2
|
import type { RecordConstructor } from "../../record/types/record.interface.js";
|
|
3
3
|
import type { Meta } from "../../symbols/meta.js";
|
|
4
4
|
import type { AnyBlueprint, AnyBlueprintList, AnyOptionalRecord, AnyRecordClass, BlueprintData, BlueprintField, IBlueprint, IBlueprintCollection, IBlueprintList, OptionalRecord } from "./blueprint.interface.js";
|
|
@@ -37,13 +37,16 @@ type SlicedRecord<Original extends AnyRecordClass, Mask> = SlicedProperties<Orig
|
|
|
37
37
|
readonly [Meta]: {
|
|
38
38
|
readonly blueprint: Original["blueprint"];
|
|
39
39
|
};
|
|
40
|
-
}
|
|
40
|
+
}, KeptSensitive<Original, keyof Properties>> : never;
|
|
41
41
|
type KeptChange<Instance, Keys> = Instance extends {
|
|
42
42
|
readonly change: infer Change;
|
|
43
43
|
} ? Extract<keyof Change, Keys & string> : never;
|
|
44
44
|
type KeptUnique<Original, Keys> = Original extends {
|
|
45
45
|
readonly [RecordUniqueKeys]?: infer Unique;
|
|
46
46
|
} ? Extract<Unique, Keys & string> : never;
|
|
47
|
+
type KeptSensitive<Original, Keys> = Original extends {
|
|
48
|
+
readonly [RecordSensitiveKeys]?: infer Sensitive;
|
|
49
|
+
} ? Extract<Sensitive, Keys & string> : never;
|
|
47
50
|
/** The properties of `Blueprint`, read lazily so generic uses stay shallow. */
|
|
48
51
|
export type PropertiesOf<Blueprint> = Blueprint extends IBlueprint<infer Properties, boolean> ? Properties : never;
|
|
49
52
|
/** The blueprint of `Properties` that keeps only the keys of `Mask`. */
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { IBlueprintCollection } from "../blueprint/types/blueprint.interface.js";
|
|
2
|
-
import { type EnvironmentDependencies } from "../environment/environment.js";
|
|
3
1
|
import type { IRepositoryProvider } from "../repository/types/repository.interface.js";
|
|
4
|
-
import type {
|
|
2
|
+
import type { IUseCaseCatalog, UseCasePluginContext } from "../use-case/types/plugin.interface.js";
|
|
3
|
+
import type { AnyCommand, CommandBuilder } from "./types/command.interface.js";
|
|
5
4
|
/**
|
|
6
5
|
* Checks now that the repositories of `command` share a provider that has
|
|
7
6
|
* `transaction`, as its first call would; an application calls it when it
|
|
@@ -15,11 +14,19 @@ export declare function verifyCommand(command: object): void;
|
|
|
15
14
|
* @internal
|
|
16
15
|
*/
|
|
17
16
|
export declare function commandTransactionProvider(command: object): IRepositoryProvider | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* A `commandOf` whose `useCases` may be a function of the use case plugins
|
|
19
|
+
* of `catalogs`, by name, a later catalog winning a name:
|
|
20
|
+
* `useCases: (ctx) => ({ create: ctx.create(Posts), custom: MyUseCase })`.
|
|
21
|
+
* Throws `InvalidCommandDeclaration` for what is not a catalog made by
|
|
22
|
+
* `useCaseCatalogOf`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function commandBuilderOf<const Catalogs extends readonly IUseCaseCatalog[] = []>(...catalogs: Catalogs): CommandBuilder<UseCasePluginContext<Catalogs>>;
|
|
18
25
|
/**
|
|
19
26
|
* Groups use cases under operation names and is the boundary of a call: the
|
|
20
27
|
* context is validated once, a transaction can wrap the use case, and the
|
|
21
28
|
* events it raised are handled by a policy once it succeeded.
|
|
22
29
|
*/
|
|
23
|
-
export declare
|
|
30
|
+
export declare const commandOf: CommandBuilder<Record<never, never>>;
|
|
24
31
|
/** Whether `value` is a command made by `commandOf`. */
|
|
25
32
|
export declare function isCommand(value: unknown): value is AnyCommand;
|
|
@@ -48,6 +48,25 @@ export interface CommandSettings<UseCases extends CommandUseCases, Context exten
|
|
|
48
48
|
readonly events?: CommandEvents;
|
|
49
49
|
readonly onEventError?: CommandEventErrorHandler;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* The `useCases` of a command made by a builder: the object, or a function
|
|
53
|
+
* of the use case plugins of its catalogs that gives it.
|
|
54
|
+
*/
|
|
55
|
+
export type CommandUseCasesOption<UseCases extends CommandUseCases, Generics> = UseCases | ((ctx: Generics) => UseCases);
|
|
56
|
+
/** `CommandSettings` with `useCases` as a builder takes it. */
|
|
57
|
+
export interface CommandBuilderSettings<UseCases extends CommandUseCases, Context extends IBlueprintCollection | undefined, Environment extends EnvironmentDependencies | undefined, Generics> extends Omit<CommandSettings<UseCases, Context, Environment>, "useCases"> {
|
|
58
|
+
/**
|
|
59
|
+
* The use cases, by operation name; or a function that gets the use
|
|
60
|
+
* case plugins of the builder's catalogs, each called with a repository,
|
|
61
|
+
* and gives them: `(ctx) => ({ create: ctx.create(Posts) })`.
|
|
62
|
+
*/
|
|
63
|
+
readonly useCases: CommandUseCasesOption<UseCases, Generics>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* What `commandBuilderOf` gives: `commandOf`, with the use case plugins
|
|
67
|
+
* `Generics` to pick from.
|
|
68
|
+
*/
|
|
69
|
+
export type CommandBuilder<Generics> = <const UseCases extends CommandUseCases, Context extends IBlueprintCollection | undefined = undefined, Environment extends EnvironmentDependencies | undefined = undefined>(settings: CommandBuilderSettings<UseCases, Context, Environment, Generics>) => CommandOf<UseCases, Context, Environment>;
|
|
51
70
|
/** The names of the operations of a command. */
|
|
52
71
|
export type CommandOperation<Command extends {
|
|
53
72
|
readonly useCases: object;
|
|
@@ -17,7 +17,7 @@ export declare const EntityUniqueKeys: unique symbol;
|
|
|
17
17
|
* and never changed after, an `updatedAt` set by each change, and a
|
|
18
18
|
* `deletedAt` set by `destroy`, after which it no longer changes.
|
|
19
19
|
*/
|
|
20
|
-
export declare abstract class AbstractEntity<Properties extends IBlueprintCollection> extends AbstractRecord<Properties> {
|
|
20
|
+
export declare abstract class AbstractEntity<Properties extends IBlueprintCollection, Sensitive extends string = never> extends AbstractRecord<Properties, Sensitive> {
|
|
21
21
|
constructor(value: BlueprintInput<Properties>);
|
|
22
22
|
/** Queues an event for this entity without running its handler. */
|
|
23
23
|
protected emit(event: EventDefinition): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BlueprintField, BlueprintInput, BlueprintValue, IBlueprint, IBlueprintCollection, JoinedProperties } from "../../blueprint/types/blueprint.interface.js";
|
|
2
2
|
import type { ParseResult } from "../../parse/types/parse.interface.js";
|
|
3
|
-
import type { AnyRecordPlugin, IRecordPluginCatalog, PluginMembers, PluginUniqueKey, WithPluginProperties } from "../../record/types/plugin.interface.js";
|
|
3
|
+
import type { AnyRecordPlugin, IRecordPluginCatalog, PluginMembers, PluginSensitiveKey, PluginUniqueKey, WithPluginProperties } from "../../record/types/plugin.interface.js";
|
|
4
4
|
import type { MarkedUniqueKey, RecordChanges, RecordKey, RecordOptions, RecordSettings } from "../../record/types/record.interface.js";
|
|
5
5
|
import type { StandardSchemaV1 } from "../../standard/standard-schema.js";
|
|
6
6
|
import type { Kind } from "../../symbols/kind.js";
|
|
@@ -45,32 +45,38 @@ export type EntityProperties<Identity extends IEntityIdentity, Properties extend
|
|
|
45
45
|
*/
|
|
46
46
|
export type EntityInput<Identity extends IEntityIdentity, Properties extends IBlueprintCollection> = BlueprintInput<Properties> & Partial<BlueprintInput<Identity>>;
|
|
47
47
|
/** What `entityOf` takes, after the blueprint, to describe its keys. */
|
|
48
|
-
export type EntityOptions<Properties extends IBlueprintCollection, Change extends readonly RecordKey<Properties>[] = readonly RecordKey<Properties>[], Unique extends readonly RecordKey<Properties>[] = readonly RecordKey<Properties>[], Plugins extends readonly AnyRecordPlugin[] = readonly AnyRecordPlugin[], Context = unknown> = RecordOptions<Properties, Change, Unique, Plugins, Context> & EntityEvents;
|
|
48
|
+
export type EntityOptions<Properties extends IBlueprintCollection, Change extends readonly RecordKey<Properties>[] = readonly RecordKey<Properties>[], Unique extends readonly RecordKey<Properties>[] = readonly RecordKey<Properties>[], Plugins extends readonly AnyRecordPlugin[] = readonly AnyRecordPlugin[], Context = unknown, Sensitive extends readonly RecordKey<Properties>[] = readonly RecordKey<Properties>[]> = RecordOptions<Properties, Change, Unique, Plugins, Context, Sensitive> & EntityEvents;
|
|
49
49
|
/**
|
|
50
50
|
* The unique keys of an entity: `id`, those listed in `options.unique`, and
|
|
51
51
|
* those holding a property declared `unique`, as `Slug`.
|
|
52
52
|
*/
|
|
53
53
|
export type EntityUniqueKey<Identity extends IEntityIdentity, Properties extends IBlueprintCollection, Unique extends readonly string[]> = "id" | Unique[number] | MarkedUniqueKey<EntityProperties<Identity, Properties>>;
|
|
54
54
|
/** The entities of the class `entityOf` returns, with what its plugins add, `Members`. */
|
|
55
|
-
export type DeclaredEntityInstance<Identity extends IEntityIdentity, Properties extends IBlueprintCollection, Change extends readonly string[], Members = unknown> = AbstractEntity<EntityProperties<Identity, Properties
|
|
55
|
+
export type DeclaredEntityInstance<Identity extends IEntityIdentity, Properties extends IBlueprintCollection, Change extends readonly string[], Members = unknown, Sensitive extends string = never> = AbstractEntity<EntityProperties<Identity, Properties>, Sensitive> & Readonly<BlueprintValue<EntityProperties<Identity, Properties>>> & RecordChanges<Properties, Change> & Members;
|
|
56
56
|
/** What `entityOf` returns: a record class with identity. */
|
|
57
|
-
export type EntityConstructor<Identity extends IEntityIdentity, Properties extends IBlueprintCollection, Change extends readonly string[], Unique extends readonly string[] = [], Members = unknown> = {
|
|
57
|
+
export type EntityConstructor<Identity extends IEntityIdentity, Properties extends IBlueprintCollection, Change extends readonly string[], Unique extends readonly string[] = [], Members = unknown, Sensitive extends string = never> = {
|
|
58
58
|
readonly [EntityClassBrand]: true;
|
|
59
59
|
/** The keys no two entities may share, as `options.unique` lists them. */
|
|
60
60
|
readonly [EntityUniqueKeys]: readonly EntityUniqueKey<Identity, Properties, Unique>[];
|
|
61
|
-
new (value: EntityInput<Identity, Properties>): DeclaredEntityInstance<Identity, Properties, Change, Members>;
|
|
61
|
+
new (value: EntityInput<Identity, Properties>): DeclaredEntityInstance<Identity, Properties, Change, Members, Sensitive>;
|
|
62
62
|
/**
|
|
63
63
|
* The Standard Schema of the class: `validate` gives an instance of it, or
|
|
64
64
|
* the issues that reject the value. Typed with the instance of the class
|
|
65
65
|
* `entityOf` returns, not of a subclass.
|
|
66
66
|
*/
|
|
67
|
-
readonly "~standard": StandardSchemaV1.Props<EntityInput<Identity, Properties>, DeclaredEntityInstance<Identity, Properties, Change, Members>>;
|
|
67
|
+
readonly "~standard": StandardSchemaV1.Props<EntityInput<Identity, Properties>, DeclaredEntityInstance<Identity, Properties, Change, Members, Sensitive>>;
|
|
68
68
|
/**
|
|
69
69
|
* An instance of the class (a subclass included) for `value`, or every
|
|
70
70
|
* issue that rejects it; never throws for an invalid value.
|
|
71
71
|
*/
|
|
72
72
|
safeParse<Self extends new (value: never) => object>(this: Self, value: unknown): ParseResult<InstanceType<Self>>;
|
|
73
73
|
readonly [Kind]: "record";
|
|
74
|
+
/**
|
|
75
|
+
* The name of the class as declared: the `name` option, which a bundler
|
|
76
|
+
* does not rename, or the name of the class without one. A subclass may
|
|
77
|
+
* give its own with `static override readonly recordName = "..."`.
|
|
78
|
+
*/
|
|
79
|
+
readonly recordName: string;
|
|
74
80
|
readonly blueprint: IBlueprint<EntityProperties<Identity, Properties>>;
|
|
75
81
|
readonly options: RecordSettings<EntityProperties<Identity, Properties>>;
|
|
76
82
|
/** Its plugins, those they require included, each once. */
|
|
@@ -80,4 +86,4 @@ export type EntityConstructor<Identity extends IEntityIdentity, Properties exten
|
|
|
80
86
|
* What `entityBuilderOf` returns: `entityOf`, declaring entities with the
|
|
81
87
|
* identity it was given, whose `options.plugins` picks from `Context`.
|
|
82
88
|
*/
|
|
83
|
-
export type EntityBuilder<Identity extends IEntityIdentity, Context = Record<never, never>> = <Properties extends IBlueprintCollection & Partial<Record<EntityIdentityKey, never>>, const Change extends readonly RecordKey<Properties>[] = [], const Unique extends readonly RecordKey<Properties>[] = [], const Plugins extends readonly AnyRecordPlugin[] = []>(blueprint: IBlueprint<Properties, boolean>, options?: EntityOptions<NoInfer<Properties>, Change, Unique, Plugins, Context>) => EntityConstructor<Identity, WithPluginProperties<Properties, Plugins>, Change, readonly (Unique[number] | PluginUniqueKey<Plugins>)[], PluginMembers<Plugins>>;
|
|
89
|
+
export type EntityBuilder<Identity extends IEntityIdentity, Context = Record<never, never>> = <Properties extends IBlueprintCollection & Partial<Record<EntityIdentityKey, never>>, const Change extends readonly RecordKey<Properties>[] = [], const Unique extends readonly RecordKey<Properties>[] = [], const Plugins extends readonly AnyRecordPlugin[] = [], const Sensitive extends readonly RecordKey<Properties>[] = []>(blueprint: IBlueprint<Properties, boolean>, options?: EntityOptions<NoInfer<Properties>, Change, Unique, Plugins, Context, Sensitive>) => EntityConstructor<Identity, WithPluginProperties<Properties, Plugins>, Change, readonly (Unique[number] | PluginUniqueKey<Plugins>)[], PluginMembers<Plugins>, Sensitive[number] | PluginSensitiveKey<Plugins>>;
|
|
@@ -31,8 +31,17 @@ export declare class Exception<Details = unknown> extends Error {
|
|
|
31
31
|
/**
|
|
32
32
|
* Passes the exception to an upper layer: a new exception in `scope`, with
|
|
33
33
|
* this one as its cause, keeping its name and message unless given others.
|
|
34
|
+
* With the same name and no new `details`, an exception of a class declared
|
|
35
|
+
* with `exceptionOf` (or of a subclass of one) stays an instance of that
|
|
36
|
+
* class and keeps its `details`, so `instanceof` holds across layers; the
|
|
37
|
+
* constructor of the class does not run again.
|
|
34
38
|
*/
|
|
35
|
-
propagate
|
|
39
|
+
propagate(scope: ExceptionScope & {
|
|
40
|
+
readonly name?: undefined;
|
|
41
|
+
readonly message?: string;
|
|
42
|
+
readonly details?: undefined;
|
|
43
|
+
}): Exception<Details>;
|
|
44
|
+
propagate<Next = undefined>(scope: ExceptionPropagation<Next>): Exception<Next>;
|
|
36
45
|
toJSON(): ExceptionFrame<Details> & {
|
|
37
46
|
trace: readonly ExceptionFrame[];
|
|
38
47
|
};
|
|
@@ -2,15 +2,16 @@ import { Exception } from "../exception/exception.js";
|
|
|
2
2
|
import type { OperationDescriptor, OutputStatuses } from "./types/output.interface.js";
|
|
3
3
|
/**
|
|
4
4
|
* The exception that raised `error` under its name: a use case or a command
|
|
5
|
-
* passes an exception up as a copy with the same name
|
|
6
|
-
*
|
|
5
|
+
* passes an exception up as a copy with the same name and the original as
|
|
6
|
+
* its cause, so the original is the deepest one with that name.
|
|
7
7
|
*/
|
|
8
8
|
export declare function raisedOf(error: Exception): Exception;
|
|
9
9
|
/**
|
|
10
10
|
* The HTTP-style status of an error, in this order: `statuses` by exception
|
|
11
11
|
* name; 400 for invalid input or context (and any exception whose
|
|
12
12
|
* `details.issues` is a list, except `InvalidCommandEnvironment`, a 500); 404 for a missing entity or operation; 409 for
|
|
13
|
-
* a unique violation
|
|
13
|
+
* a unique violation or an entity that already exists; 401 for
|
|
14
|
+
* `UseCaseInvalidCredentials`; 422 for a class in `operation.errors`; 500 for the
|
|
14
15
|
* rest, errors that are not exceptions included. Exceptions match by name,
|
|
15
16
|
* or by class for `operation.errors`.
|
|
16
17
|
*/
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AnyPropertyConstructor } from "./types/property-collection.type.js";
|
|
2
|
+
/**
|
|
3
|
+
* The static of a property class whose callers give another form of its
|
|
4
|
+
* value than the one it stores: a password is given plain and stored as a
|
|
5
|
+
* hash. Classes extending or refining the property keep it.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PropertyInput: unique symbol;
|
|
8
|
+
/** What a property class holds under `PropertyInput`. */
|
|
9
|
+
export interface IPropertyInput<Value = unknown> {
|
|
10
|
+
/** The property that validates what a caller gives, of the same value type. */
|
|
11
|
+
readonly accepts: AnyPropertyConstructor;
|
|
12
|
+
/** Turns what a caller gave into the value the property stores. */
|
|
13
|
+
convert(value: Value): Value | Promise<Value>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* What `field` declares under `PropertyInput`; `undefined` for a property
|
|
17
|
+
* that takes its value as it stores it, and for a field that is not a
|
|
18
|
+
* property.
|
|
19
|
+
*/
|
|
20
|
+
export declare function propertyInputOf(field: unknown): IPropertyInput | undefined;
|
|
@@ -6,20 +6,20 @@ import { AbstractDefineProperty } from "./define-property.js";
|
|
|
6
6
|
import type { AnyPropertyConstructor } from "./types/property-collection.type.js";
|
|
7
7
|
import type { PropertyValue } from "./types/property-constructor.type.js";
|
|
8
8
|
import type { PropertyOptions } from "./types/property-options.interface.js";
|
|
9
|
-
import type { IPropertyType, UniqueMark } from "./types/property-type.interface.js";
|
|
9
|
+
import type { IPropertyType, SensitiveMark, UniqueMark } from "./types/property-type.interface.js";
|
|
10
10
|
type SchemaValueType<SchemaType extends TSchema, Optional extends boolean = false> = Optional extends true ? TOptional<SchemaType> : SchemaType;
|
|
11
11
|
/**
|
|
12
12
|
* What `propertyOf` takes. `SchemaType` is inferred from `schema` alone: the
|
|
13
13
|
* value is `NoInfer`, since inferring through `Static` makes TypeScript
|
|
14
14
|
* measure `Static` itself, which costs about a second on every check.
|
|
15
15
|
*/
|
|
16
|
-
type PropertyOfArgs<SchemaType extends TSchema, Optional extends boolean = false, Unique extends boolean = false, Value = Static<SchemaType>> = {
|
|
16
|
+
type PropertyOfArgs<SchemaType extends TSchema, Optional extends boolean = false, Unique extends boolean = false, Sensitive extends boolean = false, Value = Static<SchemaType>> = {
|
|
17
17
|
name: string;
|
|
18
18
|
schema: SchemaType;
|
|
19
19
|
default?: NoInfer<Value>;
|
|
20
20
|
optional?: Optional;
|
|
21
21
|
/** A record masks its value in `toJSON`, at any depth, as `Password`. */
|
|
22
|
-
sensitive?:
|
|
22
|
+
sensitive?: Sensitive;
|
|
23
23
|
/**
|
|
24
24
|
* A record lists a key holding it in `options.unique`, as `Slug`; records
|
|
25
25
|
* do not check it, repositories (or the database) enforce it.
|
|
@@ -53,5 +53,5 @@ export interface PropertyClass<SchemaType extends TSchema, Value = Static<Schema
|
|
|
53
53
|
with<Self extends AnyPropertyConstructor>(this: Self, options: PropertyOptions<SchemaType, Value>): Self;
|
|
54
54
|
demo<Self extends AbstractProperty<any>>(this: new (value: never) => Self): Self;
|
|
55
55
|
}
|
|
56
|
-
export declare function propertyOf<SchemaType extends TSchema, Optional extends boolean = false, const Unique extends boolean = false>({ name, schema, optional, sensitive, unique, default: _default, preHandle: onPreHandle, afterHandle: onAfterHandle, }: PropertyOfArgs<SchemaType, Optional, Unique>): PropertyClass<SchemaValueType<SchemaType, Optional>, Static<SchemaType>> & UniqueMark<Unique>;
|
|
56
|
+
export declare function propertyOf<SchemaType extends TSchema, Optional extends boolean = false, const Unique extends boolean = false, const Sensitive extends boolean = false>({ name, schema, optional, sensitive, unique, default: _default, preHandle: onPreHandle, afterHandle: onAfterHandle, }: PropertyOfArgs<SchemaType, Optional, Unique, Sensitive>): PropertyClass<SchemaValueType<SchemaType, Optional>, Static<SchemaType>> & UniqueMark<Unique> & SensitiveMark<Sensitive>;
|
|
57
57
|
export {};
|
|
@@ -5,7 +5,7 @@ import type { AbstractProperty } from "../abstract-property.js";
|
|
|
5
5
|
import type { AnyPropertyConstructor } from "./property-collection.type.js";
|
|
6
6
|
import type { PropertyValue } from "./property-constructor.type.js";
|
|
7
7
|
import type { CallableKey, StoredField } from "./property-options.interface.js";
|
|
8
|
-
import type { IPropertyType, UniqueTypeOf } from "./property-type.interface.js";
|
|
8
|
+
import type { IPropertyType, SensitiveTypeOf, UniqueTypeOf } from "./property-type.interface.js";
|
|
9
9
|
/**
|
|
10
10
|
* `Property` accepting `undefined`: its schema becomes `TOptional`, while its
|
|
11
11
|
* own methods and statics (e.g. `Password#verify`, `Id.generate`) are kept.
|
|
@@ -14,7 +14,7 @@ export type OptionalProperty<Property extends AnyPropertyConstructor> = Property
|
|
|
14
14
|
readonly type: IPropertyType<infer SchemaType, infer Value>;
|
|
15
15
|
} ? SchemaType extends TOptional<TSchema> ? StoredField<Property> : Omit<Property, "type" | "prototype" | "safeParse" | "~standard" | CallableKey> & {
|
|
16
16
|
new (value: PropertyValue<TOptional<SchemaType>, Value>): AbstractProperty<TOptional<SchemaType>, Value> & Omit<InstanceType<Property>, keyof AbstractProperty<TSchema>>;
|
|
17
|
-
readonly type: IPropertyType<TOptional<SchemaType>, Value> & UniqueTypeOf<Property>;
|
|
17
|
+
readonly type: IPropertyType<TOptional<SchemaType>, Value> & UniqueTypeOf<Property> & SensitiveTypeOf<Property>;
|
|
18
18
|
safeParse(value: unknown): ParseResult<PropertyValue<TOptional<SchemaType>, Value>>;
|
|
19
19
|
readonly "~standard": StandardSchemaV1.Props<PropertyValue<TOptional<SchemaType>, Value>, PropertyValue<TOptional<SchemaType>, Value>>;
|
|
20
20
|
} : never;
|
|
@@ -25,6 +25,23 @@ export type UniqueMark<Unique extends boolean> = Unique extends true ? {
|
|
|
25
25
|
readonly unique: true;
|
|
26
26
|
};
|
|
27
27
|
} : unknown;
|
|
28
|
+
/**
|
|
29
|
+
* The type of a property declared `sensitive`, as `Password`, so that the
|
|
30
|
+
* type of `toJSON` masks the keys holding it.
|
|
31
|
+
*/
|
|
32
|
+
export type SensitiveMark<Sensitive extends boolean> = Sensitive extends true ? {
|
|
33
|
+
readonly type: {
|
|
34
|
+
readonly sensitive: true;
|
|
35
|
+
};
|
|
36
|
+
} : unknown;
|
|
37
|
+
/** `{ sensitive: true }` when `Property` is declared `sensitive`, for its optional version. */
|
|
38
|
+
export type SensitiveTypeOf<Property> = Property extends {
|
|
39
|
+
readonly type: {
|
|
40
|
+
readonly sensitive: true;
|
|
41
|
+
};
|
|
42
|
+
} ? {
|
|
43
|
+
readonly sensitive: true;
|
|
44
|
+
} : unknown;
|
|
28
45
|
/** `{ unique: true }` when `Property` is declared `unique`, for its optional version. */
|
|
29
46
|
export type UniqueTypeOf<Property> = Property extends {
|
|
30
47
|
readonly type: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BlueprintField, BlueprintInput, BlueprintValue, IBlueprint, IBlueprintCollection } from "../blueprint/types/blueprint.interface.js";
|
|
2
2
|
import type { ParseResult } from "../parse/types/parse.interface.js";
|
|
3
3
|
import type { StandardSchemaV1 } from "../standard/standard-schema.js";
|
|
4
4
|
import { Meta } from "../symbols/meta.js";
|
|
5
|
-
import type { IRecord, RecordChange, RecordEffects, RecordSettings } from "./types/record.interface.js";
|
|
5
|
+
import type { IRecord, RecordChange, RecordEffects, RecordJson, RecordSettings } from "./types/record.interface.js";
|
|
6
6
|
/** The statics of a class made by `recordOf`, that its records read. */
|
|
7
7
|
interface RecordDeclaration<Properties extends IBlueprintCollection> {
|
|
8
8
|
readonly blueprint: IBlueprint<Properties>;
|
|
@@ -54,7 +54,7 @@ export declare const RecordPluginHooks: unique symbol;
|
|
|
54
54
|
* having `key`, then those of the record, for a stored change.
|
|
55
55
|
*/
|
|
56
56
|
export declare function runRecordEffects<Self extends object>(record: Self, key: PropertyKey, next: unknown, previous: unknown): Self;
|
|
57
|
-
export declare abstract class AbstractRecord<Properties extends IBlueprintCollection> implements IRecord<Properties> {
|
|
57
|
+
export declare abstract class AbstractRecord<Properties extends IBlueprintCollection, Sensitive extends string = never> implements IRecord<Properties, Sensitive> {
|
|
58
58
|
get [Meta](): RecordDeclaration<Properties>;
|
|
59
59
|
constructor(value: BlueprintInput<Properties>);
|
|
60
60
|
/**
|
|
@@ -72,7 +72,7 @@ export declare abstract class AbstractRecord<Properties extends IBlueprintCollec
|
|
|
72
72
|
* The value with the sensitive keys, and every property declared
|
|
73
73
|
* `sensitive` (as `Password`), masked.
|
|
74
74
|
*/
|
|
75
|
-
toJSON():
|
|
75
|
+
toJSON(): RecordJson<Properties, Sensitive>;
|
|
76
76
|
/**
|
|
77
77
|
* Validates `value`, stores it under `key`, then runs `onSetAll` and the
|
|
78
78
|
* effect of `key` in `onSet`.
|
|
@@ -9,6 +9,8 @@ export declare const InvalidRecordValue: import("../../index.js").DeclaredExcept
|
|
|
9
9
|
readonly errors: readonly string[];
|
|
10
10
|
readonly issues: readonly Issue[];
|
|
11
11
|
}>;
|
|
12
|
+
/** `recordOf` or `entityOf` got an option it cannot use, as a `name` that is not an identifier. */
|
|
13
|
+
export declare const InvalidRecordDeclaration: import("../../index.js").DeclaredExceptionClass<string>;
|
|
12
14
|
/**
|
|
13
15
|
* A record is given a key its blueprint does not declare, in its value or by
|
|
14
16
|
* `set`; `key` is its path, e.g. `address.extra`, and `source` the record name.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Whether `name` can be the `name` option of `recordOf` or `entityOf`. */
|
|
2
|
+
export declare function isRecordName(name: unknown): name is string;
|
|
3
|
+
/**
|
|
4
|
+
* The name of a record or entity class: the `name` option it, or the class it
|
|
5
|
+
* extends, was declared with, which bundlers and minifiers do not change;
|
|
6
|
+
* without one, the name of the class.
|
|
7
|
+
*/
|
|
8
|
+
export declare function recordNameOf(Class: object): string;
|
|
9
|
+
/** Keeps the `name` option `Class` was declared with. */
|
|
10
|
+
export declare function declareRecordName(Class: object, name: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* The name `Class` declares: the `name` option of it or of a class it
|
|
13
|
+
* extends, or a `static recordName` of its own; `undefined` when the name of
|
|
14
|
+
* the record is only the name of its class.
|
|
15
|
+
*/
|
|
16
|
+
export declare function declaredRecordNameOf(Class: object): string | undefined;
|
|
@@ -9,8 +9,12 @@ export declare const RecordPlugins: unique symbol;
|
|
|
9
9
|
export declare const IdentifiedRecord: unique symbol;
|
|
10
10
|
/** Whether `version` is a semantic version. */
|
|
11
11
|
export declare function isVersion(version: unknown): version is string;
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Whether a plugin of version `available` satisfies a reference to
|
|
14
|
+
* `requested`: the same major version (the same minor below `1.0.0`), and
|
|
15
|
+
* not older.
|
|
16
|
+
*/
|
|
17
|
+
export declare function satisfies(available: string, requested: string): boolean;
|
|
14
18
|
/** The `onSet` and `onSetAll` a plugin runs, for changes to its `keys`. */
|
|
15
19
|
interface RecordPluginHook {
|
|
16
20
|
readonly plugin: AnyRecordPlugin;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { AnyBlueprint, IBlueprint, IBlueprintCollection } from "../blueprint/types/blueprint.interface.js";
|
|
2
2
|
import { AbstractRecord } from "./abstract-record.js";
|
|
3
|
-
import type { AnyRecordPlugin, IRecordPluginCatalog, PluginMembers, PluginUniqueKey, RecordPluginContext, WithPluginProperties } from "./types/plugin.interface.js";
|
|
3
|
+
import type { AnyRecordPlugin, IRecordPluginCatalog, PluginMembers, PluginSensitiveKey, PluginUniqueKey, RecordPluginContext, WithPluginProperties } from "./types/plugin.interface.js";
|
|
4
4
|
import type { RecordConstructor, RecordKey, RecordOptions } from "./types/record.interface.js";
|
|
5
5
|
/**
|
|
6
6
|
* What `recordBuilderOf` returns: `recordOf`, whose `options.plugins` can
|
|
7
7
|
* pick plugins from `Context`, the plugins of its catalogs by name.
|
|
8
8
|
*/
|
|
9
|
-
export type RecordBuilder<Context> = <Properties extends IBlueprintCollection, const Change extends readonly RecordKey<Properties>[] = [], const Unique extends readonly RecordKey<Properties>[] = [], const Plugins extends readonly AnyRecordPlugin[] = []>(blueprint: IBlueprint<Properties, boolean>, options?: RecordOptions<NoInfer<Properties>, Change, Unique, Plugins, Context>) => RecordConstructor<WithPluginProperties<Properties, Plugins>, Change, Unique[number] | PluginUniqueKey<Plugins>, PluginMembers<Plugins>>;
|
|
9
|
+
export type RecordBuilder<Context> = <Properties extends IBlueprintCollection, const Change extends readonly RecordKey<Properties>[] = [], const Unique extends readonly RecordKey<Properties>[] = [], const Plugins extends readonly AnyRecordPlugin[] = [], const Sensitive extends readonly RecordKey<Properties>[] = []>(blueprint: IBlueprint<Properties, boolean>, options?: RecordOptions<NoInfer<Properties>, Change, Unique, Plugins, Context, Sensitive>) => RecordConstructor<WithPluginProperties<Properties, Plugins>, Change, Unique[number] | PluginUniqueKey<Plugins>, PluginMembers<Plugins>, never, Sensitive[number] | PluginSensitiveKey<Plugins>>;
|
|
10
10
|
/**
|
|
11
11
|
* A `recordOf` whose `options.plugins` can pick plugins from `catalogs`,
|
|
12
12
|
* e.g. `recordBuilderOf(StdRecordPlugins)`, as `(ctx) => [ctx.publishable]`;
|
|
@@ -27,6 +27,7 @@ export declare function pluginContextOf(catalogs: readonly IRecordPluginCatalog[
|
|
|
27
27
|
export declare const recordOf: RecordBuilder<Record<never, never>>;
|
|
28
28
|
/** The options `declareRecord` takes, untyped. */
|
|
29
29
|
interface RecordOptionsInput {
|
|
30
|
+
readonly name?: string;
|
|
30
31
|
readonly sensitive?: readonly string[];
|
|
31
32
|
readonly unique?: readonly string[];
|
|
32
33
|
readonly change?: readonly string[];
|
|
@@ -37,5 +38,5 @@ interface RecordOptionsInput {
|
|
|
37
38
|
* and named `name`; `reserved` are more names no key can take, the members
|
|
38
39
|
* `Base` adds, and `context` the plugins `options.plugins` can pick from.
|
|
39
40
|
*/
|
|
40
|
-
export declare function declareRecord(Base: abstract new (value: never) => AbstractRecord<IBlueprintCollection>, declared: AnyBlueprint, { plugins, ...declaredOptions }: RecordOptionsInput,
|
|
41
|
+
export declare function declareRecord(Base: abstract new (value: never) => AbstractRecord<IBlueprintCollection>, declared: AnyBlueprint, { plugins, name: declaredName, ...declaredOptions }: RecordOptionsInput, fallback: string, reserved?: readonly string[], context?: Readonly<Record<string, AnyRecordPlugin>>): abstract new (value: never) => AbstractRecord<IBlueprintCollection>;
|
|
41
42
|
export {};
|
|
@@ -7,6 +7,11 @@ import type { RecordSettings } from "./record.interface.js";
|
|
|
7
7
|
* class holds a value under it.
|
|
8
8
|
*/
|
|
9
9
|
export declare const RecordUniqueKeys: unique symbol;
|
|
10
|
+
/**
|
|
11
|
+
* Where the type of the keys a record class lists in `options.sensitive` is
|
|
12
|
+
* kept, for the type of `toJSON` of what its plugin is applied to. Type only.
|
|
13
|
+
*/
|
|
14
|
+
export declare const RecordSensitiveKeys: unique symbol;
|
|
10
15
|
/** What `recordPluginOf` takes, after the record class. */
|
|
11
16
|
export interface RecordPluginOptions {
|
|
12
17
|
/** A semantic version, e.g. `1.2.0`; `1.0.0` when left out. */
|
|
@@ -139,4 +144,10 @@ export type PluginUniqueKey<Plugins extends readonly AnyRecordPlugin[]> = Plugin
|
|
|
139
144
|
readonly [RecordUniqueKeys]?: infer Key;
|
|
140
145
|
};
|
|
141
146
|
} ? Extract<Key, string> : never : never;
|
|
147
|
+
/** The keys the record classes of the plugins list in `options.sensitive`. */
|
|
148
|
+
export type PluginSensitiveKey<Plugins extends readonly AnyRecordPlugin[]> = Plugins[number] extends infer Plugin ? Plugin extends {
|
|
149
|
+
readonly record: {
|
|
150
|
+
readonly [RecordSensitiveKeys]?: infer Key;
|
|
151
|
+
};
|
|
152
|
+
} ? Extract<Key, string> : never : never;
|
|
142
153
|
export {};
|