@fougere/core 0.8.3-alpha.0 → 0.9.0-alpha.0
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/dist/boot/AppLifecycle.d.ts +8 -0
- package/dist/boot/AppLifecycle.d.ts.map +1 -1
- package/dist/boot/AppLifecycle.js.map +1 -1
- package/dist/boot/Emissions.d.ts +26 -0
- package/dist/boot/Emissions.d.ts.map +1 -1
- package/dist/boot/Emissions.js +144 -9
- package/dist/boot/Emissions.js.map +1 -1
- package/dist/boot/auth.d.ts +1 -1
- package/dist/boot/auth.d.ts.map +1 -1
- package/dist/boot/bootstrap.d.ts.map +1 -1
- package/dist/boot/bootstrap.js +401 -598
- package/dist/boot/bootstrap.js.map +1 -1
- package/dist/boot/card.js +1 -1
- package/dist/boot/card.js.map +1 -1
- package/dist/boot/hosted.d.ts +1 -1
- package/dist/boot/hosted.d.ts.map +1 -1
- package/dist/boot/hosted.js +1 -0
- package/dist/boot/hosted.js.map +1 -1
- package/dist/boot/install.d.ts +42 -0
- package/dist/boot/install.d.ts.map +1 -0
- package/dist/boot/install.js +327 -0
- package/dist/boot/install.js.map +1 -0
- package/dist/boot/ownership.d.ts +1 -1
- package/dist/boot/ownership.d.ts.map +1 -1
- package/dist/boot/ownership.js +14 -1
- package/dist/boot/ownership.js.map +1 -1
- package/dist/boot/ports.d.ts +12 -3
- package/dist/boot/ports.d.ts.map +1 -1
- package/dist/boot/ports.js +51 -21
- package/dist/boot/ports.js.map +1 -1
- package/dist/boot/remote.d.ts.map +1 -1
- package/dist/boot/remote.js +3 -3
- package/dist/boot/remote.js.map +1 -1
- package/dist/boot/seed.d.ts +7 -1
- package/dist/boot/seed.d.ts.map +1 -1
- package/dist/boot/seed.js +7 -2
- package/dist/boot/seed.js.map +1 -1
- package/dist/boot/statement-drift.d.ts +1 -1
- package/dist/boot/statement-drift.d.ts.map +1 -1
- package/dist/boot/together.d.ts +1 -1
- package/dist/boot/together.d.ts.map +1 -1
- package/dist/boot/together.js +1 -1
- package/dist/boot/together.js.map +1 -1
- package/dist/boot/types.d.ts +18 -3
- package/dist/boot/types.d.ts.map +1 -1
- package/dist/builtin/LogLine.d.ts +38 -0
- package/dist/builtin/LogLine.d.ts.map +1 -0
- package/dist/builtin/LogLine.js +37 -0
- package/dist/builtin/LogLine.js.map +1 -0
- package/dist/builtin/logger.d.ts +57 -0
- package/dist/builtin/logger.d.ts.map +1 -1
- package/dist/builtin/logger.js +72 -17
- package/dist/builtin/logger.js.map +1 -1
- package/dist/config-loader.d.ts +3 -2
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js.map +1 -1
- package/dist/contract.d.ts +3 -7
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +3 -4
- package/dist/contract.js.map +1 -1
- package/dist/{scan/conventions.d.ts → conventions.d.ts} +6 -0
- package/dist/conventions.d.ts.map +1 -0
- package/dist/{scan/conventions.js → conventions.js} +3 -2
- package/dist/conventions.js.map +1 -0
- package/dist/crypto/encoding.d.ts +0 -1
- package/dist/crypto/encoding.d.ts.map +1 -1
- package/dist/crypto/encoding.js +0 -7
- package/dist/crypto/encoding.js.map +1 -1
- package/dist/declare.d.ts +11 -1
- package/dist/declare.d.ts.map +1 -1
- package/dist/declare.js +10 -1
- package/dist/declare.js.map +1 -1
- package/dist/descriptor/frond.d.ts +34 -0
- package/dist/descriptor/frond.d.ts.map +1 -1
- package/dist/descriptor/index.d.ts +15 -0
- package/dist/descriptor/index.d.ts.map +1 -0
- package/dist/descriptor/index.js +14 -0
- package/dist/descriptor/index.js.map +1 -0
- package/dist/descriptor/surface.d.ts +8 -0
- package/dist/descriptor/surface.d.ts.map +1 -0
- package/dist/descriptor/surface.js +16 -0
- package/dist/descriptor/surface.js.map +1 -0
- package/dist/dispatch/ArgumentResolver.d.ts.map +1 -1
- package/dist/dispatch/ArgumentResolver.js +6 -2
- package/dist/dispatch/ArgumentResolver.js.map +1 -1
- package/dist/dispatch/HandlerFacade.d.ts +2 -0
- package/dist/dispatch/HandlerFacade.d.ts.map +1 -1
- package/dist/dispatch/HandlerFacade.js +9 -4
- package/dist/dispatch/HandlerFacade.js.map +1 -1
- package/dist/dispatch/StorageGuard.d.ts.map +1 -1
- package/dist/dispatch/StorageGuard.js +9 -23
- package/dist/dispatch/StorageGuard.js.map +1 -1
- package/dist/dispatch/presenterArguments.d.ts +7 -1
- package/dist/dispatch/presenterArguments.d.ts.map +1 -1
- package/dist/dispatch/presenterArguments.js +15 -4
- package/dist/dispatch/presenterArguments.js.map +1 -1
- package/dist/dispatch/validateInput.d.ts.map +1 -1
- package/dist/dispatch/validateInput.js +2 -2
- package/dist/dispatch/validateInput.js.map +1 -1
- package/dist/effective-operation.d.ts +1 -1
- package/dist/effective-operation.d.ts.map +1 -1
- package/dist/effective-operation.js +13 -19
- package/dist/effective-operation.js.map +1 -1
- package/dist/frond-config.d.ts +24 -0
- package/dist/frond-config.d.ts.map +1 -1
- package/dist/frond-config.js.map +1 -1
- package/dist/index.d.ts +35 -40
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -14
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +2 -12
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +2 -12
- package/dist/node.js.map +1 -1
- package/dist/prefab/crud.d.ts +1 -1
- package/dist/prefab/crud.d.ts.map +1 -1
- package/dist/prefab/mirror.d.ts +10 -11
- package/dist/prefab/mirror.d.ts.map +1 -1
- package/dist/prefab/mirror.js +1 -27
- package/dist/prefab/mirror.js.map +1 -1
- package/dist/prefab/repository.d.ts +1 -1
- package/dist/prefab/repository.d.ts.map +1 -1
- package/dist/{scan/result.d.ts → scan.d.ts} +2 -2
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +2 -0
- package/dist/scan.js.map +1 -0
- package/dist/source.d.ts +1 -1
- package/dist/source.d.ts.map +1 -1
- package/dist/storage/criterion.d.ts.map +1 -0
- package/dist/{criterion.js → storage/criterion.js} +2 -2
- package/dist/storage/criterion.js.map +1 -0
- package/dist/{storage.d.ts → storage/port.d.ts} +6 -3
- package/dist/storage/port.d.ts.map +1 -0
- package/dist/{storage.js → storage/port.js} +13 -6
- package/dist/storage/port.js.map +1 -0
- package/dist/{store.d.ts → storage/store.d.ts} +1 -1
- package/dist/storage/store.d.ts.map +1 -0
- package/dist/{store.js → storage/store.js} +33 -17
- package/dist/storage/store.js.map +1 -0
- package/dist/verify.js +1 -1
- package/dist/verify.js.map +1 -1
- package/dist/wire/Invocation.d.ts +1 -3
- package/dist/wire/Invocation.d.ts.map +1 -1
- package/dist/wire/Invocation.js +1 -5
- package/dist/wire/Invocation.js.map +1 -1
- package/dist/wire/binding.d.ts +9 -0
- package/dist/wire/binding.d.ts.map +1 -1
- package/dist/wire/binding.js +11 -6
- package/dist/wire/binding.js.map +1 -1
- package/dist/wire/emit.d.ts +45 -0
- package/dist/wire/emit.d.ts.map +1 -0
- package/dist/wire/emit.js +44 -0
- package/dist/wire/emit.js.map +1 -0
- package/dist/wire/errors.js +2 -2
- package/dist/wire/errors.js.map +1 -1
- package/dist/wire/loggerMiddleware.d.ts.map +1 -1
- package/dist/wire/loggerMiddleware.js +6 -0
- package/dist/wire/loggerMiddleware.js.map +1 -1
- package/package.json +10 -4
- package/src/boot/AppLifecycle.ts +8 -0
- package/src/boot/Emissions.ts +177 -9
- package/src/boot/auth.ts +1 -1
- package/src/boot/bootstrap.ts +456 -672
- package/src/boot/card.ts +1 -1
- package/src/boot/hosted.ts +4 -2
- package/src/boot/install.ts +421 -0
- package/src/boot/ownership.ts +17 -2
- package/src/boot/ports.ts +71 -27
- package/src/boot/remote.ts +3 -3
- package/src/boot/seed.ts +18 -3
- package/src/boot/statement-drift.ts +1 -1
- package/src/boot/together.ts +1 -1
- package/src/boot/types.ts +18 -3
- package/src/builtin/LogLine.ts +38 -0
- package/src/builtin/logger.ts +109 -17
- package/src/config-loader.ts +3 -2
- package/src/contract.ts +5 -9
- package/src/{scan/conventions.ts → conventions.ts} +9 -2
- package/src/crypto/encoding.ts +0 -7
- package/src/declare.ts +20 -2
- package/src/descriptor/frond.ts +31 -0
- package/src/descriptor/index.ts +15 -0
- package/src/descriptor/surface.ts +23 -0
- package/src/dispatch/ArgumentResolver.ts +6 -2
- package/src/dispatch/HandlerFacade.ts +11 -4
- package/src/dispatch/StorageGuard.ts +8 -21
- package/src/dispatch/presenterArguments.ts +21 -9
- package/src/dispatch/validateInput.ts +2 -2
- package/src/effective-operation.ts +16 -21
- package/src/frond-config.ts +20 -0
- package/src/index.ts +44 -57
- package/src/node.ts +2 -16
- package/src/prefab/crud.ts +1 -1
- package/src/prefab/mirror.ts +12 -38
- package/src/prefab/repository.ts +1 -1
- package/src/{scan/result.ts → scan.ts} +1 -1
- package/src/source.ts +1 -1
- package/src/{criterion.ts → storage/criterion.ts} +2 -2
- package/src/{storage.ts → storage/port.ts} +20 -5
- package/src/{store.ts → storage/store.ts} +35 -16
- package/src/verify.ts +1 -1
- package/src/wire/Invocation.ts +2 -7
- package/src/wire/binding.ts +17 -6
- package/src/wire/call.ts +1 -1
- package/src/wire/emit.ts +84 -0
- package/src/wire/errors.ts +2 -2
- package/src/wire/loggerMiddleware.ts +6 -0
- package/dist/boot/boot.d.ts +0 -45
- package/dist/boot/boot.d.ts.map +0 -1
- package/dist/boot/boot.js +0 -63
- package/dist/boot/boot.js.map +0 -1
- package/dist/criterion.d.ts.map +0 -1
- package/dist/criterion.js.map +0 -1
- package/dist/declarations.d.ts +0 -34
- package/dist/declarations.d.ts.map +0 -1
- package/dist/declarations.js +0 -75
- package/dist/declarations.js.map +0 -1
- package/dist/emit.d.ts +0 -13
- package/dist/emit.d.ts.map +0 -1
- package/dist/emit.js +0 -21
- package/dist/emit.js.map +0 -1
- package/dist/imports.d.ts +0 -16
- package/dist/imports.d.ts.map +0 -1
- package/dist/imports.js +0 -78
- package/dist/imports.js.map +0 -1
- package/dist/placement.d.ts +0 -25
- package/dist/placement.d.ts.map +0 -1
- package/dist/placement.js +0 -69
- package/dist/placement.js.map +0 -1
- package/dist/scan/adapters.d.ts +0 -3
- package/dist/scan/adapters.d.ts.map +0 -1
- package/dist/scan/adapters.js +0 -25
- package/dist/scan/adapters.js.map +0 -1
- package/dist/scan/bundling.d.ts +0 -3
- package/dist/scan/bundling.d.ts.map +0 -1
- package/dist/scan/bundling.js +0 -15
- package/dist/scan/bundling.js.map +0 -1
- package/dist/scan/contract.d.ts +0 -27
- package/dist/scan/contract.d.ts.map +0 -1
- package/dist/scan/contract.js +0 -46
- package/dist/scan/contract.js.map +0 -1
- package/dist/scan/conventions.d.ts.map +0 -1
- package/dist/scan/conventions.js.map +0 -1
- package/dist/scan/emit.d.ts +0 -10
- package/dist/scan/emit.d.ts.map +0 -1
- package/dist/scan/emit.js +0 -144
- package/dist/scan/emit.js.map +0 -1
- package/dist/scan/handler-parser.d.ts +0 -26
- package/dist/scan/handler-parser.d.ts.map +0 -1
- package/dist/scan/handler-parser.js +0 -607
- package/dist/scan/handler-parser.js.map +0 -1
- package/dist/scan/result.d.ts.map +0 -1
- package/dist/scan/result.js +0 -2
- package/dist/scan/result.js.map +0 -1
- package/dist/scan/scanner.d.ts +0 -12
- package/dist/scan/scanner.d.ts.map +0 -1
- package/dist/scan/scanner.js +0 -573
- package/dist/scan/scanner.js.map +0 -1
- package/dist/scan/statement.d.ts +0 -4
- package/dist/scan/statement.d.ts.map +0 -1
- package/dist/scan/statement.js +0 -135
- package/dist/scan/statement.js.map +0 -1
- package/dist/storage.d.ts.map +0 -1
- package/dist/storage.js.map +0 -1
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js.map +0 -1
- package/src/boot/boot.ts +0 -110
- package/src/declarations.ts +0 -110
- package/src/emit.ts +0 -32
- package/src/imports.ts +0 -94
- package/src/placement.ts +0 -86
- package/src/scan/adapters.ts +0 -32
- package/src/scan/bundling.ts +0 -14
- package/src/scan/contract.ts +0 -80
- package/src/scan/emit.ts +0 -160
- package/src/scan/handler-parser.ts +0 -695
- package/src/scan/scanner.ts +0 -698
- package/src/scan/statement.ts +0 -159
- /package/dist/{criterion.d.ts → storage/criterion.d.ts} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { COMPARISONS, comparisonOf, unknownIn } from '../criterion.js';
|
|
3
|
-
import { assertListOptions } from '../storage.js';
|
|
1
|
+
import { FieldSet, FieldValueValidator, InputRefusal, type Fields } from '@fougere/schema';
|
|
2
|
+
import { COMPARISONS, comparisonOf, unknownIn } from '../storage/criterion.js';
|
|
3
|
+
import { assertListOptions } from '../storage/port.js';
|
|
4
4
|
import { ErrorCode, FougereError } from '../wire/errors.js';
|
|
5
5
|
|
|
6
6
|
/** The gestures this guard grafts onto. */
|
|
@@ -70,7 +70,7 @@ export class StorageGuard {
|
|
|
70
70
|
if (typeof list === 'function') {
|
|
71
71
|
guarded.list = async function (...args: unknown[]) {
|
|
72
72
|
const options = args[0] as { where?: Record<string, unknown> } | undefined;
|
|
73
|
-
assertListOptions(options, validation.entity);
|
|
73
|
+
assertListOptions(options, validation.entity, Object.keys(validation.fields));
|
|
74
74
|
if (options?.where) args[0] = { ...options, where: validation.criteria(options.where) };
|
|
75
75
|
|
|
76
76
|
return list.apply(this, args);
|
|
@@ -169,11 +169,7 @@ export class StorageGuard {
|
|
|
169
169
|
/** One value against one field — validated, then decoded the way the wire hands it. */
|
|
170
170
|
private value(field: Fields[string], asked: unknown): { value: unknown } | { error: string } {
|
|
171
171
|
if (asked === null || asked === undefined) return { value: asked };
|
|
172
|
-
|
|
173
|
-
if ('error' in checked) return checked;
|
|
174
|
-
if (checked.value === null) return { value: null };
|
|
175
|
-
|
|
176
|
-
return Boundary.of(field).decode(checked.value);
|
|
172
|
+
return FieldValueValidator.of(field).parse(asked);
|
|
177
173
|
}
|
|
178
174
|
|
|
179
175
|
private validated<T>(value: T, operation: string, index?: number): T {
|
|
@@ -195,18 +191,9 @@ export class StorageGuard {
|
|
|
195
191
|
parsed[key] = item;
|
|
196
192
|
continue;
|
|
197
193
|
}
|
|
198
|
-
const
|
|
199
|
-
if ('error' in
|
|
200
|
-
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
if (checked.value === null) {
|
|
204
|
-
parsed[key] = null;
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
const decoded = Boundary.of(field).decode(checked.value);
|
|
208
|
-
if ('error' in decoded) errors.push(`${where}${key}: ${decoded.error}`);
|
|
209
|
-
else parsed[key] = decoded.value;
|
|
194
|
+
const value = FieldValueValidator.of(field).parse(item);
|
|
195
|
+
if ('error' in value) errors.push(`${where}${key}: ${value.error}`);
|
|
196
|
+
else parsed[key] = value.value;
|
|
210
197
|
}
|
|
211
198
|
|
|
212
199
|
if (errors.length > 0) {
|
|
@@ -1,24 +1,36 @@
|
|
|
1
|
-
import { computeBindingPlan } from '../wire/binding.js';
|
|
1
|
+
import { computeBindingPlan, type BindingPlan } from '../wire/binding.js';
|
|
2
2
|
import type { InvocationContext } from '../wire/Invocation.js';
|
|
3
3
|
import type { PresenterEntry } from '../descriptor/frond.js';
|
|
4
4
|
import type { ArgumentResolver } from './ArgumentResolver.js';
|
|
5
5
|
import type { PresenterArgs } from './PresenterExecutor.js';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Where each computed field's extra arguments come from — read off the declaration, so a
|
|
9
|
+
* field that takes only the page is absent and asks for nothing.
|
|
10
|
+
*/
|
|
11
|
+
export function presenterPlans(
|
|
12
|
+
meta: PresenterEntry,
|
|
13
|
+
collectorTypes: Set<string>,
|
|
14
|
+
): Map<string, BindingPlan> {
|
|
15
|
+
const plans = new Map<string, BindingPlan>();
|
|
16
|
+
for (const field of meta.fieldMeta) {
|
|
17
|
+
if (!field.params?.length) continue;
|
|
18
|
+
plans.set(field.name, computeBindingPlan(field.params, collectorTypes));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return plans;
|
|
22
|
+
}
|
|
23
|
+
|
|
7
24
|
/** The invocation-dependent arguments of every computed presenter field. */
|
|
8
25
|
export async function presenterArguments(
|
|
9
|
-
|
|
26
|
+
plans: Map<string, BindingPlan>,
|
|
10
27
|
invocation: InvocationContext,
|
|
11
28
|
resolver: ArgumentResolver,
|
|
12
|
-
collectorTypes: Set<string>,
|
|
13
29
|
): Promise<PresenterArgs> {
|
|
14
30
|
const argumentsByField: PresenterArgs = {};
|
|
15
31
|
|
|
16
|
-
for (const field of
|
|
17
|
-
|
|
18
|
-
argumentsByField[field.name] = await resolver.resolve(
|
|
19
|
-
computeBindingPlan(field.params, collectorTypes),
|
|
20
|
-
invocation,
|
|
21
|
-
);
|
|
32
|
+
for (const [field, plan] of plans) {
|
|
33
|
+
argumentsByField[field] = await resolver.resolve(plan, invocation);
|
|
22
34
|
}
|
|
23
35
|
|
|
24
36
|
return argumentsByField;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InputValidator, type SchemaView } from '@fougere/schema';
|
|
1
|
+
import { InputValidator, dotted, type SchemaView } from '@fougere/schema';
|
|
2
2
|
import type { InvocationContext } from '../wire/Invocation.js';
|
|
3
3
|
import { ErrorCode, FougereError } from '../wire/errors.js';
|
|
4
4
|
|
|
@@ -17,7 +17,7 @@ export function validateInput(
|
|
|
17
17
|
if (!result.success) {
|
|
18
18
|
throw new FougereError({
|
|
19
19
|
code: ErrorCode.VALIDATION_FAILED,
|
|
20
|
-
message: result.errors.map((error) => `${error.path}: ${error.message}`).join(', '),
|
|
20
|
+
message: result.errors.map((error) => `${dotted(error.path)}: ${error.message}`).join(', '),
|
|
21
21
|
details: result.errors,
|
|
22
22
|
entity,
|
|
23
23
|
operation,
|
|
@@ -4,7 +4,8 @@ import { statementDrift } from './boot/statement-drift.js';
|
|
|
4
4
|
import { computeBindingPlan, type BindingPlan } from './wire/binding.js';
|
|
5
5
|
import { targetOf } from './prefab/prefab.js';
|
|
6
6
|
import type { CollectorEntry, FrondDescriptor, HandlerEntry } from './descriptor/frond.js';
|
|
7
|
-
import
|
|
7
|
+
import { servedSurfaces } from './descriptor/surface.js';
|
|
8
|
+
import type { ScanDiagnostic } from './scan.js';
|
|
8
9
|
import { verify } from './verify.js';
|
|
9
10
|
import {
|
|
10
11
|
inferOperationKind,
|
|
@@ -228,13 +229,19 @@ export function resolveEffectiveOperations(
|
|
|
228
229
|
|
|
229
230
|
// A fact is validated by the entity it names. This used to be patched into the
|
|
230
231
|
// facade after resolution, leaving check/explain with a different input.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
232
|
+
const announced = contract.binding.find((binding) =>
|
|
233
|
+
binding.source.kind === 'fact' || binding.source.kind === 'pipe');
|
|
234
|
+
const fact = announced?.source.kind === 'fact' || announced?.source.kind === 'pipe'
|
|
235
|
+
? schemas.get(announced.source.factName)
|
|
236
|
+
: undefined;
|
|
237
|
+
const input = contract.input ?? fact;
|
|
238
|
+
|
|
239
|
+
// An op that FINISHES a fact answers the fact, so its answer is the fact's shape:
|
|
240
|
+
// derived here, where its input already is. Left to the ordinary projection it
|
|
241
|
+
// came back stripped — measured, the subscriber got a value with no `id`.
|
|
242
|
+
const output = announced?.source.kind === 'pipe' && fact
|
|
243
|
+
? { schema: fact, closed: false }
|
|
244
|
+
: effectiveOutput(frond, handler, name, contract);
|
|
238
245
|
const className = handler.ctor.name.endsWith('Handler')
|
|
239
246
|
? handler.ctor.name.slice(0, -'Handler'.length)
|
|
240
247
|
: handler.ctor.name;
|
|
@@ -279,7 +286,7 @@ export function resolveEffectiveOperations(
|
|
|
279
286
|
...(remote ? { remote } : {}),
|
|
280
287
|
},
|
|
281
288
|
exposure: {
|
|
282
|
-
surfaces:
|
|
289
|
+
surfaces: servedSurfaces(frond, handler).map((surface) => surface ?? 'default'),
|
|
283
290
|
adapters: exposedAdapters(handler, options.adapters),
|
|
284
291
|
},
|
|
285
292
|
outputClosed: output.closed,
|
|
@@ -557,18 +564,6 @@ function effectiveOutput(
|
|
|
557
564
|
return { ...(entity ? { schema: entity.entityClass } : {}), closed: false };
|
|
558
565
|
}
|
|
559
566
|
|
|
560
|
-
function surfacesOf(frond: FrondDescriptor, handler: HandlerEntry): string[] {
|
|
561
|
-
if (handler.surface) return [handler.surface];
|
|
562
|
-
const surfaces = ['default'];
|
|
563
|
-
for (const [surface, addresses] of Object.entries(frond.surfaces ?? {})) {
|
|
564
|
-
const dedicated = frond.handlers.some((candidate) =>
|
|
565
|
-
candidate.address === handler.address && candidate.surface === surface);
|
|
566
|
-
if (!dedicated && addresses.some((address) =>
|
|
567
|
-
address.toLowerCase() === handler.address.toLowerCase())) surfaces.push(surface);
|
|
568
|
-
}
|
|
569
|
-
return [surfaces[0]!, ...surfaces.slice(1).sort()];
|
|
570
|
-
}
|
|
571
|
-
|
|
572
567
|
function exposedAdapters(
|
|
573
568
|
handler: HandlerEntry,
|
|
574
569
|
adapters: Record<string, boolean | undefined> | undefined,
|
package/src/frond-config.ts
CHANGED
|
@@ -11,6 +11,12 @@ export interface OperationOverride {
|
|
|
11
11
|
kind?: 'query' | 'command';
|
|
12
12
|
/** The GraphQL root field this op answers to. */
|
|
13
13
|
graphql?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Where this op answers over REST — the dual of `graphql:`, and the frond's to say for
|
|
16
|
+
* the same reason: how an operation is CALLED belongs beside it, not in whatever host
|
|
17
|
+
* mounts the router. The prefix stays the host's: naming is the frond's, mounting is not.
|
|
18
|
+
*/
|
|
19
|
+
rest?: { method?: string; path?: string; status?: number };
|
|
14
20
|
/**
|
|
15
21
|
* Handler class to delegate to (overrides the default `{Entity}Handler` lookup).
|
|
16
22
|
* Class name is used to resolve from DI. E.g. `ArchiveHandler` → `app.resolve('ArchiveHandler')`.
|
|
@@ -44,6 +50,20 @@ export interface FrondConfig {
|
|
|
44
50
|
surfaces?: Record<string, string[]>;
|
|
45
51
|
/** Interface → implementation bindings for DI (e.g. { Database: 'SqliteDatabase' }). */
|
|
46
52
|
bindings?: Record<string, string>;
|
|
53
|
+
/**
|
|
54
|
+
* The ops that FINISH a fact, in the order they run — by class name, keyed by fact.
|
|
55
|
+
*
|
|
56
|
+
* Declared by the frond that OWNS the fact, because ordering is a decision about the
|
|
57
|
+
* fact itself and it has one owner. Without it two links refuse: nothing would say which
|
|
58
|
+
* ran first, and scan order is not an answer.
|
|
59
|
+
*/
|
|
60
|
+
pipes?: Record<string, string[]>;
|
|
61
|
+
/**
|
|
62
|
+
* How far a middleware reaches, by class name. A middleware answers for its own frond
|
|
63
|
+
* without being named here; `'app'` is the exception, and it is stated by the frond
|
|
64
|
+
* that decides for the others.
|
|
65
|
+
*/
|
|
66
|
+
middlewares?: Record<string, 'frond' | 'app'>;
|
|
47
67
|
/** Per-operation overrides. Key = operation name (method name on a handler). */
|
|
48
68
|
operations?: Record<string, OperationOverride>;
|
|
49
69
|
}
|
package/src/index.ts
CHANGED
|
@@ -4,93 +4,84 @@ export { orderSeeds, runSeeds, seeding } from './boot/seed.js';
|
|
|
4
4
|
export { AppLifecycle, migrating } from './boot/AppLifecycle.js';
|
|
5
5
|
export type { Extension } from './boot/AppLifecycle.js';
|
|
6
6
|
export { defineFougere } from './define.js';
|
|
7
|
-
export type {
|
|
8
|
-
export type {
|
|
7
|
+
export type { FougereConfig, AdapterConfig } from './config-loader.js';
|
|
8
|
+
export type { OperationOverride, FrondConfig } from './frond-config.js';
|
|
9
9
|
export { buildGraph, clusterEntities, suggestSplit, type EntityNode, type DomainCluster } from './graph.js';
|
|
10
10
|
export { Crud } from './prefab/crud.js';
|
|
11
|
-
export type { CrudOps, CrudOpName,
|
|
11
|
+
export type { CrudViews, CrudOps, CrudOpName, CrudConstructor } from './prefab/crud.js';
|
|
12
12
|
export { Mirror } from './prefab/mirror.js';
|
|
13
|
-
export type { MirrorOf, MirrorConstructor
|
|
13
|
+
export type { Refreshed, MirrorOf, MirrorConstructor } from './prefab/mirror.js';
|
|
14
14
|
export { Presenter } from './prefab/presenter.js';
|
|
15
15
|
export type { PresenterViews } from './prefab/presenter.js';
|
|
16
16
|
export { Collector } from './prefab/collector.js';
|
|
17
17
|
export { Repository, type RepositoryOf, type RepositoryConstructor, type AggregateOf, type AggregateConstructor } from './prefab/repository.js';
|
|
18
|
-
export { Invocation
|
|
19
|
-
export type { InvocationContext
|
|
20
|
-
export { Call } from './
|
|
21
|
-
export { RouteAddress } from './
|
|
22
|
-
export type { RouteAddressInput } from './wire/RouteAddress.js';
|
|
18
|
+
export { Invocation } from './contract.js';
|
|
19
|
+
export type { InvocationContext } from './contract.js';
|
|
20
|
+
export { Call } from './contract.js';
|
|
21
|
+
export { RouteAddress } from './contract.js';
|
|
23
22
|
export { DispatchLifecycle } from './dispatch/DispatchLifecycle.js';
|
|
24
23
|
export { Dispatcher } from './dispatch/Dispatcher.js';
|
|
25
24
|
// The class and not only its type: an observer RECEIVES these, so a package that folds
|
|
26
25
|
// them — or a test of one — has to be able to make one through the door.
|
|
27
26
|
export { DispatchEvent } from './dispatch/DispatchEvent.js';
|
|
28
|
-
export type { CallPage, CallRecord } from './
|
|
29
|
-
export { driftOf, agrees, explain, type CardDrift } from './
|
|
30
|
-
export type { DispatchObserver } from './dispatch/DispatchEvent.js';
|
|
31
|
-
export type { DispatchPort } from './dispatch/DispatchPort.js';
|
|
32
|
-
export {
|
|
33
|
-
inferOperationKind,
|
|
34
|
-
resolveIsReadOp,
|
|
35
|
-
resolveOperationKind,
|
|
36
|
-
} from './wire/operation.js';
|
|
37
|
-
export { resolveContracts } from './effective-operation.js';
|
|
27
|
+
export type { CallPage, CallRecord } from './contract.js';
|
|
28
|
+
export { driftOf, agrees, explain, type CardDrift } from './contract.js';
|
|
38
29
|
export type {
|
|
39
30
|
OperationContract,
|
|
40
|
-
OperationKind,
|
|
41
|
-
OperationKindInference,
|
|
42
31
|
OperationsMap,
|
|
43
32
|
Param,
|
|
44
33
|
TypeRef,
|
|
45
34
|
} from './wire/operation.js';
|
|
46
|
-
export {
|
|
47
|
-
|
|
48
|
-
EffectiveOperationModel,
|
|
49
|
-
resolveEffectiveOperations,
|
|
50
|
-
} from './effective-operation.js';
|
|
51
|
-
export type {
|
|
52
|
-
EffectiveCollector,
|
|
53
|
-
EffectiveOperation,
|
|
54
|
-
EffectiveOperationOptions,
|
|
55
|
-
EffectiveOperationsMap,
|
|
56
|
-
EffectiveParameter,
|
|
57
|
-
} from './effective-operation.js';
|
|
35
|
+
export { resolveEffectiveOperations } from './effective-operation.js';
|
|
36
|
+
export type { EffectiveOperation } from './effective-operation.js';
|
|
58
37
|
export type { ModuleLoader } from './loader.js';
|
|
59
|
-
export { FougereError, ErrorCode, validationErrorsOf
|
|
60
|
-
export type { OperationContext, AppNext
|
|
61
|
-
export { assertIdentityCard, RPC_ENTITY, MAX_BODY_BYTES } from './
|
|
38
|
+
export { FougereError, ErrorCode, validationErrorsOf } from './contract.js';
|
|
39
|
+
export type { AppMiddleware, OperationContext, AppNext } from './wire/middleware.js';
|
|
40
|
+
export { assertIdentityCard, RPC_ENTITY, MAX_BODY_BYTES } from './contract.js';
|
|
62
41
|
export { createLocalRunner, createAppRunner } from './boot/runner.js';
|
|
63
42
|
|
|
64
43
|
// A frond an app STATES, for a boot that will not scan. No disk, no `typescript` — which
|
|
65
44
|
// is why it sits here and not in `/node`, beside the scanner that reads a project.
|
|
66
45
|
export { frond } from './declare.js';
|
|
67
|
-
export type {
|
|
46
|
+
export type { Declared, FrondDeclaration, DeclaredSubject } from './declare.js';
|
|
68
47
|
// What this app would answer to `rpc.discover`. Served by the boot, and reached until now
|
|
69
48
|
// only by tests through a deep path — a consumer comparing its own card to a producer's
|
|
70
49
|
// had to dispatch a call to ask a question about itself.
|
|
71
50
|
export { identityCardOf } from './boot/card.js';
|
|
51
|
+
export type { Facade } from './wire/call.js';
|
|
72
52
|
export type {
|
|
73
|
-
FrondCall,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
53
|
+
FrondCall,
|
|
54
|
+
Transport,
|
|
55
|
+
IdentityCard,
|
|
56
|
+
CardOp,
|
|
57
|
+
TopologyReport,
|
|
58
|
+
FrondPlacement,
|
|
59
|
+
Edge,
|
|
60
|
+
} from './contract.js';
|
|
61
|
+
export { type Emit, type Fact, type Pipe } from './wire/emit.js';
|
|
77
62
|
export { callValueOf } from './contract.js';
|
|
78
|
-
export
|
|
79
|
-
export {
|
|
63
|
+
export { toHttpError } from './wire/http-error.js';
|
|
64
|
+
export { toPublicError } from './contract.js';
|
|
80
65
|
export { loggerMiddleware } from './wire/loggerMiddleware.js';
|
|
81
|
-
export { Logger, setLogLevel, logLevel, envLevel, onLog } from './builtin/logger.js';
|
|
82
|
-
export type {
|
|
66
|
+
export { Carry, Logger, setLogLevel, logLevel, envLevel, onLog, formatted } from './builtin/logger.js';
|
|
67
|
+
export type { LogRecord, Rendered, LogSink } from './builtin/logger.js';
|
|
68
|
+
// The fact a boot announces. Its destinations are `@fougere/log`'s; the line is core's.
|
|
69
|
+
export { default as LogLine, CARRIES_LINE, LOG_LINE } from './builtin/LogLine.js';
|
|
83
70
|
// What a re-read config changes in a running process — and what it cannot.
|
|
84
|
-
export { applyConfig
|
|
71
|
+
export { applyConfig } from './boot/apply.js';
|
|
85
72
|
export { Config } from './builtin/config.js';
|
|
86
|
-
export type { Storage, StorageFactory, ListOptions, ListResult, Together } from './storage.js';
|
|
87
|
-
export { togetherKeyOf
|
|
73
|
+
export type { Storage, StorageFactory, ListOptions, ListResult, Together } from './storage/port.js';
|
|
74
|
+
export { togetherKeyOf } from './storage/port.js';
|
|
88
75
|
export type { Constraint, Source, SourceConfig, SourceView } from './source.js';
|
|
89
76
|
export { Sources } from './source.js';
|
|
90
|
-
export { storageOver } from './store.js';
|
|
91
|
-
export type { Store, Values } from './store.js';
|
|
77
|
+
export { storageOver } from './storage/store.js';
|
|
78
|
+
export type { Store, Values } from './storage/store.js';
|
|
92
79
|
export type { App, CreateAppOptions } from './boot/types.js';
|
|
93
|
-
export type { ScanResult, ScanDiagnostic } from './scan
|
|
80
|
+
export type { ScanResult, ScanDiagnostic } from './scan.js';
|
|
81
|
+
export {
|
|
82
|
+
type Conventions, type ConventionsInput, DEFAULT_CONVENTIONS,
|
|
83
|
+
resolveConventions, frondPackage, frondDirsOf, providerDirsOf,
|
|
84
|
+
} from './conventions.js';
|
|
94
85
|
export type {
|
|
95
86
|
FrondDescriptor,
|
|
96
87
|
FrondSource,
|
|
@@ -98,20 +89,16 @@ export type {
|
|
|
98
89
|
EntityEntry,
|
|
99
90
|
HandlerEntry,
|
|
100
91
|
SeedEntry,
|
|
101
|
-
SeedFactory,
|
|
102
92
|
PresenterEntry,
|
|
103
93
|
PresenterFieldMeta,
|
|
104
94
|
CollectorEntry,
|
|
105
95
|
} from './descriptor/frond.js';
|
|
106
96
|
export type { AuthConfig, AuthContext, AuthRuntime } from './boot/auth.js';
|
|
107
97
|
export { Fronds } from './descriptor/Fronds.js';
|
|
108
|
-
export { verify,
|
|
98
|
+
export { verify, type Violation } from './verify.js';
|
|
109
99
|
// Same question as verify(), answered from the source text instead of the model.
|
|
110
|
-
export type { CrossFrondImport } from './imports.js';
|
|
111
|
-
export type { HandlerDeclaration } from './declarations.js';
|
|
112
|
-
export type { OutsideConvention } from './placement.js';
|
|
113
100
|
// Who is calling, established rather than accepted — the proof beside `state`'s claim.
|
|
114
101
|
// `generateKeyPair` and `issueGrant` are NOT here: they make keys at a deployment and
|
|
115
102
|
// need `node:crypto` for a gesture WebCrypto has no equal of. They sit on `/node`.
|
|
116
103
|
export { signEnvelope, verifyEnvelope, identityFromEnv } from './identity.js';
|
|
117
|
-
export type { FrondIdentity,
|
|
104
|
+
export type { FrondIdentity, SignedCall } from './identity.js';
|
package/src/node.ts
CHANGED
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
/** What Fougere does with a filesystem
|
|
2
|
-
export { boot } from './boot/boot.js';
|
|
3
|
-
|
|
4
|
-
export { scanProject, frondAliases, watchPathsOf } from './scan/scanner.js';
|
|
5
|
-
export {
|
|
6
|
-
type Conventions, type ConventionsInput, DEFAULT_CONVENTIONS,
|
|
7
|
-
resolveConventions, frondPackage, frondDirsOf, providerDirsOf,
|
|
8
|
-
} from './scan/conventions.js';
|
|
9
|
-
export { RUNTIME_PACKAGES } from './scan/bundling.js';
|
|
10
|
-
export { emitScan, type EmitOptions } from './scan/emit.js';
|
|
11
|
-
export { emitStatement } from './scan/statement.js';
|
|
1
|
+
/** What Fougere does with a filesystem, minus the scan — that is `@fougere/compiler`. */
|
|
12
2
|
export { setModuleLoader, getModuleLoader } from './loader.js';
|
|
13
3
|
export { loadConfig, loadCascadedConfig } from './config-loader.js';
|
|
14
|
-
export { defineFrond } from './frond-config.js';
|
|
15
|
-
export { crossFrondImports } from './imports.js';
|
|
16
|
-
export { handlerDeclarations } from './declarations.js';
|
|
17
|
-
export { outsideConventions } from './placement.js';
|
|
18
|
-
export { adaptersOf } from './scan/adapters.js';
|
|
4
|
+
export { defineFrond, loadFrondConfig } from './frond-config.js';
|
|
19
5
|
|
|
20
6
|
// Making a key and binding a name to it happen once, at a deployment, on a machine with
|
|
21
7
|
// a filesystem — the CLI speaking. Verifying happens per call, everywhere, and stays on
|
package/src/prefab/crud.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { lowerFirst, type EntityConstructor, type SchemaView } from '@fougere/schema';
|
|
2
|
-
import type { Storage, ListOptions, ListResult } from '../storage.js';
|
|
2
|
+
import type { Storage, ListOptions, ListResult } from '../storage/port.js';
|
|
3
3
|
import type { OperationContract } from '../wire/operation.js';
|
|
4
4
|
import { targetOf } from './prefab.js';
|
|
5
5
|
|
package/src/prefab/mirror.ts
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Storage } from '../storage.js';
|
|
1
|
+
import type { EntityConstructor } from '@fougere/schema';
|
|
2
|
+
import type { Storage } from '../storage/port.js';
|
|
3
3
|
|
|
4
|
-
/** A paginated local copy of a source that cannot be queried directly. */
|
|
5
4
|
/** What one refresh did — enough to log it, and to decide whether to run again. */
|
|
6
5
|
export interface Refreshed {
|
|
7
6
|
/** Instances written, counting a replaced one once. */
|
|
8
7
|
written: number;
|
|
9
|
-
/** The age the pull was asked to start from — absent
|
|
8
|
+
/** The age the pull was asked to start from — absent when it asked for everything. */
|
|
10
9
|
since?: Date;
|
|
11
10
|
/** How long the whole pass took, pull included. */
|
|
12
11
|
ms: number;
|
|
13
12
|
}
|
|
14
13
|
|
|
14
|
+
/** A paginated local copy of a source that cannot be queried directly. */
|
|
15
15
|
export interface MirrorOf<T> {
|
|
16
|
-
/** The copy's own storage — where a page lands
|
|
16
|
+
/** The copy's own storage — where a page lands. */
|
|
17
17
|
storage: Storage<T>;
|
|
18
18
|
/** Pages of rows to write. The one thing a mirror's author supplies. */
|
|
19
19
|
pull(since?: Date): AsyncIterable<Partial<T>[]>;
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Pull from `since` and write every page. The mark is the CALLER's: only it knows
|
|
22
|
+
* whether a pass completed, and a pass that throws must not advance it.
|
|
23
|
+
*/
|
|
24
|
+
refresh(since?: Date): Promise<Refreshed>;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export interface MirrorConstructor<T> {
|
|
@@ -31,16 +32,6 @@ export interface MirrorConstructor<T> {
|
|
|
31
32
|
export function Mirror<E extends EntityConstructor>(shape: E): MirrorConstructor<InstanceType<E>> {
|
|
32
33
|
type T = InstanceType<E>;
|
|
33
34
|
|
|
34
|
-
// Refuse an undated copy before it can be used as if it held live rows.
|
|
35
|
-
const declared = ageFieldOf(shape);
|
|
36
|
-
if (declared === undefined) {
|
|
37
|
-
throw new Error(
|
|
38
|
-
`Mirror(${(shape as { name?: string }).name ?? '?'}): the shape carries no \`updated()\` field — ` +
|
|
39
|
-
`a copy has to be able to say when it was pulled, and \`refresh\` reads its high-water mark from it.`,
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
const age: string = declared;
|
|
43
|
-
|
|
44
35
|
abstract class MirrorBase implements MirrorOf<T> {
|
|
45
36
|
static readonly __entity = shape;
|
|
46
37
|
|
|
@@ -48,35 +39,18 @@ export function Mirror<E extends EntityConstructor>(shape: E): MirrorConstructor
|
|
|
48
39
|
|
|
49
40
|
abstract pull(since?: Date): AsyncIterable<Partial<T>[]>;
|
|
50
41
|
|
|
51
|
-
|
|
52
|
-
async freshness(): Promise<Date | undefined> {
|
|
53
|
-
const [newest] = await this.storage.list({ orderBy: age, order: 'desc', limit: 1 });
|
|
54
|
-
const value = (newest as Record<string, unknown> | undefined)?.[age];
|
|
55
|
-
return value instanceof Date ? value : undefined;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async refresh(): Promise<Refreshed> {
|
|
42
|
+
async refresh(since?: Date): Promise<Refreshed> {
|
|
59
43
|
const started = Date.now();
|
|
60
|
-
const since = await this.freshness();
|
|
61
44
|
let written = 0;
|
|
62
45
|
// Preserve the source's page boundaries: one page becomes one upsert.
|
|
63
46
|
for await (const page of this.pull(since)) {
|
|
64
47
|
if (page.length === 0) continue;
|
|
65
48
|
written += await this.storage.upsertAll(page);
|
|
66
49
|
}
|
|
50
|
+
|
|
67
51
|
return { written, since, ms: Date.now() - started };
|
|
68
52
|
}
|
|
69
53
|
}
|
|
70
54
|
|
|
71
55
|
return MirrorBase as unknown as MirrorConstructor<T>;
|
|
72
56
|
}
|
|
73
|
-
|
|
74
|
-
/** The field whose lifecycle stamps every update. */
|
|
75
|
-
export function ageFieldOf(shape: unknown): string | undefined {
|
|
76
|
-
const fields = (shape as { getFields?: () => Fields }).getFields?.();
|
|
77
|
-
if (!fields) return undefined;
|
|
78
|
-
for (const [name, field] of Object.entries(fields)) {
|
|
79
|
-
if (Lifecycle.of(field).stampedOnUpdate) return name;
|
|
80
|
-
}
|
|
81
|
-
return undefined;
|
|
82
|
-
}
|
package/src/prefab/repository.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { upperFirst, type EntityConstructor } from '@fougere/schema';
|
|
2
|
-
import type { Storage, ListOptions, ListResult, SelectOption } from '../storage.js';
|
|
2
|
+
import type { Storage, ListOptions, ListResult, SelectOption } from '../storage/port.js';
|
|
3
3
|
import type { SchemaView } from '@fougere/schema';
|
|
4
4
|
|
|
5
5
|
/** Repository(…entities) — who owns an entity's storage, and where its questions are named. */
|
package/src/source.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Registry, Role, type SchemaView } from '@fougere/schema';
|
|
2
|
-
import type { StorageFactory } from './storage.js';
|
|
2
|
+
import type { StorageFactory } from './storage/port.js';
|
|
3
3
|
|
|
4
4
|
/** A promise the judge at the door cannot keep, because it is about rows it never sees. */
|
|
5
5
|
export type Constraint = 'unique';
|
|
@@ -35,8 +35,8 @@ export type ComparisonName = (typeof COMPARISONS)[number];
|
|
|
35
35
|
*/
|
|
36
36
|
export function comparisonOf(field: Field | undefined, asked: unknown): Comparison | undefined {
|
|
37
37
|
if (asked === null || typeof asked !== 'object' || Array.isArray(asked)) return undefined;
|
|
38
|
-
//
|
|
39
|
-
if (!field || Shapes.
|
|
38
|
+
// The type is read off the base, so `optional(json())` still answers `object`.
|
|
39
|
+
if (!field || Shapes.typeOf(field.shape) === 'object') return undefined;
|
|
40
40
|
|
|
41
41
|
return asked as Comparison;
|
|
42
42
|
}
|
|
@@ -45,15 +45,30 @@ const LIST_OPTION_KEYS = [
|
|
|
45
45
|
'limit', 'offset', 'page', 'after', 'orderBy', 'order', 'count', 'where', 'select',
|
|
46
46
|
] as const;
|
|
47
47
|
|
|
48
|
-
/**
|
|
49
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Refuse an option the port does not answer to, and an order by a field the entity does not
|
|
50
|
+
* declare — an unhonoured `orderBy` returns the page in whatever order the engine chose.
|
|
51
|
+
*/
|
|
52
|
+
export function assertListOptions(
|
|
53
|
+
options: object | undefined,
|
|
54
|
+
entity: string,
|
|
55
|
+
declared: readonly string[],
|
|
56
|
+
): void {
|
|
50
57
|
if (!options) return;
|
|
51
58
|
const legal = new Set<string>(LIST_OPTION_KEYS);
|
|
52
59
|
const strangers = Object.keys(options).filter((key) => !legal.has(key));
|
|
53
|
-
if (strangers.length
|
|
60
|
+
if (strangers.length > 0) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`${entity}.list(): unknown option ${strangers.map((s) => `\`${s}\``).join(', ')}. ` +
|
|
63
|
+
`Known options are ${LIST_OPTION_KEYS.join(', ')} — to filter, pass \`where: { ${strangers[0]}: … }\`.`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const { orderBy } = options as ListOptions;
|
|
68
|
+
if (orderBy === undefined || declared.includes(orderBy)) return;
|
|
69
|
+
|
|
54
70
|
throw new Error(
|
|
55
|
-
`${entity}.list(): unknown
|
|
56
|
-
`Known options are ${LIST_OPTION_KEYS.join(', ')} — to filter, pass \`where: { ${strangers[0]}: … }\`.`,
|
|
71
|
+
`${entity}.list(): unknown orderBy \`${orderBy}\`. ${entity} declares ${declared.join(', ')}.`,
|
|
57
72
|
);
|
|
58
73
|
}
|
|
59
74
|
|