@fougere/core 0.9.0-alpha.1 → 0.9.2-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 (91) 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/install.d.ts.map +1 -1
  9. package/dist/boot/install.js +18 -2
  10. package/dist/boot/install.js.map +1 -1
  11. package/dist/boot/ports.d.ts +23 -0
  12. package/dist/boot/ports.d.ts.map +1 -1
  13. package/dist/boot/ports.js +49 -0
  14. package/dist/boot/ports.js.map +1 -1
  15. package/dist/boot/remote.d.ts +5 -1
  16. package/dist/boot/remote.d.ts.map +1 -1
  17. package/dist/boot/remote.js.map +1 -1
  18. package/dist/boot/seed.d.ts +5 -1
  19. package/dist/boot/seed.d.ts.map +1 -1
  20. package/dist/boot/seed.js +5 -1
  21. package/dist/boot/seed.js.map +1 -1
  22. package/dist/boot/together.d.ts.map +1 -1
  23. package/dist/boot/together.js +5 -1
  24. package/dist/boot/together.js.map +1 -1
  25. package/dist/builtin/logger.d.ts +1 -2
  26. package/dist/builtin/logger.d.ts.map +1 -1
  27. package/dist/builtin/logger.js +0 -19
  28. package/dist/builtin/logger.js.map +1 -1
  29. package/dist/descriptor/frond.d.ts +5 -1
  30. package/dist/descriptor/frond.d.ts.map +1 -1
  31. package/dist/descriptor/frond.js.map +1 -1
  32. package/dist/identity.d.ts.map +1 -1
  33. package/dist/identity.js +5 -1
  34. package/dist/identity.js.map +1 -1
  35. package/dist/index.d.ts +3 -3
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +3 -2
  38. package/dist/index.js.map +1 -1
  39. package/dist/prefab/collector.d.ts +5 -1
  40. package/dist/prefab/collector.d.ts.map +1 -1
  41. package/dist/prefab/collector.js +5 -1
  42. package/dist/prefab/collector.js.map +1 -1
  43. package/dist/prefab/crud.d.ts +9 -5
  44. package/dist/prefab/crud.d.ts.map +1 -1
  45. package/dist/prefab/crud.js +9 -5
  46. package/dist/prefab/crud.js.map +1 -1
  47. package/dist/prefab/mirror.d.ts +5 -1
  48. package/dist/prefab/mirror.d.ts.map +1 -1
  49. package/dist/prefab/mirror.js.map +1 -1
  50. package/dist/prefab/presenter.d.ts +6 -2
  51. package/dist/prefab/presenter.d.ts.map +1 -1
  52. package/dist/prefab/presenter.js +6 -2
  53. package/dist/prefab/presenter.js.map +1 -1
  54. package/dist/prefab/repository.d.ts +5 -1
  55. package/dist/prefab/repository.d.ts.map +1 -1
  56. package/dist/prefab/repository.js.map +1 -1
  57. package/dist/source.d.ts +5 -1
  58. package/dist/source.d.ts.map +1 -1
  59. package/dist/source.js.map +1 -1
  60. package/dist/storage/port.d.ts +27 -1
  61. package/dist/storage/port.d.ts.map +1 -1
  62. package/dist/storage/port.js +70 -0
  63. package/dist/storage/port.js.map +1 -1
  64. package/dist/wire/emit.d.ts.map +1 -1
  65. package/dist/wire/emit.js +5 -1
  66. package/dist/wire/emit.js.map +1 -1
  67. package/dist/wire/errors.d.ts +5 -1
  68. package/dist/wire/errors.d.ts.map +1 -1
  69. package/dist/wire/errors.js +5 -1
  70. package/dist/wire/errors.js.map +1 -1
  71. package/package.json +4 -4
  72. package/src/boot/AppLifecycle.ts +5 -1
  73. package/src/boot/apply.ts +5 -1
  74. package/src/boot/install.ts +18 -3
  75. package/src/boot/ports.ts +63 -0
  76. package/src/boot/remote.ts +5 -1
  77. package/src/boot/seed.ts +5 -1
  78. package/src/boot/together.ts +5 -1
  79. package/src/builtin/logger.ts +1 -20
  80. package/src/descriptor/frond.ts +5 -1
  81. package/src/identity.ts +5 -1
  82. package/src/index.ts +4 -3
  83. package/src/prefab/collector.ts +5 -1
  84. package/src/prefab/crud.ts +9 -5
  85. package/src/prefab/mirror.ts +5 -1
  86. package/src/prefab/presenter.ts +6 -2
  87. package/src/prefab/repository.ts +5 -1
  88. package/src/source.ts +5 -1
  89. package/src/storage/port.ts +74 -1
  90. package/src/wire/emit.ts +5 -1
  91. package/src/wire/errors.ts +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/wire/errors.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIvD,0FAA0F;AAC1F,oBAAY,SAAS;IAEnB,iBAAiB,sBAAsB;IACvC,WAAW,gBAAgB;IAG3B,YAAY,iBAAiB;IAC7B,SAAS,cAAc;IAGvB,SAAS,cAAc;IACvB,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,kBAAkB,uBAAuB;IAGzC,mBAAmB,wBAAwB;IAC3C,iBAAiB,sBAAsB;IACvC,oBAAoB,yBAAyB;IAC7C,iBAAiB,sBAAsB;IACvC,eAAe,oBAAoB;IAGnC,cAAc,mBAAmB;IACjC,eAAe,oBAAoB;IACnC,WAAW,gBAAgB;IAC3B,mBAAmB,wBAAwB;IAC3C,eAAe,oBAAoB;CACpC;AAID,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;gBAEf,OAAO,EAAE,mBAAmB;IASxC,MAAM;;;;;;;IAUN,iEAAiE;IACjE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY;CAW7C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,EAAE,GAAG,SAAS,CAWhF"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/wire/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIvD,0FAA0F;AAC1F,oBAAY,SAAS;IAEnB,iBAAiB,sBAAsB;IACvC,WAAW,gBAAgB;IAG3B,YAAY,iBAAiB;IAC7B,SAAS,cAAc;IAGvB,SAAS,cAAc;IACvB,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,kBAAkB,uBAAuB;IAGzC,mBAAmB,wBAAwB;IAC3C,iBAAiB,sBAAsB;IACvC,oBAAoB,yBAAyB;IAC7C,iBAAiB,sBAAsB;IACvC,eAAe,oBAAoB;IAGnC,cAAc,mBAAmB;IACjC,eAAe,oBAAoB;IACnC,WAAW,gBAAgB;IAC3B,mBAAmB,wBAAwB;IAC3C,eAAe,oBAAoB;CACpC;AAID,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;gBAEf,OAAO,EAAE,mBAAmB;IASxC,MAAM;;;;;;;IAUN,iEAAiE;IACjE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY;CAW7C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,EAAE,GAAG,SAAS,CAWhF"}
