@fougere/core 0.9.0-alpha.1 → 0.9.3-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.
Files changed (128) hide show
  1. package/dist/boot/AppLifecycle.d.ts +5 -1
  2. package/dist/boot/AppLifecycle.d.ts.map +1 -1
  3. package/dist/boot/AppLifecycle.js.map +1 -1
  4. package/dist/boot/apply.d.ts +5 -1
  5. package/dist/boot/apply.d.ts.map +1 -1
  6. package/dist/boot/apply.js +5 -1
  7. package/dist/boot/apply.js.map +1 -1
  8. package/dist/boot/declared.d.ts +29 -0
  9. package/dist/boot/declared.d.ts.map +1 -0
  10. package/dist/boot/declared.js +67 -0
  11. package/dist/boot/declared.js.map +1 -0
  12. package/dist/boot/install.d.ts.map +1 -1
  13. package/dist/boot/install.js +20 -3
  14. package/dist/boot/install.js.map +1 -1
  15. package/dist/boot/ownership.d.ts +2 -0
  16. package/dist/boot/ownership.d.ts.map +1 -1
  17. package/dist/boot/ownership.js +17 -0
  18. package/dist/boot/ownership.js.map +1 -1
  19. package/dist/boot/ports.d.ts +23 -0
  20. package/dist/boot/ports.d.ts.map +1 -1
  21. package/dist/boot/ports.js +49 -0
  22. package/dist/boot/ports.js.map +1 -1
  23. package/dist/boot/remote.d.ts +5 -1
  24. package/dist/boot/remote.d.ts.map +1 -1
  25. package/dist/boot/remote.js.map +1 -1
  26. package/dist/boot/seed.d.ts +5 -1
  27. package/dist/boot/seed.d.ts.map +1 -1
  28. package/dist/boot/seed.js +5 -1
  29. package/dist/boot/seed.js.map +1 -1
  30. package/dist/boot/together.d.ts.map +1 -1
  31. package/dist/boot/together.js +5 -1
  32. package/dist/boot/together.js.map +1 -1
  33. package/dist/boot/types.d.ts +1 -1
  34. package/dist/boot/types.d.ts.map +1 -1
  35. package/dist/builtin/logger.d.ts +1 -2
  36. package/dist/builtin/logger.d.ts.map +1 -1
  37. package/dist/builtin/logger.js +0 -19
  38. package/dist/builtin/logger.js.map +1 -1
  39. package/dist/config-loader.d.ts +0 -1
  40. package/dist/config-loader.d.ts.map +1 -1
  41. package/dist/config-loader.js.map +1 -1
  42. package/dist/contract.d.ts +1 -1
  43. package/dist/contract.d.ts.map +1 -1
  44. package/dist/contract.js.map +1 -1
  45. package/dist/descriptor/frond.d.ts +5 -1
  46. package/dist/descriptor/frond.d.ts.map +1 -1
  47. package/dist/descriptor/frond.js.map +1 -1
  48. package/dist/effective-operation.d.ts +20 -0
  49. package/dist/effective-operation.d.ts.map +1 -1
  50. package/dist/effective-operation.js +17 -0
  51. package/dist/effective-operation.js.map +1 -1
  52. package/dist/identity.d.ts.map +1 -1
  53. package/dist/identity.js +5 -1
  54. package/dist/identity.js.map +1 -1
  55. package/dist/index.d.ts +5 -4
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +6 -2
  58. package/dist/index.js.map +1 -1
  59. package/dist/prefab/collector.d.ts +5 -1
  60. package/dist/prefab/collector.d.ts.map +1 -1
  61. package/dist/prefab/collector.js +5 -1
  62. package/dist/prefab/collector.js.map +1 -1
  63. package/dist/prefab/crud.d.ts +9 -5
  64. package/dist/prefab/crud.d.ts.map +1 -1
  65. package/dist/prefab/crud.js +14 -7
  66. package/dist/prefab/crud.js.map +1 -1
  67. package/dist/prefab/mirror.d.ts +5 -1
  68. package/dist/prefab/mirror.d.ts.map +1 -1
  69. package/dist/prefab/mirror.js.map +1 -1
  70. package/dist/prefab/presenter.d.ts +6 -2
  71. package/dist/prefab/presenter.d.ts.map +1 -1
  72. package/dist/prefab/presenter.js +6 -2
  73. package/dist/prefab/presenter.js.map +1 -1
  74. package/dist/prefab/repository.d.ts +5 -1
  75. package/dist/prefab/repository.d.ts.map +1 -1
  76. package/dist/prefab/repository.js.map +1 -1
  77. package/dist/scan.d.ts +1 -1
  78. package/dist/scan.d.ts.map +1 -1
  79. package/dist/source.d.ts +5 -1
  80. package/dist/source.d.ts.map +1 -1
  81. package/dist/source.js.map +1 -1
  82. package/dist/storage/port.d.ts +27 -1
  83. package/dist/storage/port.d.ts.map +1 -1
  84. package/dist/storage/port.js +70 -0
  85. package/dist/storage/port.js.map +1 -1
  86. package/dist/wire/call.d.ts +26 -1
  87. package/dist/wire/call.d.ts.map +1 -1
  88. package/dist/wire/call.js +1 -1
  89. package/dist/wire/call.js.map +1 -1
  90. package/dist/wire/emit.d.ts.map +1 -1
  91. package/dist/wire/emit.js +5 -1
  92. package/dist/wire/emit.js.map +1 -1
  93. package/dist/wire/errors.d.ts +5 -1
  94. package/dist/wire/errors.d.ts.map +1 -1
  95. package/dist/wire/errors.js +5 -1
  96. package/dist/wire/errors.js.map +1 -1
  97. package/dist/wire/signature.d.ts +1 -2
  98. package/dist/wire/signature.d.ts.map +1 -1
  99. package/package.json +4 -4
  100. package/src/boot/AppLifecycle.ts +5 -1
  101. package/src/boot/apply.ts +5 -1
  102. package/src/boot/declared.ts +88 -0
  103. package/src/boot/install.ts +20 -4
  104. package/src/boot/ownership.ts +21 -0
  105. package/src/boot/ports.ts +63 -0
  106. package/src/boot/remote.ts +5 -1
  107. package/src/boot/seed.ts +5 -1
  108. package/src/boot/together.ts +5 -1
  109. package/src/boot/types.ts +1 -1
  110. package/src/builtin/logger.ts +1 -20
  111. package/src/config-loader.ts +0 -1
  112. package/src/contract.ts +4 -1
  113. package/src/descriptor/frond.ts +5 -1
  114. package/src/effective-operation.ts +41 -0
  115. package/src/identity.ts +5 -1
  116. package/src/index.ts +10 -3
  117. package/src/prefab/collector.ts +5 -1
  118. package/src/prefab/crud.ts +14 -7
  119. package/src/prefab/mirror.ts +5 -1
  120. package/src/prefab/presenter.ts +6 -2
  121. package/src/prefab/repository.ts +5 -1
  122. package/src/scan.ts +1 -1
  123. package/src/source.ts +5 -1
  124. package/src/storage/port.ts +74 -1
  125. package/src/wire/call.ts +29 -1
  126. package/src/wire/emit.ts +5 -1
  127. package/src/wire/errors.ts +5 -1
  128. package/src/wire/signature.ts +1 -2
