@fougere/core 0.8.4-alpha.0 → 0.9.0-alpha.1
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 +143 -8
- package/dist/boot/Emissions.js.map +1 -1
- package/dist/boot/bootstrap.d.ts.map +1 -1
- package/dist/boot/bootstrap.js +83 -18
- package/dist/boot/bootstrap.js.map +1 -1
- package/dist/boot/card.d.ts.map +1 -1
- package/dist/boot/card.js +6 -1
- package/dist/boot/card.js.map +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 +2 -0
- package/dist/boot/install.d.ts.map +1 -1
- package/dist/boot/install.js +33 -4
- package/dist/boot/install.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/types.d.ts +16 -1
- 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 +2 -1
- 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/conventions.d.ts +6 -0
- package/dist/conventions.d.ts.map +1 -1
- package/dist/conventions.js +3 -2
- package/dist/conventions.js.map +1 -1
- package/dist/declare.d.ts +11 -1
- package/dist/declare.d.ts.map +1 -1
- package/dist/declare.js +9 -0
- 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 +1 -1
- package/dist/descriptor/index.d.ts.map +1 -1
- package/dist/descriptor/index.js +1 -1
- package/dist/descriptor/index.js.map +1 -1
- 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.map +1 -1
- package/dist/dispatch/HandlerFacade.js +2 -2
- package/dist/dispatch/HandlerFacade.js.map +1 -1
- package/dist/effective-operation.d.ts.map +1 -1
- package/dist/effective-operation.js +11 -7
- 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 +30 -33
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -13
- package/dist/index.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 +35 -3
- package/dist/wire/emit.d.ts.map +1 -1
- package/dist/wire/emit.js +26 -3
- package/dist/wire/emit.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 +4 -4
- package/src/boot/AppLifecycle.ts +8 -0
- package/src/boot/Emissions.ts +176 -8
- package/src/boot/bootstrap.ts +95 -17
- package/src/boot/card.ts +6 -1
- package/src/boot/hosted.ts +3 -1
- package/src/boot/install.ts +35 -4
- package/src/boot/ports.ts +71 -27
- package/src/boot/remote.ts +3 -3
- package/src/boot/types.ts +16 -1
- package/src/builtin/LogLine.ts +38 -0
- package/src/builtin/logger.ts +109 -17
- package/src/config-loader.ts +2 -1
- package/src/contract.ts +5 -9
- package/src/conventions.ts +9 -2
- package/src/declare.ts +19 -1
- package/src/descriptor/frond.ts +31 -0
- package/src/descriptor/index.ts +1 -1
- package/src/dispatch/ArgumentResolver.ts +6 -2
- package/src/dispatch/HandlerFacade.ts +2 -2
- package/src/effective-operation.ts +13 -7
- package/src/frond-config.ts +20 -0
- package/src/index.ts +36 -50
- package/src/wire/Invocation.ts +2 -7
- package/src/wire/binding.ts +17 -6
- package/src/wire/emit.ts +58 -6
- package/src/wire/loggerMiddleware.ts +6 -0
package/src/wire/binding.ts
CHANGED
|
@@ -11,6 +11,12 @@ type ParamSource =
|
|
|
11
11
|
| { kind: 'collector'; typeName: string }
|
|
12
12
|
/** `Fact<PostPublished>` — something that happened, not something a caller typed. */
|
|
13
13
|
| { kind: 'fact'; factName: string }
|
|
14
|
+
/**
|
|
15
|
+
* `Pipe<PostPublished>` — the same thing, BEFORE it is final: what this op answers is
|
|
16
|
+
* the fact every subscriber then receives. The core has one such link already
|
|
17
|
+
* (`Emissions.stamped`, which realizes `created()`); this is the declared form of it.
|
|
18
|
+
*/
|
|
19
|
+
| { kind: 'pipe'; factName: string }
|
|
14
20
|
| { kind: 'param'; name: string; coerce?: 'number' | 'boolean' }
|
|
15
21
|
| { kind: 'input' }
|
|
16
22
|
| { kind: 'context' }
|
|
@@ -49,14 +55,19 @@ export function computeBindingPlan(
|
|
|
49
55
|
// `authoruser` missed `authorUser` and fell through to branch 4, the request input.
|
|
50
56
|
const typeKey = lowerFirst(typeName);
|
|
51
57
|
|
|
52
|
-
// 0. Fact
|
|
53
|
-
// FIRST because branch 4 would otherwise hand
|
|
54
|
-
// of something that happened.
|
|
55
|
-
const
|
|
56
|
-
|
|
58
|
+
// 0. Fact, or the same fact before it is final. Both name themselves, so nothing has
|
|
59
|
+
// to be known in advance, and they come FIRST because branch 4 would otherwise hand
|
|
60
|
+
// either the caller's input under the name of something that happened.
|
|
61
|
+
const announced = param.type.name === 'Fact' || param.type.name === 'Pipe'
|
|
62
|
+
? param.type.generics?.[0]?.name
|
|
63
|
+
: undefined;
|
|
64
|
+
if (announced) {
|
|
57
65
|
return {
|
|
58
66
|
name: param.name,
|
|
59
|
-
source: {
|
|
67
|
+
source: {
|
|
68
|
+
kind: (param.type.name === 'Pipe' ? 'pipe' : 'fact') as 'pipe' | 'fact',
|
|
69
|
+
factName: lowerFirst(announced),
|
|
70
|
+
},
|
|
60
71
|
optional: param.optional ?? false,
|
|
61
72
|
};
|
|
62
73
|
}
|
package/src/wire/emit.ts
CHANGED
|
@@ -1,32 +1,84 @@
|
|
|
1
1
|
/** Announcing a fact — the half of the topology `remotes:` never covered. */
|
|
2
2
|
import { lowerFirst } from '@fougere/schema';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* What an emitter injects. PARTIAL, because announcing is what REALIZES the fact's
|
|
6
|
+
* `lifecycle.create` — an `at: created()` is stamped by `Emissions`, so requiring it from
|
|
7
|
+
* the announcer made every emitter cast its way past its own type. A missing field is
|
|
8
|
+
* still refused, by the judge that reads the fact at announce time.
|
|
9
|
+
*/
|
|
10
|
+
export type Emit<T, A = never> = (fact: Partial<T>) => Promise<A[]>;
|
|
6
11
|
|
|
7
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* What a subscriber accepts — and what it PROMISES about itself.
|
|
14
|
+
*
|
|
15
|
+
* What it ANSWERS is its own to choose: `Promise<void>` says nothing, any other type is an
|
|
16
|
+
* opinion. It reaches an announcer that asked for one — `Emit<CanBook, Verdict>` — and
|
|
17
|
+
* nobody otherwise, since a plain announcement does not wait.
|
|
18
|
+
*/
|
|
8
19
|
export type Fact<T> = T;
|
|
9
20
|
|
|
21
|
+
/**
|
|
22
|
+
* The same fact, BEFORE it is final: an op taking one ANSWERS the value every subscriber
|
|
23
|
+
* then receives, so it is the declared form of what `Emissions.stamped` already does for
|
|
24
|
+
* `created()`.
|
|
25
|
+
*
|
|
26
|
+
* Not a second announcement and not a chain a subscriber joins: the links run once, before
|
|
27
|
+
* anyone is handed anything, which is what keeps a fact the same for every reader.
|
|
28
|
+
*/
|
|
29
|
+
export type Pipe<T> = T;
|
|
30
|
+
|
|
10
31
|
/** The container key of an emission — THE one place that spells the format. */
|
|
11
32
|
export function emitKeyOf(fact: string): string {
|
|
12
33
|
return `${lowerFirst(fact)}Emit`;
|
|
13
34
|
}
|
|
14
35
|
|
|
36
|
+
/**
|
|
37
|
+
* The key of an emission that WAITS — `Emit<CanBook, Verdict>`, where the second type is
|
|
38
|
+
* the whole difference. A separate key because they are two functions: one hands the fact
|
|
39
|
+
* over and returns, the other waits for every subscriber and gives back what they said.
|
|
40
|
+
*/
|
|
41
|
+
export function awaitKeyOf(fact: string): string {
|
|
42
|
+
return `${lowerFirst(fact)}Await`;
|
|
43
|
+
}
|
|
44
|
+
|
|
15
45
|
const SUFFIX = 'Emit';
|
|
46
|
+
const AWAIT_SUFFIX = 'Await';
|
|
16
47
|
|
|
17
48
|
/** The fact behind an emission key, or `undefined` when the key is not one. */
|
|
18
49
|
export function factOfEmitKey(key: string): string | undefined {
|
|
19
|
-
return key
|
|
20
|
-
|
|
50
|
+
return behind(key, SUFFIX);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The fact behind an awaited emission's key — the dual, read the same way. */
|
|
54
|
+
export function factOfAwaitKey(key: string): string | undefined {
|
|
55
|
+
return behind(key, AWAIT_SUFFIX);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function behind(key: string, suffix: string): string | undefined {
|
|
59
|
+
return key.length > suffix.length && key.endsWith(suffix)
|
|
60
|
+
? key.slice(0, -suffix.length)
|
|
21
61
|
: undefined;
|
|
22
62
|
}
|
|
23
63
|
|
|
24
64
|
/** What a set of handlers ANNOUNCES — `Emit<T>` read back out of their dependencies. */
|
|
25
65
|
export function factsAnnouncedBy(handlers: readonly { deps: readonly string[] }[]): string[] {
|
|
66
|
+
return factsIn(handlers, factOfEmitKey);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** What a set of handlers announces AND WAITS FOR — the same reading, one suffix apart. */
|
|
70
|
+
export function factsAwaitedBy(handlers: readonly { deps: readonly string[] }[]): string[] {
|
|
71
|
+
return factsIn(handlers, factOfAwaitKey);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function factsIn(
|
|
75
|
+
handlers: readonly { deps: readonly string[] }[],
|
|
76
|
+
behindKey: (key: string) => string | undefined,
|
|
77
|
+
): string[] {
|
|
26
78
|
return [...new Set(
|
|
27
79
|
handlers
|
|
28
80
|
.flatMap((handler) => handler.deps)
|
|
29
|
-
.map(
|
|
81
|
+
.map(behindKey)
|
|
30
82
|
.filter((fact): fact is string => fact !== undefined),
|
|
31
83
|
)];
|
|
32
84
|
}
|
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { AppMiddleware } from './middleware.js';
|
|
5
5
|
import type { Logger } from '../builtin/logger.js';
|
|
6
|
+
import { CARRIES_LINE } from '../builtin/LogLine.js';
|
|
6
7
|
|
|
7
8
|
/** Create a logger middleware that logs operation entry, exit, and errors. */
|
|
8
9
|
export function loggerMiddleware(logger: Logger): AppMiddleware {
|
|
9
10
|
return async (ctx, next) => {
|
|
11
|
+
// An op that CARRIES a line writes none: it is dispatched, so logging it announces a
|
|
12
|
+
// line inside the announcement of one — `Emission cycle: logLine → logLine`, which is
|
|
13
|
+
// the emission catching what `onLog`'s try/catch used to swallow.
|
|
14
|
+
if (CARRIES_LINE.has(ctx.entity)) return next();
|
|
15
|
+
|
|
10
16
|
const start = performance.now();
|
|
11
17
|
logger.info(`${ctx.entity}.${ctx.operation}`);
|
|
12
18
|
try {
|