@fougere/core 0.17.4-alpha.0 → 0.18.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/Declared.d.ts +2 -5
- package/dist/Declared.d.ts.map +1 -1
- package/dist/DeclaredHandler.d.ts +3 -8
- package/dist/DeclaredHandler.d.ts.map +1 -1
- package/dist/DeclaredSubject.d.ts +2 -5
- package/dist/DeclaredSubject.d.ts.map +1 -1
- package/dist/EffectiveOperation.d.ts +7 -6
- package/dist/EffectiveOperation.d.ts.map +1 -1
- package/dist/EffectiveOperationModel.d.ts.map +1 -1
- package/dist/EffectiveOperationModel.js +9 -6
- package/dist/EffectiveOperationModel.js.map +1 -1
- package/dist/FrondConfig.d.ts +0 -2
- package/dist/FrondConfig.d.ts.map +1 -1
- package/dist/FrondConfig.js.map +1 -1
- package/dist/FrondDeclaration.d.ts +3 -8
- package/dist/FrondDeclaration.d.ts.map +1 -1
- package/dist/FrondDeclaration.js +2 -1
- package/dist/FrondDeclaration.js.map +1 -1
- package/dist/OperationOverride.d.ts +5 -3
- package/dist/OperationOverride.d.ts.map +1 -1
- package/dist/SourceView.d.ts +10 -8
- package/dist/SourceView.d.ts.map +1 -1
- package/dist/SourceView.js +10 -1
- package/dist/SourceView.js.map +1 -1
- package/dist/boot/bootstrap.d.ts.map +1 -1
- package/dist/boot/bootstrap.js +5 -6
- package/dist/boot/bootstrap.js.map +1 -1
- package/dist/boot/unregistered.d.ts +4 -2
- package/dist/boot/unregistered.d.ts.map +1 -1
- package/dist/boot/unregistered.js +30 -30
- package/dist/boot/unregistered.js.map +1 -1
- package/dist/contract.d.ts +3 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +3 -0
- package/dist/contract.js.map +1 -1
- package/dist/descriptor/CollectorEntry.d.ts +2 -7
- package/dist/descriptor/CollectorEntry.d.ts.map +1 -1
- package/dist/descriptor/FrondDescriptor.d.ts +5 -23
- package/dist/descriptor/FrondDescriptor.d.ts.map +1 -1
- package/dist/descriptor/FrondDescriptor.js.map +1 -1
- package/dist/descriptor/HandlerEntry.d.ts +2 -7
- package/dist/descriptor/HandlerEntry.d.ts.map +1 -1
- package/dist/descriptor/MiddlewareEntry.d.ts +2 -7
- package/dist/descriptor/MiddlewareEntry.d.ts.map +1 -1
- package/dist/descriptor/PresenterEntry.d.ts +2 -7
- package/dist/descriptor/PresenterEntry.d.ts.map +1 -1
- package/dist/descriptor/ProviderEntry.d.ts +2 -7
- package/dist/descriptor/ProviderEntry.d.ts.map +1 -1
- package/dist/descriptor/Subject.d.ts +10 -0
- package/dist/descriptor/Subject.d.ts.map +1 -0
- package/dist/descriptor/Subject.js +2 -0
- package/dist/descriptor/Subject.js.map +1 -0
- package/dist/descriptor/index.d.ts +1 -0
- package/dist/descriptor/index.d.ts.map +1 -1
- package/dist/descriptor/index.js +1 -0
- package/dist/descriptor/index.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/prefab/AggregateConstructor.d.ts +2 -2
- package/dist/prefab/AggregateConstructor.d.ts.map +1 -1
- package/dist/prefab/AggregateOf.d.ts +2 -2
- package/dist/prefab/AggregateOf.d.ts.map +1 -1
- package/dist/prefab/AggregateShape.d.ts +2 -2
- package/dist/prefab/AggregateShape.d.ts.map +1 -1
- package/dist/prefab/CrudConstructor.d.ts +2 -2
- package/dist/prefab/CrudConstructor.d.ts.map +1 -1
- package/dist/prefab/CrudConstructor.js +12 -10
- package/dist/prefab/CrudConstructor.js.map +1 -1
- package/dist/prefab/CrudOps.d.ts +2 -2
- package/dist/prefab/CrudOps.d.ts.map +1 -1
- package/dist/prefab/CrudViews.d.ts +2 -2
- package/dist/prefab/CrudViews.d.ts.map +1 -1
- package/dist/prefab/MirrorConstructor.d.ts +2 -2
- package/dist/prefab/MirrorConstructor.d.ts.map +1 -1
- package/dist/prefab/MirrorConstructor.js.map +1 -1
- package/dist/prefab/RepositoryConstructor.d.ts +4 -4
- package/dist/prefab/RepositoryConstructor.d.ts.map +1 -1
- package/dist/prefab/RepositoryConstructor.js.map +1 -1
- package/dist/prefab/collector.d.ts +2 -1
- package/dist/prefab/collector.d.ts.map +1 -1
- package/dist/prefab/collector.js.map +1 -1
- package/dist/prefab/opsOf.d.ts +4 -0
- package/dist/prefab/opsOf.d.ts.map +1 -0
- package/dist/prefab/opsOf.js +5 -0
- package/dist/prefab/opsOf.js.map +1 -0
- package/dist/prefab/prefab.d.ts +3 -3
- package/dist/prefab/prefab.d.ts.map +1 -1
- package/dist/prefab/presenter.d.ts +3 -3
- package/dist/prefab/presenter.d.ts.map +1 -1
- package/dist/prefab/presenter.js.map +1 -1
- package/dist/wire/Addresses.d.ts +4 -4
- package/dist/wire/Addresses.d.ts.map +1 -1
- package/dist/wire/Cardinality.d.ts +4 -0
- package/dist/wire/Cardinality.d.ts.map +1 -0
- package/dist/wire/Cardinality.js +3 -0
- package/dist/wire/Cardinality.js.map +1 -0
- package/dist/wire/OperationContract.d.ts +2 -1
- package/dist/wire/OperationContract.d.ts.map +1 -1
- package/dist/wire/OperationContract.js.map +1 -1
- package/dist/wire/OperationKind.d.ts +3 -1
- package/dist/wire/OperationKind.d.ts.map +1 -1
- package/dist/wire/OperationKind.js +2 -1
- package/dist/wire/OperationKind.js.map +1 -1
- package/dist/wire/Placement.d.ts +4 -0
- package/dist/wire/Placement.d.ts.map +1 -0
- package/dist/wire/Placement.js +3 -0
- package/dist/wire/Placement.js.map +1 -0
- package/dist/wire/RouteKind.d.ts +2 -1
- package/dist/wire/RouteKind.d.ts.map +1 -1
- package/dist/wire/StateShape.d.ts +1 -2
- package/dist/wire/StateShape.d.ts.map +1 -1
- package/dist/wire/StateShape.js +11 -11
- package/dist/wire/StateShape.js.map +1 -1
- package/dist/wire/TypeRef.d.ts +5 -0
- package/dist/wire/TypeRef.d.ts.map +1 -1
- package/dist/wire/binding.d.ts +4 -1
- package/dist/wire/binding.d.ts.map +1 -1
- package/dist/wire/binding.js +4 -2
- package/dist/wire/binding.js.map +1 -1
- package/dist/wire/card/CardOp.d.ts +4 -10
- package/dist/wire/card/CardOp.d.ts.map +1 -1
- package/dist/wire/refusals.d.ts +2 -1
- package/dist/wire/refusals.d.ts.map +1 -1
- package/dist/wire/refusals.js.map +1 -1
- package/dist/wire/topology/DeclaredFrond.d.ts +2 -1
- package/dist/wire/topology/DeclaredFrond.d.ts.map +1 -1
- package/dist/wire/topology/FrondPlacement.d.ts +2 -1
- package/dist/wire/topology/FrondPlacement.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/Declared.ts +3 -7
- package/src/DeclaredHandler.ts +3 -8
- package/src/DeclaredSubject.ts +3 -5
- package/src/EffectiveOperation.ts +7 -6
- package/src/EffectiveOperationModel.ts +11 -7
- package/src/FrondConfig.ts +0 -2
- package/src/FrondDeclaration.ts +5 -8
- package/src/OperationOverride.ts +5 -3
- package/src/SourceView.ts +21 -3
- package/src/boot/bootstrap.ts +7 -6
- package/src/boot/unregistered.ts +31 -33
- package/src/contract.ts +3 -0
- package/src/descriptor/CollectorEntry.ts +2 -7
- package/src/descriptor/FrondDescriptor.ts +5 -19
- package/src/descriptor/HandlerEntry.ts +2 -7
- package/src/descriptor/MiddlewareEntry.ts +2 -7
- package/src/descriptor/PresenterEntry.ts +2 -7
- package/src/descriptor/ProviderEntry.ts +2 -7
- package/src/descriptor/Subject.ts +10 -0
- package/src/descriptor/index.ts +1 -0
- package/src/index.ts +3 -1
- package/src/prefab/AggregateConstructor.ts +2 -2
- package/src/prefab/AggregateOf.ts +2 -2
- package/src/prefab/AggregateShape.ts +2 -2
- package/src/prefab/CrudConstructor.ts +17 -13
- package/src/prefab/CrudOps.ts +3 -3
- package/src/prefab/CrudViews.ts +2 -2
- package/src/prefab/MirrorConstructor.ts +2 -2
- package/src/prefab/RepositoryConstructor.ts +9 -9
- package/src/prefab/collector.ts +4 -3
- package/src/prefab/opsOf.ts +6 -0
- package/src/prefab/prefab.ts +5 -5
- package/src/prefab/presenter.ts +3 -3
- package/src/wire/Addresses.ts +4 -4
- package/src/wire/Cardinality.ts +4 -0
- package/src/wire/OperationContract.ts +2 -1
- package/src/wire/OperationKind.ts +4 -1
- package/src/wire/Placement.ts +4 -0
- package/src/wire/RouteKind.ts +3 -1
- package/src/wire/StateShape.ts +9 -11
- package/src/wire/TypeRef.ts +2 -0
- package/src/wire/binding.ts +7 -2
- package/src/wire/card/CardOp.ts +4 -10
- package/src/wire/refusals.ts +2 -1
- package/src/wire/topology/DeclaredFrond.ts +3 -1
- package/src/wire/topology/FrondPlacement.ts +3 -1
package/dist/wire/StateShape.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Schema, dotted, optional } from '@fougere/schema';
|
|
2
2
|
import { ErrorCode } from './ErrorCode.js';
|
|
3
3
|
import { FougereError } from './FougereError.js';
|
|
4
4
|
/**
|
|
@@ -9,18 +9,17 @@ import { FougereError } from './FougereError.js';
|
|
|
9
9
|
* Documented: [collectors](https://fougere.dev/docs/business/collectors).
|
|
10
10
|
*/
|
|
11
11
|
export class StateShape {
|
|
12
|
-
|
|
13
|
-
static empty = new StateShape({});
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
this.fields = fields;
|
|
17
|
-
this.validator = InputValidator.of(fields);
|
|
12
|
+
schema;
|
|
13
|
+
static empty = new StateShape(Schema.of({ fields: {} }));
|
|
14
|
+
constructor(schema) {
|
|
15
|
+
this.schema = schema;
|
|
18
16
|
}
|
|
19
17
|
/** Two extensions declaring one member refuse: the field that judges it would depend on wiring order. */
|
|
20
18
|
static of(declarations) {
|
|
21
|
-
const fields = {};
|
|
22
19
|
const owners = new Map();
|
|
20
|
+
let schema = Schema.of({ fields: {} });
|
|
23
21
|
for (const { name, state } of declarations) {
|
|
22
|
+
const fields = {};
|
|
24
23
|
for (const [member, field] of Object.entries(state ?? {})) {
|
|
25
24
|
const owner = owners.get(member);
|
|
26
25
|
if (owner) {
|
|
@@ -30,8 +29,9 @@ export class StateShape {
|
|
|
30
29
|
owners.set(member, name);
|
|
31
30
|
fields[member] = optional(field);
|
|
32
31
|
}
|
|
32
|
+
schema = schema.extend(fields);
|
|
33
33
|
}
|
|
34
|
-
return new StateShape(
|
|
34
|
+
return new StateShape(schema);
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* The members written since `entered` rebuilt by their fields, or a refusal naming the member
|
|
@@ -41,10 +41,10 @@ export class StateShape {
|
|
|
41
41
|
const written = Object.fromEntries(Object.entries(state).filter(([member, value]) => entered[member] !== value));
|
|
42
42
|
if (Object.keys(written).length === 0)
|
|
43
43
|
return state;
|
|
44
|
-
const result = this.
|
|
44
|
+
const result = this.schema.validate(written);
|
|
45
45
|
if (result.success)
|
|
46
46
|
return { ...state, ...result.data };
|
|
47
|
-
const declared = Object.keys(this.
|
|
47
|
+
const declared = Object.keys(this.schema.getFields());
|
|
48
48
|
const errors = result.errors.map((error) => ({ ...error, path: ['state', ...error.path] }));
|
|
49
49
|
throw new FougereError({
|
|
50
50
|
code: ErrorCode.VALIDATION_FAILED,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StateShape.js","sourceRoot":"","sources":["../../src/wire/StateShape.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"StateShape.js","sourceRoot":"","sources":["../../src/wire/StateShape.ts"],"names":[],"mappings":"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"}
|
package/dist/wire/TypeRef.d.ts
CHANGED
|
@@ -16,5 +16,10 @@ export interface TypeRef {
|
|
|
16
16
|
undefined?: boolean;
|
|
17
17
|
/** Whether this is a Promise wrapper (unwrapped in output). */
|
|
18
18
|
promise?: boolean;
|
|
19
|
+
/** `Post['id']` — the entity whose primary key this value is, and the field holding it. */
|
|
20
|
+
identifies?: {
|
|
21
|
+
entity: string;
|
|
22
|
+
field: string;
|
|
23
|
+
};
|
|
19
24
|
}
|
|
20
25
|
//# sourceMappingURL=TypeRef.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypeRef.d.ts","sourceRoot":"","sources":["../../src/wire/TypeRef.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,WAAW,OAAO;IACtB,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"TypeRef.d.ts","sourceRoot":"","sources":["../../src/wire/TypeRef.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,WAAW,OAAO;IACtB,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2FAA2F;IAC3F,UAAU,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD"}
|
package/dist/wire/binding.d.ts
CHANGED
|
@@ -20,10 +20,13 @@ type ParamSource = {
|
|
|
20
20
|
| {
|
|
21
21
|
kind: 'pipe';
|
|
22
22
|
factName: string;
|
|
23
|
-
}
|
|
23
|
+
}
|
|
24
|
+
/** `identifies` names the entity whose row the value designates — `id: Post['id']`. */
|
|
25
|
+
| {
|
|
24
26
|
kind: 'param';
|
|
25
27
|
name: string;
|
|
26
28
|
coerce?: 'number' | 'boolean';
|
|
29
|
+
identifies?: string;
|
|
27
30
|
} | {
|
|
28
31
|
kind: 'input';
|
|
29
32
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/wire/binding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKxC,KAAK,WAAW,GACZ;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AACzC,qFAAqF;GACnF;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AACpC;;;;GAIG;GACD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/wire/binding.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKxC,KAAK,WAAW,GACZ;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AACzC,qFAAqF;GACnF;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AACpC;;;;GAIG;GACD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AACpC,uFAAuF;GACrF;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE;AACrB,2EAA2E;GACzE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtB,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,WAAW,GAAG,YAAY,EAAE,CAAC;AAezC,qDAAqD;AACrD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,KAAK,EAAE,EACf,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,GAC9B,WAAW,CAMb"}
|
package/dist/wire/binding.js
CHANGED
|
@@ -37,8 +37,10 @@ function sourceOf(param, collectorTypeNames) {
|
|
|
37
37
|
return { kind: 'collector', typeName: typeKey };
|
|
38
38
|
if (typeName === 'InvocationContext')
|
|
39
39
|
return { kind: 'context' };
|
|
40
|
-
if (PRIMITIVES.has(typeName))
|
|
41
|
-
|
|
40
|
+
if (PRIMITIVES.has(typeName)) {
|
|
41
|
+
const identifies = param.type.identifies?.entity;
|
|
42
|
+
return { kind: 'param', name: param.name, coerce: coercionFor(typeName), ...(identifies && { identifies }) };
|
|
43
|
+
}
|
|
42
44
|
return { kind: 'input' };
|
|
43
45
|
}
|
|
44
46
|
//# sourceMappingURL=binding.js.map
|
package/dist/wire/binding.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/wire/binding.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/wire/binding.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AA6B7C,iDAAiD;AAEjD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;AAE5D,SAAS,WAAW,CAAC,QAAgB;IACnC,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC3C,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE7C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,iDAAiD;AAEjD,qDAAqD;AACrD,MAAM,UAAU,kBAAkB,CAChC,MAAe,EACf,kBAA+B;IAE/B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;QAC3C,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK;KAClC,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,KAAY,EAAE,kBAA+B;IAC7D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC,8FAA8F;IAC9F,qFAAqF;IACrF,sDAAsD;IACtD,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAErC,MAAM,SAAS,GAAG,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1G,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,EAAE,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;IAC1F,CAAC;IAED,IAAI,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IACrF,IAAI,QAAQ,KAAK,mBAAmB;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACjE,IAAI,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC;QAEjD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,UAAU,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAC/G,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
import type { SchemaDescriptor } from '@fougere/schema';
|
|
2
|
-
import type {
|
|
2
|
+
import type { OperationContract } from '../OperationContract.js';
|
|
3
|
+
import type { OperationKind } from '../OperationKind.js';
|
|
3
4
|
/**
|
|
4
5
|
* One operation, as a stranger meets it — its name, what it is for, what it takes and whether it
|
|
5
6
|
* reads or writes.
|
|
6
7
|
*/
|
|
7
|
-
export interface CardOp {
|
|
8
|
+
export interface CardOp extends Pick<OperationContract, 'description' | 'cardinality' | 'errors'> {
|
|
8
9
|
name: string;
|
|
9
|
-
/** The author's own doc sentence, when the method carries one. */
|
|
10
|
-
description?: string;
|
|
11
10
|
/** JSON Schema of what it accepts, when the contract names a view. */
|
|
12
11
|
input?: SchemaDescriptor;
|
|
13
12
|
/** JSON Schema of what it emits, when the contract names one. */
|
|
14
13
|
output?: SchemaDescriptor;
|
|
15
|
-
|
|
16
|
-
kind: 'query' | 'command';
|
|
17
|
-
/** How much `output` describes. */
|
|
18
|
-
cardinality?: 'one' | 'maybe' | 'many' | 'page' | 'none';
|
|
19
|
-
/** What this op can REFUSE, beyond what `kind` and `input` already imply. */
|
|
20
|
-
errors?: ErrorCode[];
|
|
14
|
+
kind: OperationKind;
|
|
21
15
|
/** The fact this op is handed when it is announced — its `Fact<T>`, which IS the subscription. */
|
|
22
16
|
listens?: string;
|
|
23
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardOp.d.ts","sourceRoot":"","sources":["../../../src/wire/card/CardOp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"CardOp.d.ts","sourceRoot":"","sources":["../../../src/wire/card/CardOp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;GAGG;AACH,MAAM,WAAW,MAAO,SAAQ,IAAI,CAAC,iBAAiB,EAAE,aAAa,GAAG,aAAa,GAAG,QAAQ,CAAC;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,iEAAiE;IACjE,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,IAAI,EAAE,aAAa,CAAC;IACpB,kGAAkG;IAClG,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
package/dist/wire/refusals.d.ts
CHANGED
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
* Documented: [observability](https://fougere.dev/docs/infra/observability).
|
|
15
15
|
*/
|
|
16
16
|
import { ErrorCode } from './ErrorCode.js';
|
|
17
|
+
import type { OperationKind } from './OperationKind.js';
|
|
17
18
|
/** The little of an operation this reads — so a card op and an effective one both fit. */
|
|
18
19
|
export interface Refusable {
|
|
19
|
-
kind?:
|
|
20
|
+
kind?: OperationKind;
|
|
20
21
|
input?: unknown;
|
|
21
22
|
errors?: readonly string[];
|
|
22
23
|
/** Absent on a card op read from a frond that answers in this process. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refusals.d.ts","sourceRoot":"","sources":["../../src/wire/refusals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"refusals.d.ts","sourceRoot":"","sources":["../../src/wire/refusals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,0FAA0F;AAC1F,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAmBD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,SAAS,EAAE,CAIrD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refusals.js","sourceRoot":"","sources":["../../src/wire/refusals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"refusals.js","sourceRoot":"","sources":["../../src/wire/refusals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAY3C;;;;GAIG;AACH,MAAM,OAAO,GAA4D;IACvE,qFAAqF;IACrF,EAAE,IAAI,EAAE,SAAS,CAAC,mBAAmB,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE;IACzD,sFAAsF;IACtF,EAAE,IAAI,EAAE,SAAS,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,KAAK,SAAS,EAAE;IAC3E,oFAAoF;IACpF,EAAE,IAAI,EAAE,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,SAAS,EAAE;IACpE,0FAA0F;IAC1F,EAAE,IAAI,EAAE,SAAS,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE;IACrE,EAAE,IAAI,EAAE,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE;CAClE,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,EAAa;IACtC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE7E,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,EAAE,CAAgB,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAChF,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { Placement } from '../Placement.js';
|
|
1
2
|
/** A frond the config knows of, and where it says to reach it. */
|
|
2
3
|
export interface DeclaredFrond {
|
|
3
4
|
frond: string;
|
|
4
|
-
placement:
|
|
5
|
+
placement: Placement;
|
|
5
6
|
/**
|
|
6
7
|
* Host and port of the address `remotes:` names, absent when the frond runs here. Never the
|
|
7
8
|
* whole address: a declared one may carry credentials, and this answer leaves the process.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeclaredFrond.d.ts","sourceRoot":"","sources":["../../../src/wire/topology/DeclaredFrond.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"DeclaredFrond.d.ts","sourceRoot":"","sources":["../../../src/wire/topology/DeclaredFrond.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;CACb"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { Placement } from '../Placement.js';
|
|
1
2
|
/** A frond this process knows about, and whether it runs here. */
|
|
2
3
|
export interface FrondPlacement {
|
|
3
4
|
frond: string;
|
|
4
|
-
placement:
|
|
5
|
+
placement: Placement;
|
|
5
6
|
entities: number;
|
|
6
7
|
facades: number;
|
|
7
8
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FrondPlacement.d.ts","sourceRoot":"","sources":["../../../src/wire/topology/FrondPlacement.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"FrondPlacement.d.ts","sourceRoot":"","sources":["../../../src/wire/topology/FrondPlacement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fougere/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0-alpha.0",
|
|
4
4
|
"description": "The core — scan, call contract, façades, remote stand-ins.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fougere",
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
"tsconfig"
|
|
62
62
|
],
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@fougere/container": "0.
|
|
65
|
-
"@fougere/schema": "0.
|
|
64
|
+
"@fougere/container": "0.18.0-alpha.0",
|
|
65
|
+
"@fougere/schema": "0.18.0-alpha.0",
|
|
66
66
|
"dequal": "^2.0.3"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
package/src/Declared.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { AbstractCtor } from './Ctor.js';
|
|
2
2
|
import type { DeclaredSubject } from './DeclaredSubject.js';
|
|
3
|
+
import type { ProviderEntry } from './descriptor/ProviderEntry.js';
|
|
3
4
|
|
|
4
5
|
/** A class on its own — a port, which is abstract, included — or a class with what it asks for. */
|
|
5
|
-
export type Declared = AbstractCtor
|
|
6
|
-
ctor: AbstractCtor;
|
|
7
|
-
/** The container key, when the class's own name cannot be trusted to survive a build. */
|
|
8
|
-
name?: string;
|
|
9
|
-
/** The class is `abstract` — a port and never a realization. The scan writes it; TypeScript erases it. */
|
|
10
|
-
abstract?: true;
|
|
11
|
-
});
|
|
6
|
+
export type Declared = AbstractCtor
|
|
7
|
+
| (Omit<DeclaredSubject, 'ctor'> & { ctor: AbstractCtor } & Partial<Pick<ProviderEntry, 'name' | 'abstract'>>);
|
package/src/DeclaredHandler.ts
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import type { OperationContract } from './wire/OperationContract.js';
|
|
2
2
|
import type { DeclaredSubject } from './DeclaredSubject.js';
|
|
3
|
+
import type { HandlerEntry } from './descriptor/HandlerEntry.js';
|
|
3
4
|
|
|
4
5
|
/** A handler, and the surface it answers on when it is not the default one. */
|
|
5
|
-
export
|
|
6
|
-
/**
|
|
7
|
-
* The scan reads this from the directory (`handlers/public/`), so a statement has to say it: two
|
|
8
|
-
* handlers over one entity collide on their address otherwise, and the refusal names the same
|
|
9
|
-
* route twice.
|
|
10
|
-
*/
|
|
11
|
-
surface?: string;
|
|
6
|
+
export type DeclaredHandler = DeclaredSubject & Partial<Pick<HandlerEntry, 'surface'>> & {
|
|
12
7
|
/**
|
|
13
8
|
* What each method takes and answers — read from SOURCE by the scan, and unreachable
|
|
14
9
|
* from a class at runtime. A prefab declares its own (`Crud.__ops`) and needs nothing
|
|
15
10
|
* here; a method someone wrote does, or the route it should serve does not exist.
|
|
16
11
|
*/
|
|
17
12
|
operations?: ReadonlyMap<string, OperationContract> | Record<string, OperationContract>;
|
|
18
|
-
}
|
|
13
|
+
};
|
package/src/DeclaredSubject.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Subject } from './descriptor/Subject.js';
|
|
2
|
+
|
|
2
3
|
/** What a subject needs beyond its class, when its constructor names a frame or a port. */
|
|
3
|
-
export
|
|
4
|
-
ctor: Ctor;
|
|
5
|
-
deps?: string[];
|
|
6
|
-
}
|
|
4
|
+
export type DeclaredSubject = Pick<Subject, 'ctor'> & Partial<Pick<Subject, 'deps'>>;
|
|
@@ -4,6 +4,7 @@ import { type OperationContract } from './wire/OperationContract.js';
|
|
|
4
4
|
import { type OperationKind } from './wire/OperationKind.js';
|
|
5
5
|
import type { EffectiveParameter } from './EffectiveParameter.js';
|
|
6
6
|
import type { EffectiveCollector } from './EffectiveCollector.js';
|
|
7
|
+
import type { Placement } from './wire/Placement.js';
|
|
7
8
|
|
|
8
9
|
export interface EffectiveOperation extends OperationContract {
|
|
9
10
|
/** Stable qualified identity: `blog/public/Post.publish`. */
|
|
@@ -30,11 +31,11 @@ export interface EffectiveOperation extends OperationContract {
|
|
|
30
31
|
parameters: EffectiveParameter[];
|
|
31
32
|
collectors: EffectiveCollector[];
|
|
32
33
|
contexts: string[];
|
|
33
|
-
placement
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
/** The frond that answers it, and where — `placement` says where it ANSWERS, `reach` where it GOES. */
|
|
35
|
+
frond: string;
|
|
36
|
+
placement: Placement;
|
|
37
|
+
/** The address it is reached at, when it answers a process away. */
|
|
38
|
+
remote?: string;
|
|
38
39
|
/**
|
|
39
40
|
* What running this op reaches, and how much of that crosses a process.
|
|
40
41
|
*
|
|
@@ -48,7 +49,7 @@ export interface EffectiveOperation extends OperationContract {
|
|
|
48
49
|
* saying otherwise would dress a structural fact as a precise effect.
|
|
49
50
|
*/
|
|
50
51
|
reach: {
|
|
51
|
-
fronds: { frond: string;
|
|
52
|
+
fronds: { frond: string; placement: Placement }[];
|
|
52
53
|
/** How many of them are a process away — zero when everything it reaches runs here. */
|
|
53
54
|
hops: number;
|
|
54
55
|
};
|
|
@@ -18,8 +18,10 @@ import type { EffectiveParameter } from './EffectiveParameter.js';
|
|
|
18
18
|
import type { EffectiveOperation } from './EffectiveOperation.js';
|
|
19
19
|
import type { EffectiveOperationsMap } from './EffectiveOperationsMap.js';
|
|
20
20
|
import type { EffectiveOperationOptions } from './EffectiveOperationOptions.js';
|
|
21
|
+
import type { Placement } from './wire/Placement.js';
|
|
22
|
+
import type { Binding } from './Binding.js';
|
|
23
|
+
import { opsOf } from './prefab/opsOf.js';
|
|
21
24
|
|
|
22
|
-
type Binding = BindingPlan[number];
|
|
23
25
|
|
|
24
26
|
/** A contract whose parameters are all bound. */
|
|
25
27
|
type BoundContract = OperationContract & { binding: BindingPlan };
|
|
@@ -39,9 +41,9 @@ function reachOf(
|
|
|
39
41
|
): EffectiveOperation['reach'] {
|
|
40
42
|
const fronds = reachedBy(deps, from, index)
|
|
41
43
|
.sort()
|
|
42
|
-
.map((frond) => ({ frond,
|
|
44
|
+
.map((frond) => ({ frond, placement: (remotes[frond] ? 'remote' : 'local') as Placement }));
|
|
43
45
|
|
|
44
|
-
return { fronds, hops: fronds.filter((one) => one.
|
|
46
|
+
return { fronds, hops: fronds.filter((one) => one.placement === 'remote').length };
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
|
|
@@ -193,7 +195,9 @@ function resolveOperation(resolving: Resolving, name: string, rawContract: Opera
|
|
|
193
195
|
contexts: parameters
|
|
194
196
|
.filter((parameter) => parameter.binding.source.kind === 'context')
|
|
195
197
|
.map((parameter) => parameter.name),
|
|
196
|
-
|
|
198
|
+
frond: frond.name,
|
|
199
|
+
placement: remote ? 'remote' : 'local',
|
|
200
|
+
...(remote ? { remote } : {}),
|
|
197
201
|
reach: reachOf(handler.deps, frond.name, served, options.remotes ?? {}),
|
|
198
202
|
exposure: {
|
|
199
203
|
surfaces: servedSurfaces(frond, handler).map((surface) => surface ?? 'default'),
|
|
@@ -388,7 +392,7 @@ function validateProvenance(
|
|
|
388
392
|
diagnostics: Diagnostic[],
|
|
389
393
|
): boolean {
|
|
390
394
|
let valid = true;
|
|
391
|
-
const declared = (handler.ctor
|
|
395
|
+
const declared = opsOf(handler.ctor)[name];
|
|
392
396
|
const explicitBinding = declared?.binding !== undefined
|
|
393
397
|
|| handler.operations.get(name)?.binding !== undefined
|
|
394
398
|
|| frond.operationsOverrides?.[name]?.binding !== undefined;
|
|
@@ -519,7 +523,7 @@ function implementationOf(
|
|
|
519
523
|
const method = override?.method ?? name;
|
|
520
524
|
const declared = implementation.operations.has(method)
|
|
521
525
|
|| typeof (implementation.ctor as { prototype?: Record<string, unknown> }).prototype?.[method] === 'function'
|
|
522
|
-
|| method in (
|
|
526
|
+
|| method in opsOf(implementation.ctor);
|
|
523
527
|
if (!declared) {
|
|
524
528
|
diagnostics.push({
|
|
525
529
|
severity: 'blocking',
|
|
@@ -592,7 +596,7 @@ function resolveContracts(
|
|
|
592
596
|
overrides: FrondDescriptor['operationsOverrides'],
|
|
593
597
|
collectorTypeNames: Set<string>,
|
|
594
598
|
): OperationsMap {
|
|
595
|
-
const declared = (handler.ctor
|
|
599
|
+
const declared = opsOf(handler.ctor);
|
|
596
600
|
const contracts: OperationsMap = new Map(Object.entries(declared));
|
|
597
601
|
|
|
598
602
|
for (const [opName, scanned] of handler.operations) {
|
package/src/FrondConfig.ts
CHANGED
|
@@ -10,8 +10,6 @@ export interface FrondConfig {
|
|
|
10
10
|
reads?: NameOf<'entity'>[];
|
|
11
11
|
/** Per-surface entity lists. Overrides default deduction for each named surface. */
|
|
12
12
|
surfaces?: Record<string, NameOf<'entity'>[]>;
|
|
13
|
-
/** Interface → implementation bindings for DI (e.g. { Database: 'SqliteDatabase' }). */
|
|
14
|
-
bindings?: Record<string, NameOf<'provider'>>;
|
|
15
13
|
/**
|
|
16
14
|
* The ops that FINISH a fact, in the order they run — by class name, keyed by fact.
|
|
17
15
|
*
|
package/src/FrondDeclaration.ts
CHANGED
|
@@ -15,9 +15,10 @@ import type { OperationContract } from './wire/OperationContract.js';
|
|
|
15
15
|
import type { DeclaredSubject } from './DeclaredSubject.js';
|
|
16
16
|
import type { DeclaredHandler } from './DeclaredHandler.js';
|
|
17
17
|
import type { Declared } from './Declared.js';
|
|
18
|
+
import { opsOf } from './prefab/opsOf.js';
|
|
19
|
+
import type { Ctor } from './Ctor.js';
|
|
20
|
+
import type { FrondConfig } from './FrondConfig.js';
|
|
18
21
|
|
|
19
|
-
/** A class, as a declaration hands it over: the constructor itself. */
|
|
20
|
-
type Ctor = new (...args: never[]) => unknown;
|
|
21
22
|
|
|
22
23
|
const ctorOf = (d: Declared): Ctor => (typeof d === 'function' ? d : d.ctor) as Ctor;
|
|
23
24
|
|
|
@@ -47,7 +48,7 @@ const depsOf = (d: Declared): string[] => (typeof d === 'function' ? [] : d.deps
|
|
|
47
48
|
*/
|
|
48
49
|
function statedOperations(h: Ctor | DeclaredHandler): Map<string, OperationContract> {
|
|
49
50
|
const declared = typeof h === 'function' ? undefined : h.operations;
|
|
50
|
-
const own = (ctorOf(h)
|
|
51
|
+
const own = opsOf(ctorOf(h));
|
|
51
52
|
const merged = new Map<string, OperationContract>(Object.entries(own));
|
|
52
53
|
for (const [op, contract] of declared instanceof Map ? declared : Object.entries(declared ?? {})) {
|
|
53
54
|
merged.set(op, contract as OperationContract);
|
|
@@ -57,7 +58,7 @@ function statedOperations(h: Ctor | DeclaredHandler): Map<string, OperationContr
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/** What a declaration states about one frond. Everything else is derived from the classes. */
|
|
60
|
-
export interface FrondDeclaration {
|
|
61
|
+
export interface FrondDeclaration extends Pick<FrondConfig, 'pipes' | 'surfaces'> {
|
|
61
62
|
entities?: SchemaView[];
|
|
62
63
|
handlers?: (Ctor | DeclaredHandler)[];
|
|
63
64
|
presenters?: (Ctor | DeclaredSubject)[];
|
|
@@ -66,10 +67,6 @@ export interface FrondDeclaration {
|
|
|
66
67
|
seeds?: { entityName: string; data: SeedEntry['data'] }[];
|
|
67
68
|
/** What runs around this frond's operations, and around those of the fronds under it. */
|
|
68
69
|
middlewares?: (Ctor | DeclaredSubject)[];
|
|
69
|
-
/** The ops that finish a fact, in order — the same key `frond.config.ts` states. */
|
|
70
|
-
pipes?: Record<string, string[]>;
|
|
71
|
-
/** Per-surface entity lists — the same key `frond.config.ts` states. */
|
|
72
|
-
surfaces?: Record<string, string[]>;
|
|
73
70
|
/** The import scope this frond answers under. Defaults to the conventional one. */
|
|
74
71
|
scope?: string;
|
|
75
72
|
/** What `frond.config.ts` states — the third producer of an operation contract. */
|
package/src/OperationOverride.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SchemaView } from '@fougere/schema';
|
|
2
|
+
import type { Ctor } from './Ctor.js';
|
|
2
3
|
import type { BindingPlan } from './wire/binding.js';
|
|
4
|
+
import type { OperationKind } from './wire/OperationKind.js';
|
|
3
5
|
|
|
4
6
|
/** Per-operation override. */
|
|
5
7
|
export interface OperationOverride {
|
|
6
8
|
/** Force operation kind, over the naming convention (`isReadOp`). */
|
|
7
|
-
kind?:
|
|
9
|
+
kind?: OperationKind;
|
|
8
10
|
/** The GraphQL root field this op answers to. */
|
|
9
11
|
graphql?: string;
|
|
10
12
|
/**
|
|
@@ -17,7 +19,7 @@ export interface OperationOverride {
|
|
|
17
19
|
* Handler class to delegate to (overrides the default `{Entity}Handler` lookup).
|
|
18
20
|
* Class name is used to resolve from DI. E.g. `ArchiveHandler` → `app.resolve('ArchiveHandler')`.
|
|
19
21
|
*/
|
|
20
|
-
handler?:
|
|
22
|
+
handler?: Ctor;
|
|
21
23
|
/** Method name on `handler` (defaults to the operation name). */
|
|
22
24
|
method?: string;
|
|
23
25
|
/** CASL ability check (e.g. */
|
package/src/SourceView.ts
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import type { SchemaView } from '@fougere/schema';
|
|
2
|
+
import type { EntityEntry } from './descriptor/EntityEntry.js';
|
|
3
|
+
|
|
4
|
+
/** The app as ONE source sees it: the entities it holds, by the name the scan wrote down. */
|
|
2
5
|
export interface SourceView {
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
entities: ReadonlyMap<string, SchemaView>;
|
|
7
|
+
/** The names another source holds — a reference to one gets a column and no key. Absent: all here. */
|
|
8
|
+
elsewhere?: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** What a source holds of these fronds — every entity, or the ones `holds` keeps and the rest named. */
|
|
12
|
+
export function sourceViewOf(
|
|
13
|
+
fronds: readonly { readonly entities: readonly Pick<EntityEntry, 'name' | 'entityClass'>[] }[],
|
|
14
|
+
holds?: (name: string) => boolean,
|
|
15
|
+
): SourceView {
|
|
16
|
+
const all = new Map(fronds.flatMap((frond) => frond.entities.map((entry) => [entry.name, entry.entityClass] as const)));
|
|
17
|
+
if (!holds) return { entities: all };
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
entities: new Map([...all].filter(([name]) => holds(name))),
|
|
21
|
+
elsewhere: [...all.keys()].filter((name) => !holds(name)).sort(),
|
|
22
|
+
};
|
|
5
23
|
}
|
package/src/boot/bootstrap.ts
CHANGED
|
@@ -574,7 +574,7 @@ function answerRemotes(
|
|
|
574
574
|
{ container, routeRegistry, dispatcher, getMiddlewares, options, state }: Pick<Assembly, 'container' | 'routeRegistry' | 'dispatcher' | 'getMiddlewares' | 'options' | 'state'>,
|
|
575
575
|
remoteRouter: RemoteRouter,
|
|
576
576
|
fronds: Fronds,
|
|
577
|
-
):
|
|
577
|
+
): (name: string) => boolean {
|
|
578
578
|
// Only for what another process may serve: an entity a frond hosts HERE and gives no handler
|
|
579
579
|
// is served by nobody, and a stand-in for it had GraphQL project an entity with no operation.
|
|
580
580
|
const servedElsewhere = (address: string): boolean => {
|
|
@@ -582,9 +582,8 @@ function answerRemotes(
|
|
|
582
582
|
|
|
583
583
|
return owner === undefined || owner.name in (options.remotes ?? {});
|
|
584
584
|
};
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
: undefined));
|
|
585
|
+
const answeredElsewhere = (name: string): boolean => isFacadeKey(name) && servedElsewhere(addressOf(name));
|
|
586
|
+
container.setFallback((name) => (answeredElsewhere(name) ? facadeOperations(dispatcher, addressOf(name)) : undefined));
|
|
588
587
|
|
|
589
588
|
const remoteFacades = new Map<string, Record<string, Function>>();
|
|
590
589
|
routeRegistry.addResolver(remoteRoutes((address) => {
|
|
@@ -595,6 +594,8 @@ function answerRemotes(
|
|
|
595
594
|
|
|
596
595
|
return facade;
|
|
597
596
|
}));
|
|
597
|
+
|
|
598
|
+
return answeredElsewhere;
|
|
598
599
|
}
|
|
599
600
|
|
|
600
601
|
/** Refused rather than replaced: two declarations of one name would make the answer depend on wiring order. */
|
|
@@ -700,7 +701,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
700
701
|
refuseWhatDoesNotHold(refused);
|
|
701
702
|
markLineCarriers(emissions);
|
|
702
703
|
|
|
703
|
-
|
|
704
|
+
const answeredElsewhere = remoteRouter ? answerRemotes(assembly, remoteRouter, fronds) : () => false;
|
|
704
705
|
|
|
705
706
|
const { resolve, schemaFor, facadeFor, operationsFor, presenterFor } = readings({
|
|
706
707
|
container, fronds, remoteRouter, localDispatcher, routeRegistry, effectiveByKey, log,
|
|
@@ -741,7 +742,7 @@ export async function createApp(options: CreateAppOptions): Promise<App> {
|
|
|
741
742
|
|
|
742
743
|
built = app;
|
|
743
744
|
await appLifecycle.up(app);
|
|
744
|
-
refuseWhatDoesNotHold(unregistered(container, fronds));
|
|
745
|
+
refuseWhatDoesNotHold(unregistered(container, fronds, answeredElsewhere));
|
|
745
746
|
stopAnnouncing = announceLines(emissions, container, carry);
|
|
746
747
|
|
|
747
748
|
return app;
|
package/src/boot/unregistered.ts
CHANGED
|
@@ -1,42 +1,40 @@
|
|
|
1
1
|
import type { Container } from '@fougere/container';
|
|
2
2
|
import type { Diagnostic } from '../diagnostic.js';
|
|
3
3
|
import type { FrondDescriptor } from '../descriptor/FrondDescriptor.js';
|
|
4
|
-
|
|
5
|
-
type Declared = { frond: string; filePath: string };
|
|
6
|
-
|
|
7
|
-
/** Every class a frond hands the container, by identity — the one key a bundler cannot rename. */
|
|
8
|
-
function declaredBy(fronds: readonly FrondDescriptor[]): Map<Function, Declared> {
|
|
9
|
-
const declared = new Map<Function, Declared>();
|
|
10
|
-
for (const frond of fronds) {
|
|
11
|
-
const entries = [...frond.handlers, ...frond.providers, ...frond.presenters, ...frond.collectors, ...frond.middlewares];
|
|
12
|
-
for (const { ctor, filePath } of entries) declared.set(ctor, { frond: frond.name, filePath });
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return declared;
|
|
16
|
-
}
|
|
4
|
+
import { SEAMS } from './ports.js';
|
|
17
5
|
|
|
18
6
|
/**
|
|
19
7
|
* What a constructor asks for and nothing where it is built answers — refused at boot rather than
|
|
20
|
-
* at its first call, once the extensions have risen, since `up` registers too.
|
|
8
|
+
* at its first call, once the extensions have risen, since `up` registers too. Read off what each
|
|
9
|
+
* class DECLARES, in the scope of the frond that declares it. A seam is answered by the link that
|
|
10
|
+
* wraps it, and a facade another process serves by the stand-in `answeredElsewhere` names.
|
|
21
11
|
*/
|
|
22
|
-
export function unregistered(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
12
|
+
export function unregistered(
|
|
13
|
+
container: Container,
|
|
14
|
+
fronds: readonly FrondDescriptor[],
|
|
15
|
+
answeredElsewhere: (name: string) => boolean,
|
|
16
|
+
): Diagnostic[] {
|
|
17
|
+
const refused = new Map<string, Diagnostic>();
|
|
18
|
+
for (const frond of fronds) {
|
|
19
|
+
if (!container.has(`frond:${frond.name}`)) continue;
|
|
20
|
+
const scope = container.resolve<Container>(`frond:${frond.name}`);
|
|
21
|
+
const declared = [...frond.handlers, ...frond.providers, ...frond.presenters, ...frond.collectors, ...frond.middlewares];
|
|
22
|
+
for (const { ctor, deps, filePath } of declared) {
|
|
23
|
+
for (const missing of deps) {
|
|
24
|
+
if (scope.has(missing) || SEAMS.has(missing) || answeredElsewhere(missing)) continue;
|
|
25
|
+
if (refused.has(`${ctor.name}→${missing}`)) continue;
|
|
26
|
+
refused.set(`${ctor.name}→${missing}`, {
|
|
27
|
+
severity: 'blocking',
|
|
28
|
+
code: 'dependency-unregistered',
|
|
29
|
+
frond: frond.name,
|
|
30
|
+
subject: ctor.name,
|
|
31
|
+
filePath,
|
|
32
|
+
message: `${ctor.name} asks for ${missing}, and nothing in frond '${frond.name}' or above it answers that name. `
|
|
33
|
+
+ `A class of that name in a convention directory, or one extending it, would.`,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
severity: 'blocking' as const,
|
|
34
|
-
code: 'dependency-unregistered',
|
|
35
|
-
...(where ? { frond: where.frond } : {}),
|
|
36
|
-
subject,
|
|
37
|
-
filePath: where?.filePath ?? '',
|
|
38
|
-
message: `${subject} asks for ${missing}, and nothing ${where ? `in frond '${where.frond}' or above it ` : ''}answers that name. `
|
|
39
|
-
+ `A class of that name in a convention directory, or one extending it, would.`,
|
|
40
|
-
}];
|
|
41
|
-
});
|
|
39
|
+
return [...refused.values()];
|
|
42
40
|
}
|