@@ -1,4 +1,8 @@
1
- /** The error vocabulary — what a refusal IS, independently of who hears it. */
1
+ /**
2
+ * The error vocabulary — what a refusal IS, independently of who hears it.
3
+ *
4
+ * Documented: [errors](https://fougere.dev/docs/business/errors).
5
+ */
2
6
  // ── ErrorCode ──────────────────────────────────
3
7
  /** Semantic error codes — transport-agnostic. Each bridge maps them to its own format. */
4
8
  export var ErrorCode;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/wire/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/wire/errors.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- /** A method's signature, as a contract is built from it — the shape, never the reading. */
2
1
  /** A type reference — primitives, entities, arrays, generics. */
3
2
  export interface TypeRef {
4
3
  /** Raw type text as written in source (e.g. 'Pagination<Post>'). */
@@ -24,7 +23,7 @@ export interface Param {
24
23
  type: TypeRef;
25
24
  optional?: boolean;
26
25
  }
27
- /** A method signature. */
26
+ /** A method's signature, as a contract is built from it — the shape, never the reading. */
28
27
  export interface Signature {
29
28
  name: string;
30
29
  params: Param[];
@@ -1 +1 @@
1
- {"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../src/wire/signature.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,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;CACnB;AAED,oCAAoC;AACpC,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,0BAA0B;AAC1B,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
1
+ {"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../src/wire/signature.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;CACnB;AAED,oCAAoC;AACpC,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,2FAA2F;AAC3F,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fougere/core",
3
- "version": "0.9.0-alpha.1",
3
+ "version": "0.9.3-alpha.0",
4
4
  "description": "The core — scan, call contract, façades, remote stand-ins.",
5
5
  "keywords": [
6
6
  "fougere",
@@ -61,12 +61,12 @@
61
61
  "dependencies": {
62
62
  "@typescript/typescript6": "^6.0.2",
63
63
  "dequal": "^2.0.3",
64
- "@fougere/container": "0.9.0-alpha.1",
65
- "@fougere/schema": "0.9.0-alpha.1"
64
+ "@fougere/container": "0.9.3-alpha.0",
65
+ "@fougere/schema": "0.9.3-alpha.0"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/node": "^22.0.0",
69
- "@fougere/compiler": "0.9.0-alpha.1"
69
+ "@fougere/compiler": "0.9.3-alpha.0"
70
70
  },
71
71
  "publishConfig": {
72
72
  "access": "public"
@@ -1,7 +1,11 @@
1
1
  import type { App } from './types.js';
2
2
  import type { FrondDescriptor } from '../descriptor/frond.js';
3
3
 
4
- /** One process-level extension and its reversible lifecycle. */
4
+ /**
5
+ * One process-level extension and its reversible lifecycle.
6
+ *
7
+ * Documented: [lifecycle](https://fougere.dev/docs/infra/lifecycle).
8
+ */
5
9
  export interface Extension {
6
10
  name: string;
7
11
  /**
package/src/boot/apply.ts CHANGED
@@ -9,7 +9,11 @@ export interface ConfigApplication {
9
9
  pending: string[];
10
10
  }
11
11
 
12
- /** What a (re-)read config changes in a process that is already running. */
12
+ /**
13
+ * What a (re-)read config changes in a process that is already running.
14
+ *
15
+ * Documented: [lifecycle](https://fougere.dev/docs/infra/lifecycle).
16
+ */
13
17
  export function applyConfig(next: FougereConfig, inForce?: FougereConfig): ConfigApplication {
14
18
  const applied: string[] = [];
15
19
  const pending: string[] = [];
@@ -0,0 +1,88 @@
1
+ /**
2
+ * What an app says about its NEIGHBOURS — the dual of the identity card, which says what it IS.
3
+ *
4
+ * Documented: [observability](https://fougere.dev/docs/infra/observability).
5
+ */
6
+ import type { FrondDescriptor } from '../descriptor/frond.js';
7
+ import { facadeKeyOf, type DeclaredEdge, type DeclaredFrond, type DeclaredTopology } from '../wire/call.js';
8
+
9
+ interface Declaring {
10
+ fronds: readonly FrondDescriptor[];
11
+ remotes: Readonly<Record<string, string>>;
12
+ }
13
+
14
+ /** Read from the config and the scan, never from a call, so nothing has to answer for it. */
15
+ export function declaredTopologyOf({ fronds, remotes }: Declaring): DeclaredTopology {
16
+ const hosted = fronds.filter((frond) => !frond.brought);
17
+
18
+ return { fronds: placements(hosted, remotes), edges: crossings(hosted) };
19
+ }
20
+
21
+ function placements(hosted: readonly FrondDescriptor[], remotes: Readonly<Record<string, string>>): DeclaredFrond[] {
22
+ const here = hosted
23
+ .filter((frond) => !remotes[frond.name])
24
+ .map((frond) => ({ frond: frond.name, placement: 'local' as const }));
25
+
26
+ const elsewhere = Object.entries(remotes)
27
+ .map(([frond, address]) => ({ frond, placement: 'remote' as const, at: hostOf(address) }));
28
+
29
+ return [...here, ...elsewhere];
30
+ }
31
+
32
+ /**
33
+ * Which frond serves each address — indexed FORWARD, so a dependency is recognized by what
34
+ * answers it and never by its spelling. A surface is left out: its key carries a `:`, and no
35
+ * dependency can name one.
36
+ */
37
+ export function servedBy(fronds: readonly FrondDescriptor[]): Map<string, string> {
38
+ const index = new Map<string, string>();
39
+ for (const frond of fronds) {
40
+ if (frond.brought) continue;
41
+ for (const handler of frond.handlers) {
42
+ if (handler.surface) continue;
43
+ index.set(facadeKeyOf(handler.address), frond.name);
44
+ }
45
+ }
46
+
47
+ return index;
48
+ }
49
+
50
+ /**
51
+ * The fronds one class reaches through a façade — the only sanctioned crossing.
52
+ *
53
+ * An address no scanned frond serves is left out rather than guessed: naming the frond behind it
54
+ * means reading its card, and a card is a DISCOVERY, which belongs to the other half of the
55
+ * report. This answers what the CODE declares, and never more.
56
+ */
57
+ export function reachedBy(deps: readonly string[], from: string, index: Map<string, string>): string[] {
58
+ const reached = deps
59
+ .map((dependency) => index.get(dependency))
60
+ .filter((frond): frond is string => frond !== undefined && frond !== from);
61
+
62
+ return [...new Set(reached)];
63
+ }
64
+
65
+ function crossings(hosted: readonly FrondDescriptor[]): DeclaredEdge[] {
66
+ const index = servedBy(hosted);
67
+ const found = new Map<string, DeclaredEdge>();
68
+
69
+ for (const frond of hosted) {
70
+ for (const handler of frond.handlers) {
71
+ for (const to of reachedBy(handler.deps, frond.name, index)) {
72
+ found.set(`${frond.name} ${to}`, { from: frond.name, to });
73
+ }
74
+ }
75
+ }
76
+
77
+ return [...found.values()];
78
+ }
79
+
80
+ function hostOf(address: string): string {
81
+ try {
82
+ const url = new URL(address);
83
+
84
+ return `${url.protocol}//${url.host}`;
85
+ } catch {
86
+ return address;
87
+ }
88
+ }
@@ -6,7 +6,7 @@ import type { Dispatcher } from '../dispatch/Dispatcher.js';
6
6
  import type { RouteRegistry } from '../dispatch/RouteRegistry.js';
7
7
  import type { Emissions } from './Emissions.js';
8
8
  import type { EffectiveOperationsMap, EffectiveOperationModel } from '../effective-operation.js';
9
- import { nameOf } from '../descriptor/frond.js';
9
+ import { nameOf, type ProviderEntry } from '../descriptor/frond.js';
10
10
  import type { EntityEntry, FrondDescriptor, HandlerEntry } from '../descriptor/frond.js';
11
11
  import type { OperationsMap } from '../wire/operation.js';
12
12
  import type { AppMiddleware } from '../wire/middleware.js';
@@ -14,9 +14,9 @@ import type { CreateAppOptions } from './types.js';
14
14
  import { registerFrames } from './together.js';
15
15
  import { HandlerFacade } from '../dispatch/HandlerFacade.js';
16
16
  import { targetOf } from '../prefab/prefab.js';
17
- import { ownersOf, refuseStorageInUserCode, refuseCrudOnOwned } from './ownership.js';
17
+ import { ownersOf, refuseSharedName, refuseStorageInUserCode, refuseCrudOnOwned } from './ownership.js';
18
18
  import { StorageGuard } from '../dispatch/StorageGuard.js';
19
- import { portBindings } from './ports.js';
19
+ import { portBindings, seamChains, wrapping, SEAMS } from './ports.js';
20
20
  import { facadeKeyOf, contractsKeyOf } from '../wire/call.js';
21
21
  import { inheritsCrud, subjectOf } from '../prefab/crud.js';
22
22
  import { repositoryKeyOf } from '../prefab/repository.js';
@@ -117,6 +117,7 @@ export async function installFrond(frond: FrondDescriptor, assembly: Assembly):
117
117
 
118
118
  // Who owns what, and the rule that makes owning mean something. Before anything is
119
119
  // registered, so a bad line is named by this refusal rather than by the container's.
120
+ refuseSharedName(frond);
120
121
  const owners = ownersOf(frond.providers);
121
122
  refuseStorageInUserCode(frond, owners, (entity) => entityByName.has(entity));
122
123
  refuseCrudOnOwned(frond, owners);
@@ -124,11 +125,22 @@ export async function installFrond(frond: FrondDescriptor, assembly: Assembly):
124
125
  for (const provider of frond.providers) {
125
126
  scope.register(nameOf(provider), provider.ctor, { deps: provider.deps });
126
127
  }
128
+ // What this frond puts in front of one of the framework's own ports. Its own, like every
129
+ // provider — a link goes where its frond goes, which is what a frond behind `remotes:`
130
+ // takes with it.
131
+ const seams = seamChains(frond.providers, options.ports);
132
+ for (const [seam, links] of seams) {
133
+ boundPorts.add(seam);
134
+ frondLog.debug(`seam ${seam} → ${links.map((one) => one.ctor.name).join(' → ')} → the realization`);
135
+ }
127
136
  // …and again under the port each one extends, so `private payment: Payment`
128
137
  // reaches the realization instead of the base class it is declared against.
129
138
  // Registered AFTER the loop above so a port key always wins over the base's
130
139
  // own registration — same precedence as a declared repository over its default.
131
140
  for (const [port, chain] of portBindings(frond.providers, (n) => scope.has(n), options.ports)) {
141
+ // A seam is bound where its realization is BUILT, not under a container key — nothing
142
+ // resolves `Storage`, and `<Entity>Storage` is what a handler asks for.
143
+ if (SEAMS.has(port)) continue;
132
144
  // Registered from the INSIDE OUT, each wrapper asking for the one it stands in front
133
145
  // of: the container resolves a dep by NAME, so wrapping is a substituted key and
134
146
  // needs nothing of the container itself. The outermost answers under the port.
@@ -168,8 +180,12 @@ export async function installFrond(frond: FrondDescriptor, assembly: Assembly):
168
180
  ? baseStorage.output(outputSchema)
169
181
  : baseStorage;
170
182
 
183
+ // The declared chain first, then the guard OUTSIDE it: the guard hands on the value
184
+ // it parsed, so a wrapper reads what the entity says a row is rather than what
185
+ // arrived. Same order the client door has held since `StorageGuard` existed.
186
+ const linked = wrapping('Storage', seams.get('Storage') ?? [], scoped, (dep) => scope.resolve(dep));
171
187
  // Storage is a way out like the client surface — see `StorageGuard`.
172
- const guarded = new StorageGuard(entity.entityClass.getFields(), entity.name).guard(scoped);
188
+ const guarded = new StorageGuard(entity.entityClass.getFields(), entity.name).guard(linked);
173
189
  scope.registerValue(key, guarded);
174
190
 
175
191
  // The default repository IS the guarded port — it already answers every gesture a
@@ -5,6 +5,27 @@ import { targetOf } from '../prefab/prefab.js';
5
5
  import { ownedBy, repositoryKeyOf } from '../prefab/repository.js';
6
6
  import { entityOfStorageKey } from '../storage/port.js';
7
7
 
8
+ /** One name, one file: two providers under one key and the second silently replaces the first. */
9
+ export function refuseSharedName(frond: FrondDescriptor): void {
10
+ const declared = new Map<string, string>();
11
+
12
+ for (const provider of frond.providers) {
13
+ const name = nameOf(provider);
14
+ const first = declared.get(name);
15
+ if (first !== undefined) {
16
+ throw new Error(
17
+ `[provider] two files declare ${name}:\n`
18
+ + ` ${first}\n`
19
+ + ` ${provider.filePath}\n`
20
+ + ` A frond registers both under one key, so the second replaces the first and whoever `
21
+ + `asks for ${name} is handed whichever was scanned last.\n`
22
+ + ' Rename one of the two.',
23
+ );
24
+ }
25
+ declared.set(name, provider.filePath);
26
+ }
27
+ }
28
+
8
29
  /** Who owns an entity's storage. */
9
30
  export function ownersOf(providers: readonly ProviderEntry[]): Map<string, string> {
10
31
  const owners = new Map<string, string>();
package/src/boot/ports.ts CHANGED
@@ -1,5 +1,68 @@
1
1
  import { nameOf, type ProviderEntry } from '../descriptor/frond.js';
2
2
 
3
+ /**
4
+ * The framework's own ports — a class core exports that a user class may stand in front of.
5
+ *
6
+ * They differ from a port in one way, and it decides everything else: their realization is
7
+ * HANDED IN rather than scanned (`storageFactory` builds one per entity), so a class that
8
+ * extends one can only be a wrapper.
9
+ *
10
+ * The scope is the FROND, like every other provider, and there is no key that widens it: a
11
+ * link that must be everywhere is a frond that is everywhere, which `Extension.fronds`
12
+ * already answers — `@fougere/calls` brings one into every app that installs it. A
13
+ * process-wide key would break the gradient, since a frond moved behind `remotes:` would
14
+ * silently leave the reach of a link its own code never mentioned.
15
+ *
16
+ * Documented: [ports](https://fougere.dev/docs/business/ports).
17
+ */
18
+ export const SEAMS = new Set(['Storage']);
19
+
20
+ /**
21
+ * What stands in front of each seam, outermost first — the same reading `portBindings`
22
+ * does, with no realization to find.
23
+ */
24
+ export function seamChains(
25
+ providers: ProviderEntry[],
26
+ chosen: Record<string, string | readonly string[]> | undefined,
27
+ ): Map<string, ProviderEntry[]> {
28
+ const wrappers = new Map<string, ProviderEntry[]>();
29
+ for (const provider of providers) {
30
+ const seam = (Object.getPrototypeOf(provider.ctor) as { name?: string } | null)?.name;
31
+ if (!seam || !SEAMS.has(seam)) continue;
32
+ if (!provider.deps.includes(seam)) {
33
+ throw new Error(
34
+ `[ports] ${nameOf(provider)} extends ${seam}, and a seam's realization is handed in `
35
+ + `rather than declared — so a class extending one can only stand IN FRONT of it, `
36
+ + `which it says by asking for it: constructor(private inner: ${seam}).`,
37
+ );
38
+ }
39
+ wrappers.set(seam, [...(wrappers.get(seam) ?? []), provider]);
40
+ }
41
+
42
+ const bound = new Map<string, ProviderEntry[]>();
43
+ for (const [seam, all] of wrappers) bound.set(seam, chain(seam, [], all, chosen?.[seam]));
44
+
45
+ return bound;
46
+ }
47
+
48
+ /** Put the declared chain in front of an instance the framework holds, and hand back the outermost. */
49
+ export function wrapping<T extends object>(
50
+ seam: string,
51
+ links: readonly ProviderEntry[],
52
+ inner: T,
53
+ resolve: (name: string) => unknown,
54
+ ): T {
55
+ let current = inner;
56
+ // From the INSIDE out, so each link is handed the one it stands in front of — the same
57
+ // order `install.ts` registers a port's chain in, for the same reason.
58
+ for (const link of [...links].reverse()) {
59
+ const made = link.ctor as unknown as new (...args: unknown[]) => T;
60
+ current = new made(...link.deps.map((dep) => (dep === seam ? current : resolve(dep))));
61
+ }
62
+
63
+ return current;
64
+ }
65
+
3
66
  /**
4
67
  * A port is a class something already answers under, and what answers it may be a CHAIN:
5
68
  * the realization, wrapped by whoever stands in front of it.
@@ -1,4 +1,8 @@
1
- /** Remote façade — what resolve() falls back to. */
1
+ /**
2
+ * Remote façade — what resolve() falls back to.
3
+ *
4
+ * Documented: [the gradient](https://fougere.dev/docs/infra/gradient).
5
+ */
2
6
  import type { FrondCall, Transport } from '../wire/call.js';
3
7
  import { assertIdentityCard, RPC_ENTITY } from '../wire/call.js';
4
8
  import { runMiddlewares, type AppMiddleware, type OperationContext } from '../wire/middleware.js';
package/src/boot/seed.ts CHANGED
@@ -61,7 +61,11 @@ interface SeedDoor {
61
61
  write(item: unknown): Promise<unknown>;
62
62
  }
63
63
 
64
- /** Plant a set of seeds, in the order given. */
64
+ /**
65
+ * Plant a set of seeds, in the order given.
66
+ *
67
+ * Documented: [seeds](https://fougere.dev/docs/business/seeds).
68
+ */
65
69
  export async function runSeeds(
66
70
  app: App,
67
71
  seeds: SeedEntry[],
@@ -1,4 +1,8 @@
1
- /** Building a frame — what a handler asking for `Together<[…]>` receives. */
1
+ /**
2
+ * Building a frame — what a handler asking for `Together<[…]>` receives.
3
+ *
4
+ * Documented: [together](https://fougere.dev/docs/business/together).
5
+ */
2
6
  import { ambient } from '#ambient';
3
7
  import { upperFirst, lowerFirst, type SchemaView } from '@fougere/schema';
4
8
  import type { Container } from '@fougere/container';
package/src/boot/types.ts CHANGED
@@ -137,9 +137,9 @@ export interface App extends DispatchPort {
137
137
  extensions(): string[];
138
138
  /** Declare one `rpc` op — what the app says about ITSELF, beside the card. */
139
139
  serveRpc(operationName: string, answer: RpcAnswer): void;
140
- /** Register a global app middleware (runs on every operation). */
141
140
  /** Watch every dispatch transition; the returned function unsubscribes. */
142
141
  observe(observer: DispatchObserver): () => void;
142
+ /** Register a global app middleware (runs on every operation). */
143
143
  use(middleware: AppMiddleware): void;
144
144
  /** Register an app middleware scoped to a specific entity. */
145
145
  use(entity: string, middleware: AppMiddleware): void;
@@ -13,11 +13,9 @@ export interface LogRecord {
13
13
  at: number;
14
14
  }
15
15
 
16
+ /** Where a line goes once it is written — `@fougere/log` ships one, `observability` another. */
16
17
  export type LogSink = (record: LogRecord) => void;
17
18
 
18
- /** Who else takes this process's log lines, beside the console. */
19
- const sinks: LogSink[] = [];
20
-
21
19
  /**
22
20
  * Where one boot's lines wait, and where they go once they can.
23
21
  *
@@ -66,15 +64,6 @@ export class Carry {
66
64
  }
67
65
  }
68
66
 
69
- /** Take every line this process logs. Returns the way to withdraw. */
70
- export function onLog(next: LogSink): () => void {
71
- sinks.push(next);
72
- return () => {
73
- const at = sinks.indexOf(next);
74
- if (at >= 0) sinks.splice(at, 1);
75
- };
76
- }
77
-
78
67
  const LEVELS: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3, silent: 4 };
79
68
 
80
69
  /** The level, held ONCE for the process and CONSULTED at every emission. */
@@ -176,14 +165,6 @@ export class Logger {
176
165
  level: level as LogRecord['level'], name: this.name, message: msg, args, at: Date.now(),
177
166
  };
178
167
 
179
- // Beside the console, never instead of it: a forwarded line is an addition, and a
180
- // sink that throws must not cost the operator the line they were reading.
181
- for (const take of sinks) {
182
- try {
183
- take(record);
184
- } catch { /* forwarding never breaks logging */ }
185
- }
186
-
187
168
  this.carry?.push(record);
188
169
 
189
170
  // The console ALWAYS, whoever else took the line. Skipping it once a destination
@@ -21,7 +21,6 @@ export interface FougereConfig {
21
21
  logLevel?: LogLevel;
22
22
  /** Remote fronds — frondName → base URL. */
23
23
  remotes?: Record<string, string>;
24
- /** Which realization answers which port — port class name → implementation class name. */
25
24
  /** What answers a port — a name, or the chain from the outside in. */
26
25
  ports?: Record<string, string | readonly string[]>;
27
26
  /** Auth declaration — picks a provider package and forwards options to it. */
package/src/contract.ts CHANGED
@@ -30,7 +30,10 @@ export { driftOf, agrees, explain } from './wire/drift.js';
30
30
  export type { CardDrift } from './wire/drift.js';
31
31
 
32
32
  /** What `rpc.discover` answers. */
33
- export type { IdentityCard, CardOp, TopologyReport, FrondPlacement, Edge } from './wire/call.js';
33
+ export type {
34
+ IdentityCard, CardOp, TopologyReport, FrondPlacement, Edge,
35
+ DeclaredTopology, DeclaredFrond, DeclaredEdge,
36
+ } from './wire/call.js';
34
37
  export { assertIdentityCard } from './wire/call.js';
35
38
 
36
39
  /** The key a class name is filed under — 'Post' → 'post'. */
@@ -1,4 +1,8 @@
1
- /** What a frond is made of — one interface per convention directory. */
1
+ /**
2
+ * What a frond is made of — one interface per convention directory.
3
+ *
4
+ * Documented: [the Frond](https://fougere.dev/docs/concepts/frond).
5
+ */
2
6
  import type { SchemaView } from '@fougere/schema';
3
7
  import type { Param, OperationContract, OperationsMap } from '../wire/operation.js';
4
8
  import type { PresenterViews } from '../prefab/presenter.js';
@@ -1,6 +1,7 @@
1
1
  /** The operation model after every declaration and convention has been resolved. */
2
2
  import { lowerFirst, type SchemaView } from '@fougere/schema';
3
3
  import { statementDrift } from './boot/statement-drift.js';
4
+ import { reachedBy, servedBy } from './boot/declared.js';
4
5
  import { computeBindingPlan, type BindingPlan } from './wire/binding.js';
5
6
  import { targetOf } from './prefab/prefab.js';
6
7
  import type { CollectorEntry, FrondDescriptor, HandlerEntry } from './descriptor/frond.js';
@@ -69,6 +70,23 @@ export interface EffectiveOperation extends OperationContract {
69
70
  runtime: 'local' | 'remote';
70
71
  remote?: string;
71
72
  };
73
+ /**
74
+ * What running this op reaches, and how much of that crosses a process.
75
+ *
76
+ * `placement` says where the op ANSWERS; this says where it GOES. The pair is what every
77
+ * number a process hard-codes is really a function of — how often a trace is sampled, where
78
+ * a latency histogram's bounds should sit, what a load threshold may assume. An op that
79
+ * answers here and hops twice is not the same subject as one that answers here and hops none.
80
+ *
81
+ * Read from the handler, never from the op: a dependency is declared on the constructor, so
82
+ * the crossing belongs to the CLASS. Every op of one handler reaches the same fronds, and
83
+ * saying otherwise would dress a structural fact as a precise effect.
84
+ */
85
+ reach: {
86
+ fronds: { frond: string; runtime: 'local' | 'remote' }[];
87
+ /** How many of them are a process away — zero when everything it reaches runs here. */
88
+ hops: number;
89
+ };
72
90
  exposure: {
73
91
  surfaces: string[];
74
92
  adapters: string[];
@@ -80,6 +98,26 @@ export interface EffectiveOperation extends OperationContract {
80
98
 
81
99
  export type EffectiveOperationsMap = Map<string, EffectiveOperation>;
82
100
 
101
+ /**
102
+ * Where an op's work goes: the fronds its handler reaches, and how many are a process away.
103
+ *
104
+ * A frond this app never scanned is not among them. The report can say a call LEFT — that is
105
+ * `placement` — but naming what is on the far side of an address means reading its card, and a
106
+ * card is a discovery rather than a declaration.
107
+ */
108
+ function reachOf(
109
+ deps: readonly string[],
110
+ from: string,
111
+ index: Map<string, string>,
112
+ remotes: Record<string, string>,
113
+ ): EffectiveOperation['reach'] {
114
+ const fronds = reachedBy(deps, from, index)
115
+ .sort()
116
+ .map((frond) => ({ frond, runtime: (remotes[frond] ? 'remote' : 'local') as 'local' | 'remote' }));
117
+
118
+ return { fronds, hops: fronds.filter((one) => one.runtime === 'remote').length };
119
+ }
120
+
83
121
  /** The absence rules every door normalises to before the handler is invoked. */
84
122
  export const EFFECTIVE_OPERATION_SEMANTICS = Object.freeze({
85
123
  optional: 'undefined' as const,
@@ -131,6 +169,8 @@ export function resolveEffectiveOperations(
131
169
  const schemas = new Map(
132
170
  fronds.flatMap((frond) => frond.entities.map((entity) => [entity.name, entity.entityClass] as const)),
133
171
  );
172
+ /** Every address a frond answers, so a dependency naming one is read as the crossing it is. */
173
+ const served = servedBy(fronds);
134
174
 
135
175
  // Input ambiguity is produced where schemas are available (the scanner), but it is a
136
176
  // resolution failure. Lift it into the same refusal table as kind/binding/topology.
@@ -285,6 +325,7 @@ export function resolveEffectiveOperations(
285
325
  runtime: remote ? 'remote' : 'local',
286
326
  ...(remote ? { remote } : {}),
287
327
  },
328
+ reach: reachOf(handler.deps, frond.name, served, options.remotes ?? {}),
288
329
  exposure: {
289
330
  surfaces: servedSurfaces(frond, handler).map((surface) => surface ?? 'default'),
290
331
  adapters: exposedAdapters(handler, options.adapters),
package/src/identity.ts CHANGED
@@ -1,4 +1,8 @@
1
- /** Who is calling — the proof, not the claim. */
1
+ /**
2
+ * Who is calling — the proof, not the claim.
3
+ *
4
+ * Documented: [identity](https://fougere.dev/docs/infra/identity).
5
+ */
2
6
  import { crypto } from '#crypto';
3
7
  import type { PublicJwk, Signer, Verifier } from './crypto/port.js';
4
8
  import { b64url, unb64url, bytesOf, textOf, unb64 } from './crypto/encoding.js';
package/src/index.ts CHANGED
@@ -48,6 +48,9 @@ export type { Declared, FrondDeclaration, DeclaredSubject } from './declare.js';
48
48
  // only by tests through a deep path — a consumer comparing its own card to a producer's
49
49
  // had to dispatch a call to ask a question about itself.
50
50
  export { identityCardOf } from './boot/card.js';
51
+ // Its dual: what the app declares about its NEIGHBOURS. Read by `rpc.topology`, by
52
+ // `@fougere/calls` and by `fougere graph`, which each held their own half of it.
53
+ export { declaredTopologyOf } from './boot/declared.js';
51
54
  export type { Facade } from './wire/call.js';
52
55
  export type {
53
56
  FrondCall,
@@ -57,21 +60,25 @@ export type {
57
60
  TopologyReport,
58
61
  FrondPlacement,
59
62
  Edge,
63
+ DeclaredTopology,
64
+ DeclaredFrond,
65
+ DeclaredEdge,
60
66
  } from './contract.js';
61
67
  export { type Emit, type Fact, type Pipe } from './wire/emit.js';
62
68
  export { callValueOf } from './contract.js';
63
69
  export { toHttpError } from './wire/http-error.js';
64
70
  export { toPublicError } from './contract.js';
65
71
  export { loggerMiddleware } from './wire/loggerMiddleware.js';
66
- export { Carry, Logger, setLogLevel, logLevel, envLevel, onLog, formatted } from './builtin/logger.js';
72
+ export { Carry, Logger, setLogLevel, logLevel, envLevel, formatted } from './builtin/logger.js';
67
73
  export type { LogRecord, Rendered, LogSink } from './builtin/logger.js';
68
74
  // The fact a boot announces. Its destinations are `@fougere/log`'s; the line is core's.
69
75
  export { default as LogLine, CARRIES_LINE, LOG_LINE } from './builtin/LogLine.js';
70
76
  // What a re-read config changes in a running process — and what it cannot.
71
77
  export { applyConfig } from './boot/apply.js';
72
78
  export { Config } from './builtin/config.js';
73
- export type { Storage, StorageFactory, ListOptions, ListResult, Together } from './storage/port.js';
74
- export { togetherKeyOf } from './storage/port.js';
79
+ export type { StorageFactory, ListOptions, ListResult, Together } from './storage/port.js';
80
+ // A VALUE as well as a type: it is what a wrapper extends, which is the whole of declaring one.
81
+ export { Storage, togetherKeyOf } from './storage/port.js';
75
82
  export type { Constraint, Source, SourceConfig, SourceView } from './source.js';
76
83
  export { Sources } from './source.js';
77
84
  export { storageOver } from './storage/store.js';
@@ -1,4 +1,8 @@
1
- /** Collector(Type) — resolves one handler input parameter from the invocation context. */
1
+ /**
2
+ * Collector(Type) — resolves one handler input parameter from the invocation context.
3
+ *
4
+ * Documented: [collectors](https://fougere.dev/docs/business/collectors).
5
+ */
2
6
 
3
7
  import { upperFirst } from '@fougere/schema';
4
8