@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,7 +1,7 @@
|
|
|
1
1
|
/** The thirteen gestures of {@link Storage}, derived from four. */
|
|
2
2
|
import { applyCreate, applyUpdate, Lifecycle, Role, type SchemaView } from '@fougere/schema';
|
|
3
3
|
import { comparisonOf, comparisonsIn, type Comparison } from './criterion.js';
|
|
4
|
-
import type { Storage, StorageFactory } from './
|
|
4
|
+
import type { Storage, StorageFactory } from './port.js';
|
|
5
5
|
|
|
6
6
|
/** One instance, as every realization hands it over. */
|
|
7
7
|
export type Values = Record<string, unknown>;
|
|
@@ -47,11 +47,29 @@ export function storageOver(open: (entity: SchemaView, name: string) => Store):
|
|
|
47
47
|
? Object.fromEntries(Object.entries(values).filter(([key]) => selected.has(key)))
|
|
48
48
|
: values);
|
|
49
49
|
|
|
50
|
+
// Same contract as SQL: the key and the creation stamps survive an overwrite.
|
|
51
|
+
// Named, and not reached through `this`: a caller may have wrapped these gestures,
|
|
52
|
+
// and a derived one that goes back through the front door is judged twice.
|
|
53
|
+
const upsert = async (input: Partial<Record<string, unknown>>): Promise<Values> => {
|
|
54
|
+
const values = applyCreate(fields, applyUpdate(fields, input));
|
|
55
|
+
const id = values[pk] as string | undefined;
|
|
56
|
+
if (id === undefined) throw new Error(`${name}.upsert(): no \`${pk}\` — an upsert needs the key it writes at.`);
|
|
57
|
+
const previous = await store.get(keyOf(id));
|
|
58
|
+
if (previous) {
|
|
59
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
60
|
+
if (key === pk || Lifecycle.of(field).stampedOnce) values[key] = previous[key];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
await store.set(keyOf(id), values);
|
|
64
|
+
return pick(values);
|
|
65
|
+
};
|
|
66
|
+
|
|
50
67
|
return {
|
|
51
68
|
client: store.client,
|
|
52
69
|
async list(options?: any) {
|
|
53
70
|
let items = await store.all();
|
|
54
71
|
if (options?.where) items = items.filter((values) => matches(values, options.where));
|
|
72
|
+
if (options?.orderBy) items = sorted(items, options.orderBy, options.order);
|
|
55
73
|
// Held before the page is cut, and after the filter: `total` answers "how many
|
|
56
74
|
// match", which is what a paginator divides. Reading `store.size` at the end
|
|
57
75
|
// answered a different question — everything the store holds, including the ones
|
|
@@ -104,22 +122,9 @@ export function storageOver(open: (entity: SchemaView, name: string) => Store):
|
|
|
104
122
|
}
|
|
105
123
|
return grouped;
|
|
106
124
|
},
|
|
107
|
-
|
|
108
|
-
async upsert(input: Partial<Record<string, unknown>>) {
|
|
109
|
-
const values = applyCreate(fields, applyUpdate(fields, input));
|
|
110
|
-
const id = values[pk] as string | undefined;
|
|
111
|
-
if (id === undefined) throw new Error(`${name}.upsert(): no \`${pk}\` — an upsert needs the key it writes at.`);
|
|
112
|
-
const previous = await store.get(keyOf(id));
|
|
113
|
-
if (previous) {
|
|
114
|
-
for (const [key, field] of Object.entries(fields)) {
|
|
115
|
-
if (key === pk || Lifecycle.of(field).stampedOnce) values[key] = previous[key];
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
await store.set(keyOf(id), values);
|
|
119
|
-
return pick(values);
|
|
120
|
-
},
|
|
125
|
+
upsert,
|
|
121
126
|
async upsertAll(inputs: readonly Partial<Record<string, unknown>>[]) {
|
|
122
|
-
for (const input of inputs) await
|
|
127
|
+
for (const input of inputs) await upsert(input);
|
|
123
128
|
return inputs.length;
|
|
124
129
|
},
|
|
125
130
|
async create(input: Partial<Record<string, unknown>>) {
|
|
@@ -189,3 +194,17 @@ const ordered = (held: unknown, asked: unknown, holds: (a: number, b: number) =>
|
|
|
189
194
|
/** What a Date and a number have in common, and a string keeps for itself. */
|
|
190
195
|
const order = (value: unknown): number =>
|
|
191
196
|
value instanceof Date ? value.getTime() : (value as number);
|
|
197
|
+
|
|
198
|
+
/** The ORDER BY the engine would have compiled, answered over the rows the store held. */
|
|
199
|
+
const sorted = (rows: Values[], field: string, direction: 'asc' | 'desc' | undefined): Values[] =>
|
|
200
|
+
[...rows].sort((left, right) =>
|
|
201
|
+
(direction === 'desc' ? -1 : 1) * rank(left[field], right[field]));
|
|
202
|
+
|
|
203
|
+
/** A row that holds nothing sorts first, and two of them tie. */
|
|
204
|
+
const rank = (left: unknown, right: unknown): number => {
|
|
205
|
+
if (left === null || left === undefined) return right === null || right === undefined ? 0 : -1;
|
|
206
|
+
if (right === null || right === undefined) return 1;
|
|
207
|
+
const [held, against] = [order(left), order(right)];
|
|
208
|
+
|
|
209
|
+
return held === against ? 0 : held < against ? -1 : 1;
|
|
210
|
+
};
|
package/src/verify.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { FrondDescriptor } from './descriptor/frond.js';
|
|
2
2
|
import { lowerFirst } from '@fougere/schema';
|
|
3
3
|
import { repositoryKeyOf } from './prefab/repository.js';
|
|
4
|
-
import { storageKeyOf } from './storage.js';
|
|
4
|
+
import { storageKeyOf } from './storage/port.js';
|
|
5
5
|
import { presenterKeyOf } from './prefab/presenter.js';
|
|
6
6
|
import { collectorKeyOf } from './prefab/collector.js';
|
|
7
7
|
|
package/src/wire/Invocation.ts
CHANGED
|
@@ -60,6 +60,8 @@ export class Invocation implements InvocationContext {
|
|
|
60
60
|
return context instanceof Invocation ? context : new Invocation(context ?? {});
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
static readonly empty = Invocation.from();
|
|
64
|
+
|
|
63
65
|
/** Replaces the input — how the façade hands on the value it parsed. */
|
|
64
66
|
withInput(input: unknown): Invocation {
|
|
65
67
|
return new Invocation({ ...this, input });
|
|
@@ -70,10 +72,3 @@ export class Invocation implements InvocationContext {
|
|
|
70
72
|
return new Invocation({ ...this, state });
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
|
-
|
|
74
|
-
export const EMPTY_INVOCATION = Invocation.from();
|
|
75
|
-
|
|
76
|
-
/** Names the same gesture as `Invocation.from` for callers that read better this way. */
|
|
77
|
-
export function canonicalInvocation(context?: PartialInvocation): Invocation {
|
|
78
|
-
return Invocation.from(context);
|
|
79
|
-
}
|
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/call.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Call contract — a frond call is a value. */
|
|
2
2
|
import { Card, type SchemaDescriptor } from '@fougere/schema';
|
|
3
|
-
import { factsAnnouncedBy } from '
|
|
3
|
+
import { factsAnnouncedBy } from './emit.js';
|
|
4
4
|
import { Invocation, type InvocationContext, type PartialInvocation } from './Invocation.js';
|
|
5
5
|
import type { RouteAddress } from './RouteAddress.js';
|
|
6
6
|
import { FougereError, ErrorCode } from './errors.js';
|
package/src/wire/emit.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** Announcing a fact — the half of the topology `remotes:` never covered. */
|
|
2
|
+
import { lowerFirst } from '@fougere/schema';
|
|
3
|
+
|
|
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[]>;
|
|
11
|
+
|
|
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
|
+
*/
|
|
19
|
+
export type Fact<T> = T;
|
|
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
|
+
|
|
31
|
+
/** The container key of an emission — THE one place that spells the format. */
|
|
32
|
+
export function emitKeyOf(fact: string): string {
|
|
33
|
+
return `${lowerFirst(fact)}Emit`;
|
|
34
|
+
}
|
|
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
|
+
|
|
45
|
+
const SUFFIX = 'Emit';
|
|
46
|
+
const AWAIT_SUFFIX = 'Await';
|
|
47
|
+
|
|
48
|
+
/** The fact behind an emission key, or `undefined` when the key is not one. */
|
|
49
|
+
export function factOfEmitKey(key: string): string | undefined {
|
|
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)
|
|
61
|
+
: undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** What a set of handlers ANNOUNCES — `Emit<T>` read back out of their dependencies. */
|
|
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[] {
|
|
78
|
+
return [...new Set(
|
|
79
|
+
handlers
|
|
80
|
+
.flatMap((handler) => handler.deps)
|
|
81
|
+
.map(behindKey)
|
|
82
|
+
.filter((fact): fact is string => fact !== undefined),
|
|
83
|
+
)];
|
|
84
|
+
}
|
package/src/wire/errors.ts
CHANGED
|
@@ -55,7 +55,7 @@ export class FougereError extends Error {
|
|
|
55
55
|
|
|
56
56
|
constructor(options: FougereErrorOptions) {
|
|
57
57
|
super(options.message, { cause: options.cause });
|
|
58
|
-
this.name =
|
|
58
|
+
this.name = new.target.name;
|
|
59
59
|
this.code = options.code;
|
|
60
60
|
this.entity = options.entity;
|
|
61
61
|
this.operation = options.operation;
|
|
@@ -97,7 +97,7 @@ export function validationErrorsOf(error: unknown): ValidationError[] | undefine
|
|
|
97
97
|
const refusals = details.filter(
|
|
98
98
|
(entry): entry is ValidationError =>
|
|
99
99
|
typeof entry === 'object' && entry !== null
|
|
100
|
-
&&
|
|
100
|
+
&& Array.isArray((entry as ValidationError).path)
|
|
101
101
|
&& typeof (entry as ValidationError).message === 'string',
|
|
102
102
|
);
|
|
103
103
|
return refusals.length === details.length ? refusals : undefined;
|
|
@@ -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 {
|
package/dist/boot/boot.d.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { type FougereConfig } from '../config-loader.js';
|
|
2
|
-
import type { App, CreateAppOptions } from './types.js';
|
|
3
|
-
import { type Extension } from './AppLifecycle.js';
|
|
4
|
-
import type { Transport } from '../wire/call.js';
|
|
5
|
-
import type { Container } from '@fougere/container';
|
|
6
|
-
interface BootOptions {
|
|
7
|
-
/** Project root. Defaults to process.cwd(). */
|
|
8
|
-
root?: string;
|
|
9
|
-
/** Override config (merged with fougere.config.ts). */
|
|
10
|
-
config?: Partial<FougereConfig>;
|
|
11
|
-
/** Container factory. Required. */
|
|
12
|
-
createContainer: () => Container;
|
|
13
|
-
/** Only boot these fronds (by name). Absent = all. */
|
|
14
|
-
fronds?: string[];
|
|
15
|
-
/**
|
|
16
|
-
* Remote fronds — label → address. A declared remote wins over local
|
|
17
|
-
* presence (the frond runs elsewhere). Requires `remoteTransport`.
|
|
18
|
-
*/
|
|
19
|
-
remotes?: Record<string, string>;
|
|
20
|
-
/** Builds the transport to reach `remotes`. Supplied by a layer-2 package. */
|
|
21
|
-
remoteTransport?: (url: string) => Transport;
|
|
22
|
-
/** Carries an announced fact out of this process. */
|
|
23
|
-
onEmit?: CreateAppOptions['onEmit'];
|
|
24
|
-
/**
|
|
25
|
-
* storage setup — returns the storage handle (db), an storageFactory, and its two halves.
|
|
26
|
-
* The `db` value is forwarded to the auth provider via AuthContext when `auth` is set.
|
|
27
|
-
*/
|
|
28
|
-
db?: (config: FougereConfig) => {
|
|
29
|
-
db?: unknown;
|
|
30
|
-
storageFactory: CreateAppOptions['storageFactory'];
|
|
31
|
-
/** Bring the schema up to date — an extension's `up`, because it runs after the container. */
|
|
32
|
-
migrate?: (app: App) => Promise<void> | void;
|
|
33
|
-
/** Closes what the factory opened — `boot()` called it, so `boot()` releases it. */
|
|
34
|
-
close?: () => Promise<void>;
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* What this app takes on beyond its fronds. Appended after the framework's own, so a
|
|
38
|
-
* host adds to the ascent — or replaces a member of it by declaring the same name.
|
|
39
|
-
*/
|
|
40
|
-
extensions?: readonly (Extension | undefined)[];
|
|
41
|
-
}
|
|
42
|
-
/** Boot a Fougere app from fougere.config.ts. */
|
|
43
|
-
export declare function boot(options: BootOptions): Promise<App>;
|
|
44
|
-
export {};
|
|
45
|
-
//# sourceMappingURL=boot.d.ts.map
|
package/dist/boot/boot.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../src/boot/boot.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGrE,OAAO,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,UAAU,WAAW;IACnB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,mCAAmC;IACnC,eAAe,EAAE,MAAM,SAAS,CAAC;IACjC,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,8EAA8E;IAC9E,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;IAC7C,qDAAqD;IACrD,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACpC;;;OAGG;IACH,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK;QAC9B,EAAE,CAAC,EAAE,OAAO,CAAC;QACb,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;QACnD,8FAA8F;QAC9F,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAC7C,oFAAoF;QACpF,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;KAC7B,CAAC;IACF;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,GAAG,SAAS,CAAC,EAAE,CAAC;CACjD;AAED,iDAAiD;AACjD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CA4D7D"}
|
package/dist/boot/boot.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { createApp } from './bootstrap.js';
|
|
2
|
-
import { seeding } from './seed.js';
|
|
3
|
-
import { scanProject } from '../scan/scanner.js';
|
|
4
|
-
import { loadConfig } from '../config-loader.js';
|
|
5
|
-
import { Logger } from '../builtin/logger.js';
|
|
6
|
-
import { applyConfig } from './apply.js';
|
|
7
|
-
import { migrating } from './AppLifecycle.js';
|
|
8
|
-
/** Boot a Fougere app from fougere.config.ts. */
|
|
9
|
-
export async function boot(options) {
|
|
10
|
-
const bootStart = performance.now();
|
|
11
|
-
const log = new Logger('boot');
|
|
12
|
-
const root = options.root ?? process.cwd();
|
|
13
|
-
log.info(`root: ${root}`);
|
|
14
|
-
log.debug('loading config');
|
|
15
|
-
const fileConfig = await loadConfig(root);
|
|
16
|
-
const config = { ...fileConfig, ...options.config };
|
|
17
|
-
// What this config changes in the process, said the same way at boot and at reload —
|
|
18
|
-
// there is one applier, and a host re-reading later calls the very same function.
|
|
19
|
-
applyConfig(config);
|
|
20
|
-
log.info('config loaded');
|
|
21
|
-
let dbSetup;
|
|
22
|
-
if (options.db) {
|
|
23
|
-
log.debug('initializing database');
|
|
24
|
-
dbSetup = options.db(config);
|
|
25
|
-
log.info('database initialized');
|
|
26
|
-
}
|
|
27
|
-
log.debug('creating app (scan + container)');
|
|
28
|
-
const app = await createApp({
|
|
29
|
-
// boot() lives on the Node entry, so boot() is what reads the disk. `createApp` is
|
|
30
|
-
// handed the answer and reaches for nothing.
|
|
31
|
-
scan: await scanProject(root, options.fronds, config.conventions),
|
|
32
|
-
createContainer: options.createContainer,
|
|
33
|
-
storageFactory: dbSetup?.storageFactory,
|
|
34
|
-
db: dbSetup?.db,
|
|
35
|
-
auth: config.auth,
|
|
36
|
-
remotes: options.remotes,
|
|
37
|
-
ports: config.ports,
|
|
38
|
-
// Read from the config for the same reason `ports` is, one line up: it is a fact the
|
|
39
|
-
// project states, not one the caller passes. Absent here, `serveRest` and
|
|
40
|
-
// `serveGraphQL` both answered `pass` on an app whose config declared them — the
|
|
41
|
-
// hosts got it right through their own boot (`app/shared/src/boot.ts`), and this
|
|
42
|
-
// path, the conventional one, served nothing.
|
|
43
|
-
adapters: config.adapters,
|
|
44
|
-
// boot() called the factory, so boot() owns closing what it opened. Not an extension:
|
|
45
|
-
// it was opened before the container existed, so it closes after the container goes.
|
|
46
|
-
onDispose: dbSetup?.close,
|
|
47
|
-
/**
|
|
48
|
-
* The whole ascent, in one ordered list — tables, then rows, then whatever the host takes on.
|
|
49
|
-
*/
|
|
50
|
-
extensions: [
|
|
51
|
-
migrating(dbSetup?.migrate, (message) => log.warn(message)),
|
|
52
|
-
seeding((message) => log.debug(message)),
|
|
53
|
-
...(options.extensions ?? []),
|
|
54
|
-
],
|
|
55
|
-
onEmit: options.onEmit,
|
|
56
|
-
remoteTransport: options.remoteTransport,
|
|
57
|
-
});
|
|
58
|
-
log.info(`ascent: ${app.extensions().join(' → ') || 'nothing declared'}`);
|
|
59
|
-
const ms = (performance.now() - bootStart).toFixed(0);
|
|
60
|
-
log.info(`ready in ${ms}ms — ${app.fronds.length} frond(s)`);
|
|
61
|
-
return app;
|
|
62
|
-
}
|
|
63
|
-
//# sourceMappingURL=boot.js.map
|
package/dist/boot/boot.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"boot.js","sourceRoot":"","sources":["../../src/boot/boot.ts"],"names":[],"mappings":"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"}
|
package/dist/criterion.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"criterion.d.ts","sourceRoot":"","sources":["../src/criterion.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,OAAO,EAAE,KAAK,KAAK,EAAU,MAAM,iBAAiB,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,wDAAwD;IACxD,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,WAAW,qFAAsF,CAAC;AAE/G,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,EAAE,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAM7F;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE,CAIjF;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,EAAE,CAE1D"}
|
package/dist/criterion.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"criterion.js","sourceRoot":"","sources":["../src/criterion.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,OAAO,EAAc,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAsBrD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AAI/G;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAwB,EAAE,KAAc;IACnE,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1F,uFAAuF;IACvF,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAE/E,OAAO,KAAmB,CAAC;AAC7B,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,aAAa,CAAC,UAAsB;IAClD,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CACtC,CAAC,KAAK,EAAsC,EAAE,CAAE,WAAiC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CACrG,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,SAAS,CAAC,UAAsB;IAC9C,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAE,WAAiC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACtG,CAAC"}
|
package/dist/declarations.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { Conventions } from './scan/conventions.js';
|
|
2
|
-
import type { HandlerEntry } from './descriptor/frond.js';
|
|
3
|
-
export interface HandlerDeclaration {
|
|
4
|
-
/** Stable rule name — the same vocabulary `verify()` uses. */
|
|
5
|
-
rule: 'handler-declaration';
|
|
6
|
-
frond: string;
|
|
7
|
-
filePath: string;
|
|
8
|
-
/** The handler that hosts it. */
|
|
9
|
-
handler: string;
|
|
10
|
-
/** What is declared — `AGREED_WITHIN`, `says`, `Assessment`. */
|
|
11
|
-
subject: string;
|
|
12
|
-
/** What it is in the source: a value, or a shape. */
|
|
13
|
-
kind: 'value' | 'shape';
|
|
14
|
-
message: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Everything a handler file declares that is not the handler itself.
|
|
18
|
-
*
|
|
19
|
-
* A handler names gestures; what a gesture uses is declared where its nature says, and one
|
|
20
|
-
* question settles which: does it arrive INJECTED or IMPORTED? A threshold, a formula, a word
|
|
21
|
-
* list arrive imported and belong under `rules/`. Anything holding a client, a connection or
|
|
22
|
-
* a cursor arrives injected and belongs under `services/`. Neither ever belongs in the file
|
|
23
|
-
* that calls it — nothing there can be reached by a second caller, and the handler grows into
|
|
24
|
-
* the domain it was supposed to address.
|
|
25
|
-
*
|
|
26
|
-
* It names the two addresses, which `outsideConventions` does on the same question one file
|
|
27
|
-
* higher. Saying "a module beside its entities" instead left the reader to invent a place,
|
|
28
|
-
* and inventing one is the drift both rules report.
|
|
29
|
-
*/
|
|
30
|
-
export declare function handlerDeclarations(fronds: readonly {
|
|
31
|
-
name: string;
|
|
32
|
-
handlers: readonly Pick<HandlerEntry, 'name' | 'filePath'>[];
|
|
33
|
-
}[], conventions: Conventions): Promise<HandlerDeclaration[]>;
|
|
34
|
-
//# sourceMappingURL=declarations.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"declarations.d.ts","sourceRoot":"","sources":["../src/declarations.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAQ1D,MAAM,WAAW,kBAAkB;IACjC,8DAA8D;IAC9D,IAAI,EAAE,qBAAqB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAuBD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,SAAS;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC;CAC9D,EAAE,EACH,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA0C/B"}
|
package/dist/declarations.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
let _ts;
|
|
3
|
-
async function loadTs() {
|
|
4
|
-
if (!_ts)
|
|
5
|
-
_ts = (await import('@typescript/typescript6')).default;
|
|
6
|
-
return _ts;
|
|
7
|
-
}
|
|
8
|
-
function subjectsOf(typescript, source) {
|
|
9
|
-
const found = [];
|
|
10
|
-
for (const statement of source.statements) {
|
|
11
|
-
if (typescript.isVariableStatement(statement)) {
|
|
12
|
-
for (const declared of statement.declarationList.declarations)
|
|
13
|
-
if (typescript.isIdentifier(declared.name))
|
|
14
|
-
found.push([declared.name.text, 'value']);
|
|
15
|
-
}
|
|
16
|
-
else if (typescript.isFunctionDeclaration(statement) && statement.name) {
|
|
17
|
-
found.push([statement.name.text, 'value']);
|
|
18
|
-
}
|
|
19
|
-
else if (typescript.isInterfaceDeclaration(statement) ||
|
|
20
|
-
typescript.isTypeAliasDeclaration(statement) ||
|
|
21
|
-
typescript.isEnumDeclaration(statement)) {
|
|
22
|
-
found.push([statement.name.text, 'shape']);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return found;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Everything a handler file declares that is not the handler itself.
|
|
29
|
-
*
|
|
30
|
-
* A handler names gestures; what a gesture uses is declared where its nature says, and one
|
|
31
|
-
* question settles which: does it arrive INJECTED or IMPORTED? A threshold, a formula, a word
|
|
32
|
-
* list arrive imported and belong under `rules/`. Anything holding a client, a connection or
|
|
33
|
-
* a cursor arrives injected and belongs under `services/`. Neither ever belongs in the file
|
|
34
|
-
* that calls it — nothing there can be reached by a second caller, and the handler grows into
|
|
35
|
-
* the domain it was supposed to address.
|
|
36
|
-
*
|
|
37
|
-
* It names the two addresses, which `outsideConventions` does on the same question one file
|
|
38
|
-
* higher. Saying "a module beside its entities" instead left the reader to invent a place,
|
|
39
|
-
* and inventing one is the drift both rules report.
|
|
40
|
-
*/
|
|
41
|
-
export async function handlerDeclarations(fronds, conventions) {
|
|
42
|
-
const typescript = await loadTs();
|
|
43
|
-
const found = [];
|
|
44
|
-
for (const frond of fronds) {
|
|
45
|
-
for (const handler of frond.handlers) {
|
|
46
|
-
const text = await readFile(handler.filePath, 'utf8').catch(() => undefined);
|
|
47
|
-
if (text === undefined)
|
|
48
|
-
continue;
|
|
49
|
-
const source = typescript.createSourceFile(handler.filePath, text, typescript.ScriptTarget.Latest, false);
|
|
50
|
-
for (const [subject, kind] of subjectsOf(typescript, source)) {
|
|
51
|
-
found.push({
|
|
52
|
-
rule: 'handler-declaration',
|
|
53
|
-
frond: frond.name,
|
|
54
|
-
filePath: handler.filePath,
|
|
55
|
-
handler: handler.name,
|
|
56
|
-
subject,
|
|
57
|
-
kind,
|
|
58
|
-
message: kind === 'value'
|
|
59
|
-
? `'${subject}' is declared in ${handler.name}, so only ${handler.name} can reach it. `
|
|
60
|
-
+ `If it needs nothing but its arguments, it is a word of '${frond.name}' and belongs `
|
|
61
|
-
+ `in \`${conventions.dirs.rules}/\`; if it holds a dependency, it belongs in `
|
|
62
|
-
+ `\`${conventions.dirs.services}/\`. Either way it is stated once and imported, and `
|
|
63
|
-
+ `the handler keeps only the gesture.`
|
|
64
|
-
: `'${subject}' is declared in ${handler.name}, which makes the shape of what an `
|
|
65
|
-
+ `operation answers readable only from the file that answers it. A shape belongs `
|
|
66
|
-
+ `with the entity it describes in \`${conventions.dirs.entities}/\`, or in `
|
|
67
|
-
+ `\`${conventions.dirs.rules}/\` beside the words that compute it — where the caller, `
|
|
68
|
-
+ `the test and the other operations can all name it.`,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return found;
|
|
74
|
-
}
|
|
75
|
-
//# sourceMappingURL=declarations.js.map
|
package/dist/declarations.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"declarations.js","sourceRoot":"","sources":["../src/declarations.ts"],"names":[],"mappings":"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"}
|
package/dist/emit.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/** What an emitter injects. */
|
|
2
|
-
export type Emit<T> = (fact: T) => Promise<void>;
|
|
3
|
-
/** What a subscriber accepts — and what it PROMISES about itself. */
|
|
4
|
-
export type Fact<T> = T;
|
|
5
|
-
/** The container key of an emission — THE one place that spells the format. */
|
|
6
|
-
export declare function emitKeyOf(fact: string): string;
|
|
7
|
-
/** The fact behind an emission key, or `undefined` when the key is not one. */
|
|
8
|
-
export declare function factOfEmitKey(key: string): string | undefined;
|
|
9
|
-
/** What a set of handlers ANNOUNCES — `Emit<T>` read back out of their dependencies. */
|
|
10
|
-
export declare function factsAnnouncedBy(handlers: readonly {
|
|
11
|
-
deps: readonly string[];
|
|
12
|
-
}[]): string[];
|
|
13
|
-
//# sourceMappingURL=emit.d.ts.map
|
package/dist/emit.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAGA,+BAA+B;AAC/B,MAAM,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEjD,qEAAqE;AACrE,MAAM,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAExB,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAID,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI7D;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,SAAS;IAAE,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAAE,GAAG,MAAM,EAAE,CAO3F"}
|
package/dist/emit.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/** Announcing a fact — the half of the topology `remotes:` never covered. */
|
|
2
|
-
import { lowerFirst } from '@fougere/schema';
|
|
3
|
-
/** The container key of an emission — THE one place that spells the format. */
|
|
4
|
-
export function emitKeyOf(fact) {
|
|
5
|
-
return `${lowerFirst(fact)}Emit`;
|
|
6
|
-
}
|
|
7
|
-
const SUFFIX = 'Emit';
|
|
8
|
-
/** The fact behind an emission key, or `undefined` when the key is not one. */
|
|
9
|
-
export function factOfEmitKey(key) {
|
|
10
|
-
return key.length > SUFFIX.length && key.endsWith(SUFFIX)
|
|
11
|
-
? key.slice(0, -SUFFIX.length)
|
|
12
|
-
: undefined;
|
|
13
|
-
}
|
|
14
|
-
/** What a set of handlers ANNOUNCES — `Emit<T>` read back out of their dependencies. */
|
|
15
|
-
export function factsAnnouncedBy(handlers) {
|
|
16
|
-
return [...new Set(handlers
|
|
17
|
-
.flatMap((handler) => handler.deps)
|
|
18
|
-
.map(factOfEmitKey)
|
|
19
|
-
.filter((fact) => fact !== undefined))];
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=emit.js.map
|
package/dist/emit.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"emit.js","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAQ7C,+EAA+E;AAC/E,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;AACnC,CAAC;AAED,MAAM,MAAM,GAAG,MAAM,CAAC;AAEtB,+EAA+E;AAC/E,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;QACvD,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;QAC9B,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,QAAgD;IAC/E,OAAO,CAAC,GAAG,IAAI,GAAG,CAChB,QAAQ;aACL,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;aAClC,GAAG,CAAC,aAAa,CAAC;aAClB,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CACxD,CAAC,CAAC;AACL,CAAC"}
|
package/dist/imports.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { FrondDescriptor } from './descriptor/frond.js';
|
|
2
|
-
export interface CrossFrondImport {
|
|
3
|
-
/** Stable rule name — the same vocabulary `verify()` uses. */
|
|
4
|
-
rule: 'cross-frond-import';
|
|
5
|
-
/** The frond doing the reaching. */
|
|
6
|
-
frond: string;
|
|
7
|
-
filePath: string;
|
|
8
|
-
/** The specifier as written. */
|
|
9
|
-
specifier: string;
|
|
10
|
-
/** The frond the path lands in — absent when it lands outside every frond. */
|
|
11
|
-
target?: string;
|
|
12
|
-
message: string;
|
|
13
|
-
}
|
|
14
|
-
/** Every relative import that resolves outside its own frond. */
|
|
15
|
-
export declare function crossFrondImports(fronds: readonly Pick<FrondDescriptor, 'name' | 'source'>[]): Promise<CrossFrondImport[]>;
|
|
16
|
-
//# sourceMappingURL=imports.d.ts.map
|
package/dist/imports.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../src/imports.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQ7D,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,IAAI,EAAE,oBAAoB,CAAC;IAC3B,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AA2BD,iEAAiE;AACjE,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,SAAS,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,QAAQ,CAAC,EAAE,GAC1D,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAwC7B"}
|