@@ -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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"}
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.2-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.2-alpha.0",
65
+ "@fougere/schema": "0.9.2-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.2-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[] = [];
@@ -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';
@@ -16,7 +16,7 @@ import { HandlerFacade } from '../dispatch/HandlerFacade.js';
16
16
  import { targetOf } from '../prefab/prefab.js';
17
17
  import { ownersOf, 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';
@@ -124,11 +124,22 @@ export async function installFrond(frond: FrondDescriptor, assembly: Assembly):
124
124
  for (const provider of frond.providers) {
125
125
  scope.register(nameOf(provider), provider.ctor, { deps: provider.deps });
126
126
  }
127
+ // What this frond puts in front of one of the framework's own ports. Its own, like every
128
+ // provider — a link goes where its frond goes, which is what a frond behind `remotes:`
129
+ // takes with it.
130
+ const seams = seamChains(frond.providers, options.ports);
131
+ for (const [seam, links] of seams) {
132
+ boundPorts.add(seam);
133
+ frondLog.debug(`seam ${seam} → ${links.map((one) => one.ctor.name).join(' → ')} → the realization`);
134
+ }
127
135
  // …and again under the port each one extends, so `private payment: Payment`
128
136
  // reaches the realization instead of the base class it is declared against.
129
137
  // Registered AFTER the loop above so a port key always wins over the base's
130
138
  // own registration — same precedence as a declared repository over its default.
131
139
  for (const [port, chain] of portBindings(frond.providers, (n) => scope.has(n), options.ports)) {
140
+ // A seam is bound where its realization is BUILT, not under a container key — nothing
141
+ // resolves `Storage`, and `<Entity>Storage` is what a handler asks for.
142
+ if (SEAMS.has(port)) continue;
132
143
  // Registered from the INSIDE OUT, each wrapper asking for the one it stands in front
133
144
  // of: the container resolves a dep by NAME, so wrapping is a substituted key and
134
145
  // needs nothing of the container itself. The outermost answers under the port.
@@ -168,8 +179,12 @@ export async function installFrond(frond: FrondDescriptor, assembly: Assembly):
168
179
  ? baseStorage.output(outputSchema)
169
180
  : baseStorage;
170
181
 
182
+ // The declared chain first, then the guard OUTSIDE it: the guard hands on the value
183
+ // it parsed, so a wrapper reads what the entity says a row is rather than what
184
+ // arrived. Same order the client door has held since `StorageGuard` existed.
185
+ const linked = wrapping('Storage', seams.get('Storage') ?? [], scoped, (dep) => scope.resolve(dep));
171
186
  // Storage is a way out like the client surface — see `StorageGuard`.
172
- const guarded = new StorageGuard(entity.entityClass.getFields(), entity.name).guard(scoped);
187
+ const guarded = new StorageGuard(entity.entityClass.getFields(), entity.name).guard(linked);
173
188
  scope.registerValue(key, guarded);
174
189
 
175
190
  // The default repository IS the guarded port — it already answers every gesture a
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';
@@ -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
@@ -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';
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
@@ -63,15 +63,16 @@ export { callValueOf } from './contract.js';
63
63
  export { toHttpError } from './wire/http-error.js';
64
64
  export { toPublicError } from './contract.js';
65
65
  export { loggerMiddleware } from './wire/loggerMiddleware.js';
66
- export { Carry, Logger, setLogLevel, logLevel, envLevel, onLog, formatted } from './builtin/logger.js';
66
+ export { Carry, Logger, setLogLevel, logLevel, envLevel, formatted } from './builtin/logger.js';
67
67
  export type { LogRecord, Rendered, LogSink } from './builtin/logger.js';
68
68
  // The fact a boot announces. Its destinations are `@fougere/log`'s; the line is core's.
69
69
  export { default as LogLine, CARRIES_LINE, LOG_LINE } from './builtin/LogLine.js';
70
70
  // What a re-read config changes in a running process — and what it cannot.
71
71
  export { applyConfig } from './boot/apply.js';
72
72
  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';
73
+ export type { StorageFactory, ListOptions, ListResult, Together } from './storage/port.js';
74
+ // A VALUE as well as a type: it is what a wrapper extends, which is the whole of declaring one.
75
+ export { Storage, togetherKeyOf } from './storage/port.js';
75
76
  export type { Constraint, Source, SourceConfig, SourceView } from './source.js';
76
77
  export { Sources } from './source.js';
77
78
  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
 
@@ -4,8 +4,8 @@ import type { OperationContract } from '../wire/operation.js';
4
4
  import { targetOf } from './prefab.js';
5
5
 
6
6
  /**
7
- * So a class is recognized by what it ANSWERS, since the mixin leaves no other trace.
8
- * FR : pour qu'une classe se reconnaisse à ce qu'elle répond, le mixin ne laissant rien d'autre.
7
+ * A class is recognized by what it ANSWERS the mixin leaves no other trace.
8
+ * FR : une classe se reconnaît à ce qu'elle répond, le mixin ne laissant rien d'autre.
9
9
  * `inheritsCrud(class PostHandler extends Crud(Post) {})` → `true`
10
10
  */
11
11
  export function inheritsCrud(ctor: unknown): boolean {
@@ -15,8 +15,8 @@ export function inheritsCrud(ctor: unknown): boolean {
15
15
  }
16
16
 
17
17
  /**
18
- * So storage follows the shape the handler was built on, which may differ from its address.
19
- * FR : pour que le stockage suive la forme sur laquelle le handler est bâti.
18
+ * Storage follows the shape the handler was built on, which may differ from its address.
19
+ * FR : le stockage suit la forme sur laquelle le handler est bâti, pas son adresse.
20
20
  * `subjectOf(class Draft extends Crud(Post) {}, 'draft')` → `'post'`
21
21
  */
22
22
  export function subjectOf(ctor: unknown, address: string): string {
@@ -112,7 +112,11 @@ export interface CrudConstructor<T, V = {}> {
112
112
  readonly __ops: Record<string, OperationContract>;
113
113
  }
114
114
 
115
- /** Mixin — extends Crud(Entity) to get all 5 typed CRUD methods. */
115
+ /**
116
+ * Mixin — extends Crud(Entity) to get all 5 typed CRUD methods.
117
+ *
118
+ * Documented: [handlers](https://fougere.dev/docs/business/handlers).
119
+ */
116
120
  export function Crud<E extends EntityConstructor, V extends CrudViews | EntityConstructor = {}>(
117
121
  entity: E,
118
122
  output?: V,
@@ -11,7 +11,11 @@ export interface Refreshed {
11
11
  ms: number;
12
12
  }
13
13
 
14
- /** A paginated local copy of a source that cannot be queried directly. */
14
+ /**
15
+ * A paginated local copy of a source that cannot be queried directly.
16
+ *
17
+ * Documented: [the base](https://fougere.dev/docs/concepts/the-base).
18
+ */
15
19
  export interface MirrorOf<T> {
16
20
  /** The copy's own storage — where a page lands. */
17
21
  storage: Storage<T>;
@@ -1,4 +1,8 @@
1
- /** Presenter(Entity) — enriches an entity's output with computed fields. */
1
+ /**
2
+ * Presenter(Entity) — enriches an entity's output with computed fields.
3
+ *
4
+ * Documented: [presenters](https://fougere.dev/docs/business/presenters).
5
+ */
2
6
 
3
7
  import { upperFirst, type EntityConstructor } from '@fougere/schema';
4
8
 
@@ -8,7 +12,7 @@ import { upperFirst, type EntityConstructor } from '@fougere/schema';
8
12
  */
9
13
  export type PresenterViews = Record<string, EntityConstructor | [EntityConstructor]>;
10
14
 
11
- /** `Presenter(Order, { items. */
15
+ /** `Presenter(Order, { items: [OrderItemView] })` — the views its computed fields emit. */
12
16
  export function Presenter<E extends EntityConstructor>(entity: E, views?: PresenterViews) {
13
17
  class PresenterBase {
14
18
  static readonly __entity = entity;
@@ -2,7 +2,11 @@ import { upperFirst, type EntityConstructor } from '@fougere/schema';
2
2
  import type { Storage, ListOptions, ListResult, SelectOption } from '../storage/port.js';
3
3
  import type { SchemaView } from '@fougere/schema';
4
4
 
5
- /** Repository(…entities) — who owns an entity's storage, and where its questions are named. */
5
+ /**
6
+ * Repository(…entities) — who owns an entity's storage, and where its questions are named.
7
+ *
8
+ * Documented: [repositories](https://fougere.dev/docs/business/repositories).
9
+ */
6
10
 
7
11
  /**
8
12
  * The shape a repository of ONE entity has — the port itself, plus whatever the subclass names on
package/src/source.ts CHANGED
@@ -12,7 +12,11 @@ export function declares(schema: SchemaView, constraint: Constraint): boolean {
12
12
  return Object.values(schema.getFields()).some((field) => Role.of(field).isUnique);
13
13
  }
14
14
 
15
- /** A place rows live, whatever realizes it. */
15
+ /**
16
+ * A place rows live, whatever realizes it.
17
+ *
18
+ * Documented: [sources](https://fougere.dev/docs/infra/sources).
19
+ */
16
20
  export interface Source {
17
21
  storageFactory: StorageFactory;
18
22
  /**
@@ -102,8 +102,81 @@ export interface Storage<T = Record<string, unknown>> {
102
102
  delete(id: string): Promise<boolean>;
103
103
  /** Returns a scoped storage that restricts all read results to the fields of the given schema. */
104
104
  output(schema: SchemaView): Storage<T>;
105
+ }
106
+
107
+ /**
108
+ * What each link of a chain stands in front of.
109
+ *
110
+ * A SYMBOL on the instance, set through a cast so it joins no declaration: `Storage` is an
111
+ * interface as well as a class, and the realizations satisfy it structurally —
112
+ * `storageOver` returns an object literal, and one more member would stop it being a
113
+ * storage. A `#private` field says the same thing and makes the class NOMINAL, which
114
+ * refuses every realization at once.
115
+ *
116
+ * On the instance and not in a `WeakMap` beside it, because `StorageGuard.guard` hands out
117
+ * `Object.create(storage)` — a new object whose prototype is the link. A symbol is found
118
+ * through that chain; a map keyed on the link is not, and the guarded object read
119
+ * `undefined`.
120
+ */
121
+ const BEHIND = Symbol('fougere.storage.behind');
122
+
123
+ const behind = <T>(link: object): Storage<T> =>
124
+ (link as Record<symbol, unknown>)[BEHIND] as Storage<T>;
125
+
126
+ /**
127
+ * A storage that stands in front of another — the base a wrapper extends, and the only
128
+ * thing that makes `Storage` a seam rather than a shape.
129
+ *
130
+ * Merged with the interface above, so the class carries the thirteen gestures as a TYPE
131
+ * while its prototype carries them as a FORWARD. A wrapper writes what it changes and
132
+ * nothing else:
133
+ *
134
+ * ```ts
135
+ * class Audit extends Storage {
136
+ * constructor(private inner: Storage) { super(inner); }
137
+ * async create(row) { await say(row); return this.inner.create(row); }
138
+ * }
139
+ * ```
140
+ *
141
+ * `ports: { Storage: ['Audit'] }` orders the chain when a frond declares two, which is the
142
+ * same key, the same order and the same refusals a port gets. A realization does not extend
143
+ * this: it is handed in by `storageFactory` and is the last link, so what a wrapper does not
144
+ * override reaches it through these forwards.
145
+ *
146
+ * Documented: [storage](https://fougere.dev/docs/business/storage) and
147
+ * [ports](https://fougere.dev/docs/business/ports).
148
+ */
149
+ export abstract class Storage<T = Record<string, unknown>> {
150
+ constructor(inner: Storage<T>) {
151
+ (this as Record<symbol, unknown>)[BEHIND] = inner;
152
+ }
153
+
154
+ list(options?: ListOptions & SelectOption): Promise<ListResult<T>> { return behind<T>(this).list(options); }
155
+ findById(id: string, options?: SelectOption): Promise<T | undefined> { return behind<T>(this).findById(id, options); }
156
+ findBy(criteria: Partial<T> | Record<string, unknown>, options?: SelectOption): Promise<T | undefined> {
157
+ return behind<T>(this).findBy(criteria, options);
158
+ }
159
+ findAllBy(criteria: Partial<T> | Record<string, unknown>, options?: SelectOption): Promise<T[]> {
160
+ return behind<T>(this).findAllBy(criteria, options);
161
+ }
162
+ findByKeys(ids: readonly string[], options?: SelectOption): Promise<Map<string, T>> {
163
+ return behind<T>(this).findByKeys(ids, options);
164
+ }
165
+ findAllByKeys(field: string, keys: readonly string[], options?: SelectOption): Promise<Map<string, T[]>> {
166
+ return behind<T>(this).findAllByKeys(field, keys, options);
167
+ }
168
+ create(input: Partial<T>, options?: SelectOption): Promise<T> { return behind<T>(this).create(input, options); }
169
+ upsert(input: Partial<T>, options?: SelectOption): Promise<T> { return behind<T>(this).upsert(input, options); }
170
+ upsertAll(inputs: readonly Partial<T>[], options?: SelectOption): Promise<number> {
171
+ return behind<T>(this).upsertAll(inputs, options);
172
+ }
173
+ update(id: string, input: Partial<T>, options?: SelectOption): Promise<T> {
174
+ return behind<T>(this).update(id, input, options);
175
+ }
176
+ delete(id: string): Promise<boolean> { return behind<T>(this).delete(id); }
177
+ output(schema: SchemaView): Storage<T> { return behind<T>(this).output(schema); }
105
178
  /** What this storage wraps — the Kysely instance for the SQL one, something else elsewhere. */
106
- readonly client: unknown;
179
+ get client(): unknown { return behind<T>(this).client; }
107
180
  }
108
181
 
109
182
  /**
package/src/wire/emit.ts CHANGED
@@ -1,4 +1,8 @@
1
- /** Announcing a fact — the half of the topology `remotes:` never covered. */
1
+ /**
2
+ * Announcing a fact — the half of the topology `remotes:` never covered.
3
+ *
4
+ * Documented: [facts](https://fougere.dev/docs/business/facts).
5
+ */
2
6
  import { lowerFirst } from '@fougere/schema';
3
7
 
4
8
  /**
@@ -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
 
3
7
  import type { ValidationError } from '@fougere/schema';
4
8