@afora/core 0.0.4 → 0.0.6
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 +2 -0
- package/dist/core/application/exceptions.d.ts +9 -0
- package/dist/core/application/providers.d.ts +46 -0
- package/dist/core/application/types/application.interface.d.ts +70 -15
- package/dist/core/blueprint/types/slice.interface.d.ts +5 -2
- 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 +2 -2
- 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/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 +1 -1
- package/dist/core/repository/state.d.ts +3 -2
- package/dist/core/repository/types/query.interface.d.ts +37 -0
- package/dist/core/repository/types/repository.interface.d.ts +10 -6
- package/dist/core/use-case/steps/types/steps.interface.d.ts +1 -1
- package/dist/experimental.js +3 -2
- package/dist/{index-hn82hm31.js → index-3nd9bjnc.js} +69 -10
- package/dist/{index-ewm6r4nw.js → index-gbgc40xe.js} +452 -96
- package/dist/index.d.ts +9 -7
- package/dist/index.js +16 -2
- package/dist/std/properties/password.d.ts +5 -1
- package/dist/std/record-plugins.d.ts +5 -5
- package/dist/testing/index.js +91 -2
- package/dist/testing/provider-contract.d.ts +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -335,6 +335,8 @@ Where the others win: Zod and Valibot are faster, have far larger ecosystems and
|
|
|
335
335
|
|
|
336
336
|
## Contributing
|
|
337
337
|
|
|
338
|
+
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).
|
|
339
|
+
|
|
338
340
|
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
341
|
|
|
340
342
|
Scripts:
|
|
@@ -40,6 +40,15 @@ export declare const ApplicationNotStarted: import("../../index.js").DeclaredExc
|
|
|
40
40
|
/** The application, or none when `useApplication()` found none started. */
|
|
41
41
|
readonly application?: string;
|
|
42
42
|
}>;
|
|
43
|
+
/**
|
|
44
|
+
* A repository read or wrote through a provider of `providersOf` made by
|
|
45
|
+
* `providerFrom` outside an application: an application that registers the
|
|
46
|
+
* storage makes it on start, and its bound repositories use it.
|
|
47
|
+
*/
|
|
48
|
+
export declare const ProviderNotBound: import("../../index.js").DeclaredExceptionClass<{
|
|
49
|
+
/** The key of the provider in its storage. */
|
|
50
|
+
readonly provider: string;
|
|
51
|
+
}>;
|
|
43
52
|
/**
|
|
44
53
|
* `app.start()` was called while another application is the started one of
|
|
45
54
|
* the process; `start({ replace: true })` stops it and takes its place.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { IRepositoryProvider } from "../repository/types/repository.interface.js";
|
|
2
|
+
import { Kind } from "../symbols/kind.js";
|
|
3
|
+
import { type ProviderFactory } from "./start.js";
|
|
4
|
+
/**
|
|
5
|
+
* One provider of a storage made by `providersOf`, e.g. `Providers.audit`:
|
|
6
|
+
* what a repository (`repositoryOf({ provider: Providers.audit })`) or an
|
|
7
|
+
* application (`provider: Providers.main`) names. Each application that
|
|
8
|
+
* registers the storage reads and writes through its own instance of it.
|
|
9
|
+
*/
|
|
10
|
+
export type ProviderSlot<Key extends string = string> = IRepositoryProvider & {
|
|
11
|
+
readonly [Kind]: "provider-slot";
|
|
12
|
+
/** Its key in the storage. */
|
|
13
|
+
readonly key: Key;
|
|
14
|
+
};
|
|
15
|
+
/** The providers of `providersOf`, by key. */
|
|
16
|
+
export type ProviderStorage<Keys extends string = string> = {
|
|
17
|
+
readonly [Key in Keys]: ProviderSlot<Key>;
|
|
18
|
+
} & {
|
|
19
|
+
readonly [Kind]: "provider-storage";
|
|
20
|
+
};
|
|
21
|
+
/** What a slot stands for. */
|
|
22
|
+
interface SlotEntry {
|
|
23
|
+
readonly key: string;
|
|
24
|
+
readonly storage: object;
|
|
25
|
+
readonly value: IRepositoryProvider | ProviderFactory;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Named providers, declared once in a module of their own so that
|
|
29
|
+
* repositories can name one before any application exists, e.g.
|
|
30
|
+
* `const Providers = providersOf({ main: providerFrom(Database, ...), audit: auditProvider() })`,
|
|
31
|
+
* then `repositoryOf({ ..., provider: Providers.audit })` and
|
|
32
|
+
* `applicationOf({ providers: Providers, provider: Providers.main, ... })`.
|
|
33
|
+
* Each value is a provider or a factory of `providerFrom`; an application
|
|
34
|
+
* that registers the storage makes each factory on `start()`, its own
|
|
35
|
+
* instance (an application that extends it shares them).
|
|
36
|
+
*/
|
|
37
|
+
export declare function providersOf<const Entries extends Readonly<Record<string, IRepositoryProvider | ProviderFactory>>>(entries: Entries): ProviderStorage<keyof Entries & string>;
|
|
38
|
+
/** Whether `value` is a provider of a storage made by `providersOf`. */
|
|
39
|
+
export declare function isProviderSlot(value: unknown): value is ProviderSlot;
|
|
40
|
+
/** Whether `value` is a storage made by `providersOf`. */
|
|
41
|
+
export declare function isProviderStorage(value: unknown): value is ProviderStorage;
|
|
42
|
+
/** The slots of `storage`, in the order of its keys. @internal */
|
|
43
|
+
export declare function slotsOf(storage: ProviderStorage): readonly ProviderSlot[];
|
|
44
|
+
/** What `slot` stands for. @internal */
|
|
45
|
+
export declare function slotEntry(slot: ProviderSlot): SlotEntry;
|
|
46
|
+
export {};
|
|
@@ -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,9 +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";
|
|
13
|
+
import type { ProviderSlot, ProviderStorage } from "../providers.js";
|
|
12
14
|
import type { LogFactory, ProviderFactory } from "../start.js";
|
|
13
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
|
+
];
|
|
14
38
|
/** The declarations of an application, by name, one collection for each kind. */
|
|
15
39
|
export interface ApplicationCollections {
|
|
16
40
|
readonly properties: Named<unknown>;
|
|
@@ -53,9 +77,18 @@ export interface ApplicationSettings<Name extends string, Extended extends reado
|
|
|
53
77
|
* The provider of the repositories that did not declare one; the
|
|
54
78
|
* repositories of the application read and write through it. With
|
|
55
79
|
* `providerFrom`, it is made by `app.start()` from the variables of its
|
|
56
|
-
* environments, and calls before that throw `ApplicationNotStarted`.
|
|
80
|
+
* environments, and calls before that throw `ApplicationNotStarted`. A
|
|
81
|
+
* provider of `providers` (`Providers.main`) names the instance this
|
|
82
|
+
* application makes of it.
|
|
57
83
|
*/
|
|
58
84
|
readonly provider?: IRepositoryProvider | ProviderFactory;
|
|
85
|
+
/**
|
|
86
|
+
* Named providers made by `providersOf`, which repositories name
|
|
87
|
+
* (`repositoryOf({ provider: Providers.audit })`). The application makes
|
|
88
|
+
* its own instance of each `providerFrom` on `start()` and binds the
|
|
89
|
+
* repositories to it; an application that extends it shares them.
|
|
90
|
+
*/
|
|
91
|
+
readonly providers?: ProviderStorage;
|
|
59
92
|
/**
|
|
60
93
|
* How it logs: the providers its lines go to and the lowest level kept.
|
|
61
94
|
* Use cases, commands and repository calls of the application are logged
|
|
@@ -105,25 +138,29 @@ export interface IApplication<Name extends string, Collections extends Applicati
|
|
|
105
138
|
readonly entities: Collections["entities"];
|
|
106
139
|
readonly environments: Collections["environments"];
|
|
107
140
|
/**
|
|
108
|
-
* Its repositories, inherited ones included. With a `provider`
|
|
109
|
-
* bound to it: they share the declaration of the
|
|
110
|
-
* 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).
|
|
111
145
|
*/
|
|
112
146
|
readonly repositories: Collections["repositories"];
|
|
113
147
|
/**
|
|
114
|
-
* Its use cases. With a `provider` they are
|
|
115
|
-
* are the bound ones, through child use
|
|
116
|
-
* 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.
|
|
117
152
|
*/
|
|
118
153
|
readonly useCases: Collections["useCases"];
|
|
119
154
|
/**
|
|
120
|
-
* Its commands. With a `provider` they are rebuilt
|
|
121
|
-
* 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.
|
|
122
158
|
*/
|
|
123
159
|
readonly commands: Collections["commands"];
|
|
124
160
|
/**
|
|
125
|
-
* Its outputs. With a `provider` they are rebuilt
|
|
126
|
-
* (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.
|
|
127
164
|
*/
|
|
128
165
|
readonly outputs: Collections["outputs"];
|
|
129
166
|
/** Its exceptions. */
|
|
@@ -132,6 +169,13 @@ export interface IApplication<Name extends string, Collections extends Applicati
|
|
|
132
169
|
repository<Repository extends AnyRepository>(repository: Repository): Repository;
|
|
133
170
|
/** The bound version of a use case registered in the application. */
|
|
134
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>>;
|
|
135
179
|
/** The bound version of a command registered in the application. */
|
|
136
180
|
command<Command extends AnyCommand>(command: Command): Command;
|
|
137
181
|
/** The bound version of an output registered in the application. */
|
|
@@ -163,6 +207,8 @@ export interface IApplication<Name extends string, Collections extends Applicati
|
|
|
163
207
|
get<UseCase extends AnyUseCaseClass>(useCase: UseCase): UseCase;
|
|
164
208
|
/** The bound version of a repository registered in the application. */
|
|
165
209
|
get<Repository extends AnyRepository>(repository: Repository): Repository;
|
|
210
|
+
/** The instance this application reads and writes through for a provider of its `providers`. */
|
|
211
|
+
get(provider: ProviderSlot): IRepositoryProvider;
|
|
166
212
|
/** Whether `start()` completed and `stop()` was not called since. */
|
|
167
213
|
readonly started: boolean;
|
|
168
214
|
}
|
|
@@ -345,13 +391,22 @@ export interface LogDescription {
|
|
|
345
391
|
readonly kind: "opaque";
|
|
346
392
|
})[];
|
|
347
393
|
}
|
|
394
|
+
/** How `describe` names a provider of `providersOf`: by its key. */
|
|
395
|
+
export interface ProviderReference {
|
|
396
|
+
readonly kind: "ref";
|
|
397
|
+
readonly key: string;
|
|
398
|
+
}
|
|
348
399
|
/** The graph `describe` gives: every declaration by name, with its origin in `from`. */
|
|
349
400
|
export interface ApplicationDescription {
|
|
350
401
|
readonly name: string;
|
|
351
402
|
/** The names of the applications it extends directly. */
|
|
352
403
|
readonly extends: readonly string[];
|
|
353
404
|
/** The provider of the application (or of the last extended one), present only when configured. */
|
|
354
|
-
readonly provider?: ProviderDescription;
|
|
405
|
+
readonly provider?: ProviderDescription | ProviderReference;
|
|
406
|
+
/** Its providers of `providersOf` (inherited ones included), by key; present only when it has some. */
|
|
407
|
+
readonly providers?: Readonly<Record<string, ProviderDescription & {
|
|
408
|
+
readonly from: string;
|
|
409
|
+
}>>;
|
|
355
410
|
/** Its `log` (or the one of the last extended application), present only when configured. */
|
|
356
411
|
readonly log?: LogDescription | {
|
|
357
412
|
readonly kind: "opaque";
|
|
@@ -378,8 +433,8 @@ export interface ApplicationDescription {
|
|
|
378
433
|
readonly relations: readonly string[];
|
|
379
434
|
/** The names of its `environmentDependencies`. */
|
|
380
435
|
readonly environments: readonly string[];
|
|
381
|
-
/** Its own provider, present only when it declared one. */
|
|
382
|
-
readonly provider?: ProviderDescription;
|
|
436
|
+
/** Its own provider, present only when it declared one; a provider of `providersOf` by its key. */
|
|
437
|
+
readonly provider?: ProviderDescription | ProviderReference;
|
|
383
438
|
}>>;
|
|
384
439
|
readonly useCases: Readonly<Record<string, UseCaseDescription>>;
|
|
385
440
|
readonly commands: Readonly<Record<string, 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`. */
|
|
@@ -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,8 +2,8 @@ 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
|
/**
|
|
@@ -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;
|
|
@@ -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 {};
|