@fougere/core 0.9.0-alpha.0 → 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 (99) 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/bootstrap.d.ts.map +1 -1
  9. package/dist/boot/bootstrap.js +21 -15
  10. package/dist/boot/bootstrap.js.map +1 -1
  11. package/dist/boot/card.d.ts.map +1 -1
  12. package/dist/boot/card.js +6 -1
  13. package/dist/boot/card.js.map +1 -1
  14. package/dist/boot/install.d.ts.map +1 -1
  15. package/dist/boot/install.js +18 -2
  16. package/dist/boot/install.js.map +1 -1
  17. package/dist/boot/ports.d.ts +23 -0
  18. package/dist/boot/ports.d.ts.map +1 -1
  19. package/dist/boot/ports.js +49 -0
  20. package/dist/boot/ports.js.map +1 -1
  21. package/dist/boot/remote.d.ts +5 -1
  22. package/dist/boot/remote.d.ts.map +1 -1
  23. package/dist/boot/remote.js.map +1 -1
  24. package/dist/boot/seed.d.ts +5 -1
  25. package/dist/boot/seed.d.ts.map +1 -1
  26. package/dist/boot/seed.js +5 -1
  27. package/dist/boot/seed.js.map +1 -1
  28. package/dist/boot/together.d.ts.map +1 -1
  29. package/dist/boot/together.js +5 -1
  30. package/dist/boot/together.js.map +1 -1
  31. package/dist/builtin/logger.d.ts +1 -2
  32. package/dist/builtin/logger.d.ts.map +1 -1
  33. package/dist/builtin/logger.js +0 -19
  34. package/dist/builtin/logger.js.map +1 -1
  35. package/dist/descriptor/frond.d.ts +5 -1
  36. package/dist/descriptor/frond.d.ts.map +1 -1
  37. package/dist/descriptor/frond.js.map +1 -1
  38. package/dist/identity.d.ts.map +1 -1
  39. package/dist/identity.js +5 -1
  40. package/dist/identity.js.map +1 -1
  41. package/dist/index.d.ts +3 -3
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +3 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/prefab/collector.d.ts +5 -1
  46. package/dist/prefab/collector.d.ts.map +1 -1
  47. package/dist/prefab/collector.js +5 -1
  48. package/dist/prefab/collector.js.map +1 -1
  49. package/dist/prefab/crud.d.ts +9 -5
  50. package/dist/prefab/crud.d.ts.map +1 -1
  51. package/dist/prefab/crud.js +9 -5
  52. package/dist/prefab/crud.js.map +1 -1
  53. package/dist/prefab/mirror.d.ts +5 -1
  54. package/dist/prefab/mirror.d.ts.map +1 -1
  55. package/dist/prefab/mirror.js.map +1 -1
  56. package/dist/prefab/presenter.d.ts +6 -2
  57. package/dist/prefab/presenter.d.ts.map +1 -1
  58. package/dist/prefab/presenter.js +6 -2
  59. package/dist/prefab/presenter.js.map +1 -1
  60. package/dist/prefab/repository.d.ts +5 -1
  61. package/dist/prefab/repository.d.ts.map +1 -1
  62. package/dist/prefab/repository.js.map +1 -1
  63. package/dist/source.d.ts +5 -1
  64. package/dist/source.d.ts.map +1 -1
  65. package/dist/source.js.map +1 -1
  66. package/dist/storage/port.d.ts +27 -1
  67. package/dist/storage/port.d.ts.map +1 -1
  68. package/dist/storage/port.js +70 -0
  69. package/dist/storage/port.js.map +1 -1
  70. package/dist/wire/emit.d.ts.map +1 -1
  71. package/dist/wire/emit.js +5 -1
  72. package/dist/wire/emit.js.map +1 -1
  73. package/dist/wire/errors.d.ts +5 -1
  74. package/dist/wire/errors.d.ts.map +1 -1
  75. package/dist/wire/errors.js +5 -1
  76. package/dist/wire/errors.js.map +1 -1
  77. package/package.json +4 -4
  78. package/src/boot/AppLifecycle.ts +5 -1
  79. package/src/boot/apply.ts +5 -1
  80. package/src/boot/bootstrap.ts +21 -15
  81. package/src/boot/card.ts +6 -1
  82. package/src/boot/install.ts +18 -3
  83. package/src/boot/ports.ts +63 -0
  84. package/src/boot/remote.ts +5 -1
  85. package/src/boot/seed.ts +5 -1
  86. package/src/boot/together.ts +5 -1
  87. package/src/builtin/logger.ts +1 -20
  88. package/src/descriptor/frond.ts +5 -1
  89. package/src/identity.ts +5 -1
  90. package/src/index.ts +4 -3
  91. package/src/prefab/collector.ts +5 -1
  92. package/src/prefab/crud.ts +9 -5
  93. package/src/prefab/mirror.ts +5 -1
  94. package/src/prefab/presenter.ts +6 -2
  95. package/src/prefab/repository.ts +5 -1
  96. package/src/source.ts +5 -1
  97. package/src/storage/port.ts +74 -1
  98. package/src/wire/emit.ts +5 -1
  99. package/src/wire/errors.ts +5 -1
@@ -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