@afora/core 0.0.8 → 0.0.11
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 +149 -23
- package/dist/adapters.d.ts +25 -0
- package/dist/adapters.js +32 -0
- package/dist/core/application/application.d.ts +30 -0
- package/dist/core/application/application.js +1291 -0
- package/dist/core/application/exceptions.d.ts +17 -0
- package/dist/core/application/exceptions.js +85 -0
- package/dist/core/application/migrate.d.ts +19 -0
- package/dist/core/application/migrate.js +67 -0
- package/dist/core/application/providers.js +108 -0
- package/dist/core/application/registry.js +23 -0
- package/dist/core/application/schema.d.ts +30 -0
- package/dist/core/application/schema.js +398 -0
- package/dist/core/application/start.js +162 -0
- package/dist/core/application/types/application.interface.d.ts +60 -3
- package/dist/core/auth/jwt.d.ts +30 -0
- package/dist/core/auth/jwt.js +200 -0
- package/dist/core/auth/types/jwt.interface.d.ts +74 -0
- package/dist/core/blueprint/blueprint-plugin.js +7 -0
- package/dist/core/blueprint/blueprint.js +146 -0
- package/dist/core/blueprint/callable.js +13 -0
- package/dist/core/blueprint/exceptions.d.ts +5 -0
- package/dist/core/blueprint/exceptions.js +20 -0
- package/dist/core/blueprint/is-blueprint.js +4 -0
- package/dist/core/blueprint/list.js +19 -0
- package/dist/core/blueprint/optional.d.ts +3 -1
- package/dist/core/blueprint/optional.js +69 -0
- package/dist/core/blueprint/record-field.js +14 -0
- package/dist/core/blueprint/slice.js +127 -0
- package/dist/core/blueprint/types/blueprint.interface.d.ts +95 -5
- package/dist/core/blueprint/variant.d.ts +32 -0
- package/dist/core/blueprint/variant.js +72 -0
- package/dist/core/command/command.js +428 -0
- package/dist/core/command/exceptions.js +30 -0
- package/dist/core/command/types/command.interface.d.ts +10 -1
- package/dist/core/entity/abstract-entity.d.ts +24 -0
- package/dist/core/entity/abstract-entity.js +181 -0
- package/dist/core/entity/entity.d.ts +1 -1
- package/dist/core/entity/entity.js +209 -0
- package/dist/core/entity/event.d.ts +39 -0
- package/dist/core/entity/event.js +80 -0
- package/dist/core/entity/exceptions.d.ts +9 -0
- package/dist/core/entity/exceptions.js +27 -0
- package/dist/core/entity/trust.d.ts +24 -0
- package/dist/core/entity/trust.js +7 -0
- package/dist/core/entity/types/entity.interface.d.ts +30 -0
- package/dist/core/entity/version.js +13 -0
- package/dist/core/environment/environment.d.ts +26 -3
- package/dist/core/environment/environment.js +71 -0
- package/dist/core/event-policy/event-policy.js +76 -0
- package/dist/core/event-policy/exceptions.js +12 -0
- package/dist/core/event-policy/publish.js +98 -0
- package/dist/core/event-policy/publishers.js +18 -0
- package/dist/core/event-policy/types/event-policy.interface.d.ts +8 -2
- package/dist/core/exception/enums/exception-layers.js +15 -0
- package/dist/core/exception/exception.d.ts +15 -0
- package/dist/core/exception/exception.js +128 -0
- package/dist/core/exception/exported.js +49 -0
- package/dist/core/exception/guard.d.ts +20 -1
- package/dist/core/exception/guard.js +16 -0
- package/dist/core/exception/types/exception.interface.d.ts +13 -0
- package/dist/core/json.js +19 -0
- package/dist/core/logger/exceptions.js +7 -0
- package/dist/core/logger/logger.d.ts +14 -1
- package/dist/core/logger/logger.js +178 -0
- package/dist/core/openapi/exceptions.js +7 -0
- package/dist/core/openapi/openapi.js +132 -0
- package/dist/core/openapi/types/openapi.interface.d.ts +7 -1
- package/dist/core/output/access.d.ts +16 -0
- package/dist/core/output/access.js +66 -0
- package/dist/core/output/coerce.js +38 -0
- package/dist/core/output/exceptions.d.ts +16 -0
- package/dist/core/output/exceptions.js +22 -0
- package/dist/core/output/http.d.ts +36 -0
- package/dist/core/output/http.js +351 -0
- package/dist/core/output/openapi-sink.d.ts +33 -4
- package/dist/core/output/openapi-sink.js +571 -0
- package/dist/core/output/output.js +192 -0
- package/dist/core/output/problem.js +30 -0
- package/dist/core/output/select.js +28 -0
- package/dist/core/output/stage.d.ts +7 -2
- package/dist/core/output/stage.js +111 -0
- package/dist/core/output/status.d.ts +1 -1
- package/dist/core/output/status.js +52 -0
- package/dist/core/output/types/http.interface.d.ts +134 -0
- package/dist/core/output/types/output.interface.d.ts +49 -5
- package/dist/core/parse/issue.d.ts +28 -3
- package/dist/core/parse/issue.js +31 -0
- package/dist/core/parse/parse.d.ts +16 -0
- package/dist/core/parse/parse.js +323 -0
- package/dist/core/parse/strip.js +48 -0
- package/dist/core/property/abstract-property.d.ts +9 -0
- package/dist/core/property/abstract-property.js +37 -0
- package/dist/core/property/define-property.d.ts +34 -6
- package/dist/core/property/define-property.js +209 -0
- package/dist/core/property/enums/property-states.js +8 -0
- package/dist/core/property/exceptions.js +12 -0
- package/dist/core/property/input.js +10 -0
- package/dist/core/property/is-property.js +3 -0
- package/dist/core/property/lineage.js +8 -0
- package/dist/core/property/property.d.ts +27 -0
- package/dist/core/property/property.js +46 -0
- package/dist/core/property/refine.js +103 -0
- 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 +8 -0
- package/dist/core/record/abstract-record.js +307 -0
- package/dist/core/record/exceptions.js +49 -0
- package/dist/core/record/marks.js +7 -0
- package/dist/core/record/mask.js +60 -0
- package/dist/core/record/name.js +23 -0
- package/dist/core/record/plugin-catalog.js +115 -0
- package/dist/core/record/plugin.js +198 -0
- package/dist/core/record/record.js +117 -0
- package/dist/core/record/types/record.interface.d.ts +17 -1
- package/dist/core/repository/cursor.js +83 -0
- package/dist/core/repository/exceptions.d.ts +13 -0
- package/dist/core/repository/exceptions.js +72 -0
- package/dist/core/repository/in-memory.d.ts +2 -2
- package/dist/core/repository/in-memory.js +196 -0
- package/dist/core/repository/migrate.d.ts +20 -0
- package/dist/core/repository/migrate.js +254 -0
- package/dist/core/repository/plan.js +27 -0
- package/dist/core/repository/provider.js +29 -0
- package/dist/core/repository/query.js +153 -0
- package/dist/core/repository/references.js +196 -0
- package/dist/core/repository/repository.d.ts +22 -2
- package/dist/core/repository/repository.js +720 -0
- package/dist/core/repository/state.d.ts +2 -0
- package/dist/core/repository/state.js +138 -0
- package/dist/core/repository/types/query.interface.d.ts +13 -0
- package/dist/core/repository/types/repository.interface.d.ts +50 -5
- package/dist/core/repository/types/schema.interface.d.ts +132 -0
- package/dist/core/repository/upcast.d.ts +64 -0
- package/dist/core/repository/upcast.js +179 -0
- package/dist/core/schema/schema.d.ts +37 -0
- package/dist/core/schema/schema.js +542 -0
- package/dist/core/standard/standard-schema.js +1 -0
- package/dist/core/standard/standard.js +23 -0
- package/dist/core/symbols/demo.d.ts +4 -0
- package/dist/core/symbols/demo.js +1 -0
- package/dist/core/symbols/kind.d.ts +1 -1
- package/dist/core/symbols/kind.js +1 -0
- package/dist/core/symbols/meta.js +1 -0
- package/dist/core/symbols/state.d.ts +5 -0
- package/dist/core/symbols/state.js +1 -0
- package/dist/core/tracing/exceptions.d.ts +4 -0
- package/dist/core/tracing/exceptions.js +7 -0
- package/dist/core/tracing/tracing.d.ts +72 -0
- package/dist/core/tracing/tracing.js +101 -0
- package/dist/core/use-case/access.d.ts +12 -0
- package/dist/core/use-case/access.js +56 -0
- package/dist/core/use-case/decorators.d.ts +40 -0
- package/dist/core/use-case/decorators.js +65 -0
- package/dist/core/use-case/exceptions.d.ts +5 -1
- package/dist/core/use-case/exceptions.js +48 -0
- package/dist/core/use-case/plugin-catalog.js +68 -0
- package/dist/core/use-case/plugin.js +133 -0
- package/dist/core/use-case/route.d.ts +18 -0
- package/dist/core/use-case/route.js +200 -0
- package/dist/core/use-case/scope.d.ts +5 -0
- package/dist/core/use-case/scope.js +4 -0
- package/dist/core/use-case/steps/describe.d.ts +5 -1
- package/dist/core/use-case/steps/describe.js +24 -0
- package/dist/core/use-case/steps/references.js +105 -0
- package/dist/core/use-case/steps/run.js +139 -0
- package/dist/core/use-case/steps/types/check.interface.d.ts +233 -0
- package/dist/core/use-case/steps/types/steps.interface.d.ts +8 -1
- package/dist/core/use-case/steps/validate.js +368 -0
- package/dist/core/use-case/target.js +100 -0
- package/dist/core/use-case/types/access.interface.d.ts +39 -0
- package/dist/core/use-case/types/route.interface.d.ts +86 -0
- package/dist/core/use-case/use-case.d.ts +127 -2
- package/dist/core/use-case/use-case.js +493 -0
- package/dist/experimental.d.ts +18 -1
- package/dist/experimental.js +18 -123
- package/dist/index.d.ts +49 -51
- package/dist/index.js +213 -443
- package/dist/std/blueprint-plugin.js +42 -0
- package/dist/std/blueprint.d.ts +21 -0
- package/dist/std/blueprint.js +3 -0
- package/dist/std/command.js +3 -0
- package/dist/std/entity.d.ts +20 -1
- package/dist/std/entity.js +30 -0
- package/dist/std/event-policies.js +3 -0
- package/dist/std/properties/contact.d.ts +3 -0
- package/dist/std/properties/contact.js +29 -0
- package/dist/std/properties/enum.js +26 -0
- package/dist/std/properties/exceptions.js +14 -0
- package/dist/std/properties/headless.js +45 -0
- package/dist/std/properties/identity.js +28 -0
- package/dist/std/properties/json.js +161 -0
- package/dist/std/properties/password.d.ts +0 -2
- package/dist/std/properties/password.js +79 -0
- package/dist/std/properties/primitives.d.ts +4 -0
- package/dist/std/properties/primitives.js +28 -0
- package/dist/std/properties/time.js +55 -0
- package/dist/std/record-plugins.d.ts +2 -2
- package/dist/std/record-plugins.js +73 -0
- package/dist/std/record.d.ts +20 -1
- package/dist/std/record.js +3 -0
- package/dist/std/resource.d.ts +31 -0
- package/dist/std/resource.js +39 -0
- package/dist/std/runtime.d.ts +6 -0
- package/dist/std/runtime.js +193 -0
- package/dist/std/stages.js +4 -0
- package/dist/std/use-cases/auth.d.ts +5 -1
- package/dist/std/use-cases/auth.js +193 -0
- package/dist/std/use-cases/crud.js +261 -0
- package/dist/std/use-cases/index.d.ts +1 -1
- package/dist/std/use-cases/index.js +12 -0
- package/dist/std/use-cases/lifecycle.js +97 -0
- package/dist/std/use-cases/shared.d.ts +2 -2
- package/dist/std/use-cases/shared.js +232 -0
- package/dist/std/use-cases/types.d.ts +102 -2
- package/dist/std/use-cases/types.js +0 -0
- package/dist/testing/http-provider-contract.d.ts +32 -0
- package/dist/testing/http-provider-contract.js +344 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +3 -944
- package/dist/testing/memory-publisher.js +12 -0
- package/dist/testing/provider-contract.d.ts +26 -1
- package/dist/testing/provider-contract.js +1071 -0
- package/package.json +23 -3
- package/dist/index-qxfkyd6k.js +0 -1721
- package/dist/index-t5qwtyj5.js +0 -8194
|
@@ -57,6 +57,23 @@ export declare const ApplicationAlreadyStarted: import("../../index.js").Declare
|
|
|
57
57
|
readonly current: string;
|
|
58
58
|
readonly attempted: string;
|
|
59
59
|
}>;
|
|
60
|
+
/**
|
|
61
|
+
* `app.start({ lock })` found that the code cannot run over the stores the
|
|
62
|
+
* lock describes: an entity of the lock that no entity is named or lists in
|
|
63
|
+
* `previousNames` (renamed without it, its rows would no longer be read), or
|
|
64
|
+
* an entity whose `schemaVersion` is lower than the lock's.
|
|
65
|
+
* `details.problems` lists each.
|
|
66
|
+
*/
|
|
67
|
+
export declare const SchemaLockMismatch: import("../../index.js").DeclaredExceptionClass<{
|
|
68
|
+
readonly problems: readonly string[];
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* `app.migrate` got invalid options, or names an entity without a
|
|
72
|
+
* repository; `source` is the application name.
|
|
73
|
+
*/
|
|
74
|
+
export declare const InvalidSchemaMigration: import("../../index.js").DeclaredExceptionClass<{
|
|
75
|
+
readonly reason: string;
|
|
76
|
+
}>;
|
|
60
77
|
/**
|
|
61
78
|
* `app.start()` found environments whose variables are missing or rejected;
|
|
62
79
|
* `details.environments` gives the keys of each, by name.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ExceptionLayers } from "../exception/enums/exception-layers.js";
|
|
2
|
+
import { exceptionOf } from "../exception/exception.js";
|
|
3
|
+
export const InvalidApplicationDeclaration = exceptionOf({
|
|
4
|
+
layer: ExceptionLayers.Application,
|
|
5
|
+
name: "InvalidApplicationDeclaration",
|
|
6
|
+
message: ({ reason }) => reason
|
|
7
|
+
});
|
|
8
|
+
export const DuplicateApplicationDeclaration = exceptionOf({
|
|
9
|
+
layer: ExceptionLayers.Application,
|
|
10
|
+
name: "DuplicateApplicationDeclaration",
|
|
11
|
+
message: ({
|
|
12
|
+
first,
|
|
13
|
+
second
|
|
14
|
+
}) => `The same object is registered as ${first} and as ${second}.`
|
|
15
|
+
});
|
|
16
|
+
export const ApplicationConflict = exceptionOf({
|
|
17
|
+
layer: ExceptionLayers.Application,
|
|
18
|
+
name: "ApplicationConflict",
|
|
19
|
+
message: ({
|
|
20
|
+
reason
|
|
21
|
+
}) => reason
|
|
22
|
+
});
|
|
23
|
+
export const UnregisteredApplicationReference = exceptionOf({
|
|
24
|
+
layer: ExceptionLayers.Application,
|
|
25
|
+
name: "UnregisteredApplicationReference",
|
|
26
|
+
message: ({
|
|
27
|
+
holder,
|
|
28
|
+
reference
|
|
29
|
+
}) => `${holder} holds ${reference}, which is not registered in the application.`
|
|
30
|
+
});
|
|
31
|
+
export const UnregisteredRepositoryDependency = exceptionOf({
|
|
32
|
+
layer: ExceptionLayers.Application,
|
|
33
|
+
name: "UnregisteredRepositoryDependency",
|
|
34
|
+
message: ({
|
|
35
|
+
repository,
|
|
36
|
+
dependency
|
|
37
|
+
}) => `Repository ${repository} depends on ${dependency}, which is not registered in the application.`
|
|
38
|
+
});
|
|
39
|
+
export const UnregisteredUseCaseDependency = exceptionOf({
|
|
40
|
+
layer: ExceptionLayers.Application,
|
|
41
|
+
name: "UnregisteredUseCaseDependency",
|
|
42
|
+
message: ({
|
|
43
|
+
useCase,
|
|
44
|
+
dependency
|
|
45
|
+
}) => `Use case ${useCase} depends on ${dependency}, which is not registered in the application.`
|
|
46
|
+
});
|
|
47
|
+
export const ApplicationNotStarted = exceptionOf({
|
|
48
|
+
layer: ExceptionLayers.Application,
|
|
49
|
+
name: "ApplicationNotStarted",
|
|
50
|
+
message: ({
|
|
51
|
+
application
|
|
52
|
+
}) => application === undefined ? "No application is started: call await app.start() first." : `The application "${application}" is not started: call await app.start() first.`
|
|
53
|
+
});
|
|
54
|
+
export const ProviderNotBound = exceptionOf({
|
|
55
|
+
layer: ExceptionLayers.Application,
|
|
56
|
+
name: "ProviderNotBound",
|
|
57
|
+
message: ({
|
|
58
|
+
provider
|
|
59
|
+
}) => `The provider "${provider}" is made by an application: register its storage in applicationOf({ providers }) and call the repository through the application.`
|
|
60
|
+
});
|
|
61
|
+
export const ApplicationAlreadyStarted = exceptionOf({
|
|
62
|
+
layer: ExceptionLayers.Application,
|
|
63
|
+
name: "ApplicationAlreadyStarted",
|
|
64
|
+
message: ({
|
|
65
|
+
current,
|
|
66
|
+
attempted
|
|
67
|
+
}) => `The application "${current}" is already started, so "${attempted}" cannot be: stop it, or call start({ replace: true }).`
|
|
68
|
+
});
|
|
69
|
+
export const SchemaLockMismatch = exceptionOf({
|
|
70
|
+
layer: ExceptionLayers.Application,
|
|
71
|
+
name: "SchemaLockMismatch",
|
|
72
|
+
message: ({ problems }) => `The application does not match its schema lock: ${problems.join(" ")}`
|
|
73
|
+
});
|
|
74
|
+
export const InvalidSchemaMigration = exceptionOf({
|
|
75
|
+
layer: ExceptionLayers.Application,
|
|
76
|
+
name: "InvalidSchemaMigration",
|
|
77
|
+
message: ({ reason }) => reason
|
|
78
|
+
});
|
|
79
|
+
export const InvalidApplicationEnvironment = exceptionOf({
|
|
80
|
+
layer: ExceptionLayers.Environment,
|
|
81
|
+
name: "InvalidApplicationEnvironment",
|
|
82
|
+
message: ({
|
|
83
|
+
environments
|
|
84
|
+
}) => `Invalid environment variables: ${Object.entries(environments).map(([name, keys]) => `${name} (${keys.join(", ")})`).join("; ")}.`
|
|
85
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SchemaLock, SchemaMigrationOptions, SchemaMigrationReport } from "../repository/types/schema.interface.js";
|
|
2
|
+
import type { ApplicationDescription } from "./types/application.interface.js";
|
|
3
|
+
/** What `app.migrate` reads from its application. */
|
|
4
|
+
export interface MigrationSource {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
/** Its entities, by name. */
|
|
7
|
+
readonly entities: ReadonlyMap<string, object>;
|
|
8
|
+
/** Its bound repositories. */
|
|
9
|
+
readonly repositories: readonly object[];
|
|
10
|
+
describe(): ApplicationDescription;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* `app.migrate(options)`: for each entity with a repository (or those of
|
|
14
|
+
* `options.entities`), the backfill of `migrateRepository` through the
|
|
15
|
+
* provider of its first repository, one entity after the other.
|
|
16
|
+
*/
|
|
17
|
+
export declare function migrateApplication(source: MigrationSource, options: SchemaMigrationOptions): Promise<SchemaMigrationReport>;
|
|
18
|
+
/** Whether `value` has the shape of a schema lock. */
|
|
19
|
+
export declare function isLock(value: unknown): value is SchemaLock;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { migrateRepository } from "../repository/migrate.js";
|
|
2
|
+
import { findState } from "../repository/state.js";
|
|
3
|
+
import { InvalidSchemaMigration } from "./exceptions.js";
|
|
4
|
+
import { diffSchemas, schemaLockOf } from "./schema.js";
|
|
5
|
+
export async function migrateApplication(source, options) {
|
|
6
|
+
const fail = (reason) => {
|
|
7
|
+
throw new InvalidSchemaMigration({
|
|
8
|
+
source: source.name,
|
|
9
|
+
details: { reason }
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
if (typeof options !== "object" || options === null) {
|
|
13
|
+
fail('Expected the options of migrate, e.g. { mode: "check" }.');
|
|
14
|
+
}
|
|
15
|
+
const { mode, destructive = false, pageSize = 100, lock } = options;
|
|
16
|
+
if (mode !== "check" && mode !== "apply") {
|
|
17
|
+
fail('Expected mode to be "check" or "apply".');
|
|
18
|
+
}
|
|
19
|
+
if (typeof destructive !== "boolean") {
|
|
20
|
+
fail("Expected destructive to be a boolean.");
|
|
21
|
+
}
|
|
22
|
+
if (!Number.isSafeInteger(pageSize) || pageSize < 1) {
|
|
23
|
+
fail("Expected pageSize to be a positive integer.");
|
|
24
|
+
}
|
|
25
|
+
if (lock !== undefined && !isLock(lock)) {
|
|
26
|
+
fail("Expected lock to be a schema lock ({ lockVersion: 1, entities }).");
|
|
27
|
+
}
|
|
28
|
+
const byEntity = new Map;
|
|
29
|
+
for (const repository of source.repositories) {
|
|
30
|
+
const state = findState(repository);
|
|
31
|
+
if (state && !byEntity.has(state.entity))
|
|
32
|
+
byEntity.set(state.entity, state);
|
|
33
|
+
}
|
|
34
|
+
const names = options.entities ?? [...source.entities].filter(([, entity]) => byEntity.has(entity)).map(([name]) => name);
|
|
35
|
+
if (!Array.isArray(names))
|
|
36
|
+
fail("Expected entities to be a list of names.");
|
|
37
|
+
const targets = [];
|
|
38
|
+
for (const name of names) {
|
|
39
|
+
const entity = source.entities.get(name);
|
|
40
|
+
if (entity === undefined) {
|
|
41
|
+
fail(`"${name}" is not an entity of the application.`);
|
|
42
|
+
}
|
|
43
|
+
const state = byEntity.get(entity);
|
|
44
|
+
if (state === undefined) {
|
|
45
|
+
fail(`The entity "${name}" has no repository to migrate it through.`);
|
|
46
|
+
}
|
|
47
|
+
targets.push([name, state]);
|
|
48
|
+
}
|
|
49
|
+
const changes = lock === undefined ? [] : diffSchemas(lock, schemaLockOf(source.describe()));
|
|
50
|
+
const entities = {};
|
|
51
|
+
for (const [name, state] of targets) {
|
|
52
|
+
entities[name] = await migrateRepository(state, {
|
|
53
|
+
mode,
|
|
54
|
+
destructive,
|
|
55
|
+
pageSize,
|
|
56
|
+
plan: Object.freeze({
|
|
57
|
+
entity: name,
|
|
58
|
+
changes: changes.filter((change) => change.entity === name),
|
|
59
|
+
destructive
|
|
60
|
+
})
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return { mode, destructive, entities };
|
|
64
|
+
}
|
|
65
|
+
export function isLock(value) {
|
|
66
|
+
return typeof value === "object" && value !== null && value.lockVersion === 1 && typeof value.entities === "object" && value.entities !== null;
|
|
67
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Kind } from "../symbols/kind.js";
|
|
2
|
+
import { InvalidApplicationDeclaration, ProviderNotBound } from "./exceptions.js";
|
|
3
|
+
import { isProviderFactory } from "./start.js";
|
|
4
|
+
const slots = new WeakMap;
|
|
5
|
+
const storages = new WeakMap;
|
|
6
|
+
const METHODS = [
|
|
7
|
+
"findOne",
|
|
8
|
+
"findMany",
|
|
9
|
+
"insert",
|
|
10
|
+
"update",
|
|
11
|
+
"remove",
|
|
12
|
+
"count"
|
|
13
|
+
];
|
|
14
|
+
const KEY = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
15
|
+
const RESERVED = new Set(["inMemory", "__proto__", "constructor", "prototype"]);
|
|
16
|
+
function invalid(reason) {
|
|
17
|
+
throw new InvalidApplicationDeclaration({
|
|
18
|
+
source: "providersOf",
|
|
19
|
+
details: { reason }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function isProviderObject(value) {
|
|
23
|
+
return typeof value === "object" && value !== null && !isProviderFactory(value) && METHODS.some((method) => typeof value[method] === "function");
|
|
24
|
+
}
|
|
25
|
+
function slotOf(key, storage, value) {
|
|
26
|
+
const slot = {
|
|
27
|
+
[Kind]: "provider-slot",
|
|
28
|
+
key
|
|
29
|
+
};
|
|
30
|
+
if (isProviderFactory(value)) {
|
|
31
|
+
const unbound = () => {
|
|
32
|
+
throw new ProviderNotBound({ source: key, details: { provider: key } });
|
|
33
|
+
};
|
|
34
|
+
for (const method of METHODS)
|
|
35
|
+
slot[method] = unbound;
|
|
36
|
+
slot.transaction = unbound;
|
|
37
|
+
slot.increment = unbound;
|
|
38
|
+
Object.defineProperty(slot, "capabilities", {
|
|
39
|
+
get: () => {
|
|
40
|
+
return;
|
|
41
|
+
},
|
|
42
|
+
enumerable: true
|
|
43
|
+
});
|
|
44
|
+
} else {
|
|
45
|
+
const target = value;
|
|
46
|
+
for (const method of [
|
|
47
|
+
...METHODS,
|
|
48
|
+
"increment",
|
|
49
|
+
"transaction",
|
|
50
|
+
"close",
|
|
51
|
+
"migrate"
|
|
52
|
+
]) {
|
|
53
|
+
if (typeof target[method] === "function") {
|
|
54
|
+
slot[method] = (...args) => target[method]?.(...args);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
Object.defineProperty(slot, "capabilities", {
|
|
58
|
+
get: () => value.capabilities,
|
|
59
|
+
enumerable: true
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
Object.freeze(slot);
|
|
63
|
+
slots.set(slot, { key, storage, value });
|
|
64
|
+
return slot;
|
|
65
|
+
}
|
|
66
|
+
export function providersOf(entries) {
|
|
67
|
+
if (typeof entries !== "object" || entries === null || Array.isArray(entries) || Object.keys(entries).length === 0) {
|
|
68
|
+
invalid("Expected an object of providers by key.");
|
|
69
|
+
}
|
|
70
|
+
const storage = Object.create(null);
|
|
71
|
+
storage[Kind] = "provider-storage";
|
|
72
|
+
const seen = new Map;
|
|
73
|
+
const list = [];
|
|
74
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
75
|
+
if (!KEY.test(key) || RESERVED.has(key)) {
|
|
76
|
+
invalid(key === "inMemory" ? `"inMemory" is the built-in provider; choose another key.` : `Expected "${key}" to be an identifier that is not reserved.`);
|
|
77
|
+
}
|
|
78
|
+
if (isProviderSlot(value)) {
|
|
79
|
+
invalid(`"${key}" holds a provider of another storage; a storage holds providers, not slots.`);
|
|
80
|
+
}
|
|
81
|
+
if (!isProviderFactory(value) && !isProviderObject(value)) {
|
|
82
|
+
invalid(`Expected "${key}" to be a repository provider or a factory of providerFrom.`);
|
|
83
|
+
}
|
|
84
|
+
const other = seen.get(value);
|
|
85
|
+
if (other !== undefined) {
|
|
86
|
+
invalid(`"${other}" and "${key}" hold the same provider.`);
|
|
87
|
+
}
|
|
88
|
+
seen.set(value, key);
|
|
89
|
+
const slot = slotOf(key, storage, value);
|
|
90
|
+
storage[key] = slot;
|
|
91
|
+
list.push(slot);
|
|
92
|
+
}
|
|
93
|
+
Object.freeze(storage);
|
|
94
|
+
storages.set(storage, Object.freeze(list));
|
|
95
|
+
return storage;
|
|
96
|
+
}
|
|
97
|
+
export function isProviderSlot(value) {
|
|
98
|
+
return typeof value === "object" && value !== null && slots.has(value);
|
|
99
|
+
}
|
|
100
|
+
export function isProviderStorage(value) {
|
|
101
|
+
return typeof value === "object" && value !== null && storages.has(value);
|
|
102
|
+
}
|
|
103
|
+
export function slotsOf(storage) {
|
|
104
|
+
return storages.get(storage) ?? [];
|
|
105
|
+
}
|
|
106
|
+
export function slotEntry(slot) {
|
|
107
|
+
return slots.get(slot);
|
|
108
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ApplicationNotStarted } from "./exceptions.js";
|
|
2
|
+
const SLOT = Symbol.for("afora.application");
|
|
3
|
+
function slot() {
|
|
4
|
+
const global = globalThis;
|
|
5
|
+
global[SLOT] ??= { current: undefined };
|
|
6
|
+
return global[SLOT];
|
|
7
|
+
}
|
|
8
|
+
export function useApplication() {
|
|
9
|
+
const { current } = slot();
|
|
10
|
+
if (current === undefined) {
|
|
11
|
+
throw new ApplicationNotStarted({ source: "useApplication", details: {} });
|
|
12
|
+
}
|
|
13
|
+
return current;
|
|
14
|
+
}
|
|
15
|
+
export function resetApplication() {
|
|
16
|
+
slot().current = undefined;
|
|
17
|
+
}
|
|
18
|
+
export function startedApplication() {
|
|
19
|
+
return slot().current;
|
|
20
|
+
}
|
|
21
|
+
export function setStartedApplication(application) {
|
|
22
|
+
slot().current = application;
|
|
23
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SchemaChange, SchemaLock } from "../repository/types/schema.interface.js";
|
|
2
|
+
import type { ApplicationDescription } from "./types/application.interface.js";
|
|
3
|
+
/**
|
|
4
|
+
* The lock of the entities of `description` (`app.describe()`): per entity,
|
|
5
|
+
* its schema version, previous names, unique keys and fields (each with its
|
|
6
|
+
* JSON Schema, whether it is optional or unique, its `fill` and
|
|
7
|
+
* `renamedFrom`, and the fields of a nested blueprint or record), with
|
|
8
|
+
* registered properties, blueprints and records resolved and every key
|
|
9
|
+
* sorted, so equivalent applications give equal locks. The identity keys
|
|
10
|
+
* and the keys of record plugins are left out.
|
|
11
|
+
*/
|
|
12
|
+
export declare function schemaLockOf(description: ApplicationDescription): SchemaLock;
|
|
13
|
+
/**
|
|
14
|
+
* The changes from `lock` to `current` (both made by `schemaLockOf`), each
|
|
15
|
+
* classed as `automatic` (afora handles it: an optional key added, a key
|
|
16
|
+
* removed, a constraint loosened, metadata), `declared` (it needs a `fill`,
|
|
17
|
+
* a `renamedFrom`, `previousNames` or an `upgrade` step to a version above
|
|
18
|
+
* the lock's; `satisfied` says whether the code has it) or `check` (a new
|
|
19
|
+
* unique key: the stored rows must be checked first). `destructive` marks
|
|
20
|
+
* what deletes stored data once applied: a removed key, the rows of a
|
|
21
|
+
* previous name, a removed entity. Nested blueprints and records are
|
|
22
|
+
* compared key by key. Ordered by entity name, then key.
|
|
23
|
+
*/
|
|
24
|
+
export declare function diffSchemas(lock: SchemaLock, current: SchemaLock): readonly SchemaChange[];
|
|
25
|
+
/**
|
|
26
|
+
* Why the code cannot run over the stores `lock` describes: an entity of
|
|
27
|
+
* the lock that no entity is named, or lists in its `previousNames`, or an
|
|
28
|
+
* entity whose `schemaVersion` is lower than the lock's. Empty when it can.
|
|
29
|
+
*/
|
|
30
|
+
export declare function schemaLockProblemsOf(lock: SchemaLock, current: SchemaLock): readonly string[];
|