@fougere/core 0.8.3-alpha.0 → 0.8.4-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 (222) hide show
  1. package/dist/boot/Emissions.d.ts.map +1 -1
  2. package/dist/boot/Emissions.js +3 -3
  3. package/dist/boot/Emissions.js.map +1 -1
  4. package/dist/boot/auth.d.ts +1 -1
  5. package/dist/boot/auth.d.ts.map +1 -1
  6. package/dist/boot/bootstrap.d.ts.map +1 -1
  7. package/dist/boot/bootstrap.js +339 -595
  8. package/dist/boot/bootstrap.js.map +1 -1
  9. package/dist/boot/card.js +1 -1
  10. package/dist/boot/card.js.map +1 -1
  11. package/dist/boot/hosted.d.ts +1 -1
  12. package/dist/boot/hosted.d.ts.map +1 -1
  13. package/dist/boot/install.d.ts +40 -0
  14. package/dist/boot/install.d.ts.map +1 -0
  15. package/dist/boot/install.js +298 -0
  16. package/dist/boot/install.js.map +1 -0
  17. package/dist/boot/ownership.d.ts +1 -1
  18. package/dist/boot/ownership.d.ts.map +1 -1
  19. package/dist/boot/ownership.js +14 -1
  20. package/dist/boot/ownership.js.map +1 -1
  21. package/dist/boot/seed.d.ts +7 -1
  22. package/dist/boot/seed.d.ts.map +1 -1
  23. package/dist/boot/seed.js +7 -2
  24. package/dist/boot/seed.js.map +1 -1
  25. package/dist/boot/statement-drift.d.ts +1 -1
  26. package/dist/boot/statement-drift.d.ts.map +1 -1
  27. package/dist/boot/together.d.ts +1 -1
  28. package/dist/boot/together.d.ts.map +1 -1
  29. package/dist/boot/together.js +1 -1
  30. package/dist/boot/together.js.map +1 -1
  31. package/dist/boot/types.d.ts +2 -2
  32. package/dist/boot/types.d.ts.map +1 -1
  33. package/dist/config-loader.d.ts +1 -1
  34. package/dist/config-loader.d.ts.map +1 -1
  35. package/dist/contract.d.ts +2 -2
  36. package/dist/contract.d.ts.map +1 -1
  37. package/dist/contract.js +1 -1
  38. package/dist/contract.js.map +1 -1
  39. package/dist/conventions.d.ts.map +1 -0
  40. package/dist/conventions.js.map +1 -0
  41. package/dist/crypto/encoding.d.ts +0 -1
  42. package/dist/crypto/encoding.d.ts.map +1 -1
  43. package/dist/crypto/encoding.js +0 -7
  44. package/dist/crypto/encoding.js.map +1 -1
  45. package/dist/declare.js +1 -1
  46. package/dist/declare.js.map +1 -1
  47. package/dist/descriptor/index.d.ts +15 -0
  48. package/dist/descriptor/index.d.ts.map +1 -0
  49. package/dist/descriptor/index.js +14 -0
  50. package/dist/descriptor/index.js.map +1 -0
  51. package/dist/descriptor/surface.d.ts +8 -0
  52. package/dist/descriptor/surface.d.ts.map +1 -0
  53. package/dist/descriptor/surface.js +16 -0
  54. package/dist/descriptor/surface.js.map +1 -0
  55. package/dist/dispatch/HandlerFacade.d.ts +2 -0
  56. package/dist/dispatch/HandlerFacade.d.ts.map +1 -1
  57. package/dist/dispatch/HandlerFacade.js +7 -2
  58. package/dist/dispatch/HandlerFacade.js.map +1 -1
  59. package/dist/dispatch/StorageGuard.d.ts.map +1 -1
  60. package/dist/dispatch/StorageGuard.js +9 -23
  61. package/dist/dispatch/StorageGuard.js.map +1 -1
  62. package/dist/dispatch/presenterArguments.d.ts +7 -1
  63. package/dist/dispatch/presenterArguments.d.ts.map +1 -1
  64. package/dist/dispatch/presenterArguments.js +15 -4
  65. package/dist/dispatch/presenterArguments.js.map +1 -1
  66. package/dist/dispatch/validateInput.d.ts.map +1 -1
  67. package/dist/dispatch/validateInput.js +2 -2
  68. package/dist/dispatch/validateInput.js.map +1 -1
  69. package/dist/effective-operation.d.ts +1 -1
  70. package/dist/effective-operation.d.ts.map +1 -1
  71. package/dist/effective-operation.js +2 -12
  72. package/dist/effective-operation.js.map +1 -1
  73. package/dist/index.d.ts +7 -9
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +4 -2
  76. package/dist/index.js.map +1 -1
  77. package/dist/node.d.ts +2 -12
  78. package/dist/node.d.ts.map +1 -1
  79. package/dist/node.js +2 -12
  80. package/dist/node.js.map +1 -1
  81. package/dist/prefab/crud.d.ts +1 -1
  82. package/dist/prefab/crud.d.ts.map +1 -1
  83. package/dist/prefab/mirror.d.ts +10 -11
  84. package/dist/prefab/mirror.d.ts.map +1 -1
  85. package/dist/prefab/mirror.js +1 -27
  86. package/dist/prefab/mirror.js.map +1 -1
  87. package/dist/prefab/repository.d.ts +1 -1
  88. package/dist/prefab/repository.d.ts.map +1 -1
  89. package/dist/{scan/result.d.ts → scan.d.ts} +2 -2
  90. package/dist/scan.d.ts.map +1 -0
  91. package/dist/scan.js +2 -0
  92. package/dist/scan.js.map +1 -0
  93. package/dist/source.d.ts +1 -1
  94. package/dist/source.d.ts.map +1 -1
  95. package/dist/storage/criterion.d.ts.map +1 -0
  96. package/dist/{criterion.js → storage/criterion.js} +2 -2
  97. package/dist/storage/criterion.js.map +1 -0
  98. package/dist/{storage.d.ts → storage/port.d.ts} +6 -3
  99. package/dist/storage/port.d.ts.map +1 -0
  100. package/dist/{storage.js → storage/port.js} +13 -6
  101. package/dist/storage/port.js.map +1 -0
  102. package/dist/{store.d.ts → storage/store.d.ts} +1 -1
  103. package/dist/storage/store.d.ts.map +1 -0
  104. package/dist/{store.js → storage/store.js} +33 -17
  105. package/dist/storage/store.js.map +1 -0
  106. package/dist/verify.js +1 -1
  107. package/dist/verify.js.map +1 -1
  108. package/dist/wire/emit.d.ts.map +1 -0
  109. package/dist/wire/emit.js.map +1 -0
  110. package/dist/wire/errors.js +2 -2
  111. package/dist/wire/errors.js.map +1 -1
  112. package/package.json +10 -4
  113. package/src/boot/Emissions.ts +3 -3
  114. package/src/boot/auth.ts +1 -1
  115. package/src/boot/bootstrap.ts +386 -674
  116. package/src/boot/card.ts +1 -1
  117. package/src/boot/hosted.ts +1 -1
  118. package/src/boot/install.ts +390 -0
  119. package/src/boot/ownership.ts +17 -2
  120. package/src/boot/seed.ts +18 -3
  121. package/src/boot/statement-drift.ts +1 -1
  122. package/src/boot/together.ts +1 -1
  123. package/src/boot/types.ts +2 -2
  124. package/src/config-loader.ts +1 -1
  125. package/src/contract.ts +2 -2
  126. package/src/crypto/encoding.ts +0 -7
  127. package/src/declare.ts +1 -1
  128. package/src/descriptor/index.ts +15 -0
  129. package/src/descriptor/surface.ts +23 -0
  130. package/src/dispatch/HandlerFacade.ts +9 -2
  131. package/src/dispatch/StorageGuard.ts +8 -21
  132. package/src/dispatch/presenterArguments.ts +21 -9
  133. package/src/dispatch/validateInput.ts +2 -2
  134. package/src/effective-operation.ts +3 -14
  135. package/src/index.ts +10 -9
  136. package/src/node.ts +2 -16
  137. package/src/prefab/crud.ts +1 -1
  138. package/src/prefab/mirror.ts +12 -38
  139. package/src/prefab/repository.ts +1 -1
  140. package/src/{scan/result.ts → scan.ts} +1 -1
  141. package/src/source.ts +1 -1
  142. package/src/{criterion.ts → storage/criterion.ts} +2 -2
  143. package/src/{storage.ts → storage/port.ts} +20 -5
  144. package/src/{store.ts → storage/store.ts} +35 -16
  145. package/src/verify.ts +1 -1
  146. package/src/wire/call.ts +1 -1
  147. package/src/wire/errors.ts +2 -2
  148. package/dist/boot/boot.d.ts +0 -45
  149. package/dist/boot/boot.d.ts.map +0 -1
  150. package/dist/boot/boot.js +0 -63
  151. package/dist/boot/boot.js.map +0 -1
  152. package/dist/criterion.d.ts.map +0 -1
  153. package/dist/criterion.js.map +0 -1
  154. package/dist/declarations.d.ts +0 -34
  155. package/dist/declarations.d.ts.map +0 -1
  156. package/dist/declarations.js +0 -75
  157. package/dist/declarations.js.map +0 -1
  158. package/dist/emit.d.ts.map +0 -1
  159. package/dist/emit.js.map +0 -1
  160. package/dist/imports.d.ts +0 -16
  161. package/dist/imports.d.ts.map +0 -1
  162. package/dist/imports.js +0 -78
  163. package/dist/imports.js.map +0 -1
  164. package/dist/placement.d.ts +0 -25
  165. package/dist/placement.d.ts.map +0 -1
  166. package/dist/placement.js +0 -69
  167. package/dist/placement.js.map +0 -1
  168. package/dist/scan/adapters.d.ts +0 -3
  169. package/dist/scan/adapters.d.ts.map +0 -1
  170. package/dist/scan/adapters.js +0 -25
  171. package/dist/scan/adapters.js.map +0 -1
  172. package/dist/scan/bundling.d.ts +0 -3
  173. package/dist/scan/bundling.d.ts.map +0 -1
  174. package/dist/scan/bundling.js +0 -15
  175. package/dist/scan/bundling.js.map +0 -1
  176. package/dist/scan/contract.d.ts +0 -27
  177. package/dist/scan/contract.d.ts.map +0 -1
  178. package/dist/scan/contract.js +0 -46
  179. package/dist/scan/contract.js.map +0 -1
  180. package/dist/scan/conventions.d.ts.map +0 -1
  181. package/dist/scan/conventions.js.map +0 -1
  182. package/dist/scan/emit.d.ts +0 -10
  183. package/dist/scan/emit.d.ts.map +0 -1
  184. package/dist/scan/emit.js +0 -144
  185. package/dist/scan/emit.js.map +0 -1
  186. package/dist/scan/handler-parser.d.ts +0 -26
  187. package/dist/scan/handler-parser.d.ts.map +0 -1
  188. package/dist/scan/handler-parser.js +0 -607
  189. package/dist/scan/handler-parser.js.map +0 -1
  190. package/dist/scan/result.d.ts.map +0 -1
  191. package/dist/scan/result.js +0 -2
  192. package/dist/scan/result.js.map +0 -1
  193. package/dist/scan/scanner.d.ts +0 -12
  194. package/dist/scan/scanner.d.ts.map +0 -1
  195. package/dist/scan/scanner.js +0 -573
  196. package/dist/scan/scanner.js.map +0 -1
  197. package/dist/scan/statement.d.ts +0 -4
  198. package/dist/scan/statement.d.ts.map +0 -1
  199. package/dist/scan/statement.js +0 -135
  200. package/dist/scan/statement.js.map +0 -1
  201. package/dist/storage.d.ts.map +0 -1
  202. package/dist/storage.js.map +0 -1
  203. package/dist/store.d.ts.map +0 -1
  204. package/dist/store.js.map +0 -1
  205. package/src/boot/boot.ts +0 -110
  206. package/src/declarations.ts +0 -110
  207. package/src/imports.ts +0 -94
  208. package/src/placement.ts +0 -86
  209. package/src/scan/adapters.ts +0 -32
  210. package/src/scan/bundling.ts +0 -14
  211. package/src/scan/contract.ts +0 -80
  212. package/src/scan/emit.ts +0 -160
  213. package/src/scan/handler-parser.ts +0 -695
  214. package/src/scan/scanner.ts +0 -698
  215. package/src/scan/statement.ts +0 -159
  216. /package/dist/{scan/conventions.d.ts → conventions.d.ts} +0 -0
  217. /package/dist/{scan/conventions.js → conventions.js} +0 -0
  218. /package/dist/{criterion.d.ts → storage/criterion.d.ts} +0 -0
  219. /package/dist/{emit.d.ts → wire/emit.d.ts} +0 -0
  220. /package/dist/{emit.js → wire/emit.js} +0 -0
  221. /package/src/{scan/conventions.ts → conventions.ts} +0 -0
  222. /package/src/{emit.ts → wire/emit.ts} +0 -0
@@ -1,6 +1,6 @@
1
- import { Boundary, FieldSet, FieldValueValidator, InputRefusal, type Fields } from '@fougere/schema';
2
- import { COMPARISONS, comparisonOf, unknownIn } from '../criterion.js';
3
- import { assertListOptions } from '../storage.js';
1
+ import { FieldSet, FieldValueValidator, InputRefusal, type Fields } from '@fougere/schema';
2
+ import { COMPARISONS, comparisonOf, unknownIn } from '../storage/criterion.js';
3
+ import { assertListOptions } from '../storage/port.js';
4
4
  import { ErrorCode, FougereError } from '../wire/errors.js';
5
5
 
6
6
  /** The gestures this guard grafts onto. */
@@ -70,7 +70,7 @@ export class StorageGuard {
70
70
  if (typeof list === 'function') {
71
71
  guarded.list = async function (...args: unknown[]) {
72
72
  const options = args[0] as { where?: Record<string, unknown> } | undefined;
73
- assertListOptions(options, validation.entity);
73
+ assertListOptions(options, validation.entity, Object.keys(validation.fields));
74
74
  if (options?.where) args[0] = { ...options, where: validation.criteria(options.where) };
75
75
 
76
76
  return list.apply(this, args);
@@ -169,11 +169,7 @@ export class StorageGuard {
169
169
  /** One value against one field — validated, then decoded the way the wire hands it. */
170
170
  private value(field: Fields[string], asked: unknown): { value: unknown } | { error: string } {
171
171
  if (asked === null || asked === undefined) return { value: asked };
172
- const checked = FieldValueValidator.of(field).validate(asked);
173
- if ('error' in checked) return checked;
174
- if (checked.value === null) return { value: null };
175
-
176
- return Boundary.of(field).decode(checked.value);
172
+ return FieldValueValidator.of(field).parse(asked);
177
173
  }
178
174
 
179
175
  private validated<T>(value: T, operation: string, index?: number): T {
@@ -195,18 +191,9 @@ export class StorageGuard {
195
191
  parsed[key] = item;
196
192
  continue;
197
193
  }
198
- const checked = FieldValueValidator.of(field).validate(item);
199
- if ('error' in checked) {
200
- errors.push(`${where}${key}: ${checked.error}`);
201
- continue;
202
- }
203
- if (checked.value === null) {
204
- parsed[key] = null;
205
- continue;
206
- }
207
- const decoded = Boundary.of(field).decode(checked.value);
208
- if ('error' in decoded) errors.push(`${where}${key}: ${decoded.error}`);
209
- else parsed[key] = decoded.value;
194
+ const value = FieldValueValidator.of(field).parse(item);
195
+ if ('error' in value) errors.push(`${where}${key}: ${value.error}`);
196
+ else parsed[key] = value.value;
210
197
  }
211
198
 
212
199
  if (errors.length > 0) {
@@ -1,24 +1,36 @@
1
- import { computeBindingPlan } from '../wire/binding.js';
1
+ import { computeBindingPlan, type BindingPlan } from '../wire/binding.js';
2
2
  import type { InvocationContext } from '../wire/Invocation.js';
3
3
  import type { PresenterEntry } from '../descriptor/frond.js';
4
4
  import type { ArgumentResolver } from './ArgumentResolver.js';
5
5
  import type { PresenterArgs } from './PresenterExecutor.js';
6
6
 
7
+ /**
8
+ * Where each computed field's extra arguments come from — read off the declaration, so a
9
+ * field that takes only the page is absent and asks for nothing.
10
+ */
11
+ export function presenterPlans(
12
+ meta: PresenterEntry,
13
+ collectorTypes: Set<string>,
14
+ ): Map<string, BindingPlan> {
15
+ const plans = new Map<string, BindingPlan>();
16
+ for (const field of meta.fieldMeta) {
17
+ if (!field.params?.length) continue;
18
+ plans.set(field.name, computeBindingPlan(field.params, collectorTypes));
19
+ }
20
+
21
+ return plans;
22
+ }
23
+
7
24
  /** The invocation-dependent arguments of every computed presenter field. */
8
25
  export async function presenterArguments(
9
- meta: PresenterEntry,
26
+ plans: Map<string, BindingPlan>,
10
27
  invocation: InvocationContext,
11
28
  resolver: ArgumentResolver,
12
- collectorTypes: Set<string>,
13
29
  ): Promise<PresenterArgs> {
14
30
  const argumentsByField: PresenterArgs = {};
15
31
 
16
- for (const field of meta.fieldMeta) {
17
- if (!field.params?.length) continue;
18
- argumentsByField[field.name] = await resolver.resolve(
19
- computeBindingPlan(field.params, collectorTypes),
20
- invocation,
21
- );
32
+ for (const [field, plan] of plans) {
33
+ argumentsByField[field] = await resolver.resolve(plan, invocation);
22
34
  }
23
35
 
24
36
  return argumentsByField;
@@ -1,4 +1,4 @@
1
- import { InputValidator, type SchemaView } from '@fougere/schema';
1
+ import { InputValidator, dotted, type SchemaView } from '@fougere/schema';
2
2
  import type { InvocationContext } from '../wire/Invocation.js';
3
3
  import { ErrorCode, FougereError } from '../wire/errors.js';
4
4
 
@@ -17,7 +17,7 @@ export function validateInput(
17
17
  if (!result.success) {
18
18
  throw new FougereError({
19
19
  code: ErrorCode.VALIDATION_FAILED,
20
- message: result.errors.map((error) => `${error.path}: ${error.message}`).join(', '),
20
+ message: result.errors.map((error) => `${dotted(error.path)}: ${error.message}`).join(', '),
21
21
  details: result.errors,
22
22
  entity,
23
23
  operation,
@@ -4,7 +4,8 @@ import { statementDrift } from './boot/statement-drift.js';
4
4
  import { computeBindingPlan, type BindingPlan } from './wire/binding.js';
5
5
  import { targetOf } from './prefab/prefab.js';
6
6
  import type { CollectorEntry, FrondDescriptor, HandlerEntry } from './descriptor/frond.js';
7
- import type { ScanDiagnostic } from './scan/result.js';
7
+ import { servedSurfaces } from './descriptor/surface.js';
8
+ import type { ScanDiagnostic } from './scan.js';
8
9
  import { verify } from './verify.js';
9
10
  import {
10
11
  inferOperationKind,
@@ -279,7 +280,7 @@ export function resolveEffectiveOperations(
279
280
  ...(remote ? { remote } : {}),
280
281
  },
281
282
  exposure: {
282
- surfaces: surfacesOf(frond, handler),
283
+ surfaces: servedSurfaces(frond, handler).map((surface) => surface ?? 'default'),
283
284
  adapters: exposedAdapters(handler, options.adapters),
284
285
  },
285
286
  outputClosed: output.closed,
@@ -557,18 +558,6 @@ function effectiveOutput(
557
558
  return { ...(entity ? { schema: entity.entityClass } : {}), closed: false };
558
559
  }
559
560
 
560
- function surfacesOf(frond: FrondDescriptor, handler: HandlerEntry): string[] {
561
- if (handler.surface) return [handler.surface];
562
- const surfaces = ['default'];
563
- for (const [surface, addresses] of Object.entries(frond.surfaces ?? {})) {
564
- const dedicated = frond.handlers.some((candidate) =>
565
- candidate.address === handler.address && candidate.surface === surface);
566
- if (!dedicated && addresses.some((address) =>
567
- address.toLowerCase() === handler.address.toLowerCase())) surfaces.push(surface);
568
- }
569
- return [surfaces[0]!, ...surfaces.slice(1).sort()];
570
- }
571
-
572
561
  function exposedAdapters(
573
562
  handler: HandlerEntry,
574
563
  adapters: Record<string, boolean | undefined> | undefined,
package/src/index.ts CHANGED
@@ -73,7 +73,7 @@ export type {
73
73
  FrondCall, Transport, IdentityCard, CardOp, Facade, RpcAnswer,
74
74
  TopologyReport, FrondPlacement, Edge,
75
75
  } from './wire/call.js';
76
- export { type Emit, type Fact } from './emit.js';
76
+ export { type Emit, type Fact } from './wire/emit.js';
77
77
  export { callValueOf } from './contract.js';
78
78
  export type { CallValue } from './contract.js';
79
79
  export { toHttpError, toPublicError } from './wire/http-error.js';
@@ -83,14 +83,18 @@ export type { LogLevel, LogRecord, LogSink } from './builtin/logger.js';
83
83
  // What a re-read config changes in a running process — and what it cannot.
84
84
  export { applyConfig, type ConfigApplication } from './boot/apply.js';
85
85
  export { Config } from './builtin/config.js';
86
- export type { Storage, StorageFactory, ListOptions, ListResult, Together } from './storage.js';
87
- export { togetherKeyOf, membersOfTogetherKey } from './storage.js';
86
+ export type { Storage, StorageFactory, ListOptions, ListResult, Together } from './storage/port.js';
87
+ export { togetherKeyOf, membersOfTogetherKey } from './storage/port.js';
88
88
  export type { Constraint, Source, SourceConfig, SourceView } from './source.js';
89
89
  export { Sources } from './source.js';
90
- export { storageOver } from './store.js';
91
- export type { Store, Values } from './store.js';
90
+ export { storageOver } from './storage/store.js';
91
+ export type { Store, Values } from './storage/store.js';
92
92
  export type { App, CreateAppOptions } from './boot/types.js';
93
- export type { ScanResult, ScanDiagnostic } from './scan/result.js';
93
+ export type { ScanResult, ScanDiagnostic } from './scan.js';
94
+ export {
95
+ type Conventions, type ConventionsInput, DEFAULT_CONVENTIONS,
96
+ resolveConventions, frondPackage, frondDirsOf, providerDirsOf,
97
+ } from './conventions.js';
94
98
  export type {
95
99
  FrondDescriptor,
96
100
  FrondSource,
@@ -107,9 +111,6 @@ export type { AuthConfig, AuthContext, AuthRuntime } from './boot/auth.js';
107
111
  export { Fronds } from './descriptor/Fronds.js';
108
112
  export { verify, assertSplittable, type Violation } from './verify.js';
109
113
  // Same question as verify(), answered from the source text instead of the model.
110
- export type { CrossFrondImport } from './imports.js';
111
- export type { HandlerDeclaration } from './declarations.js';
112
- export type { OutsideConvention } from './placement.js';
113
114
  // Who is calling, established rather than accepted — the proof beside `state`'s claim.
114
115
  // `generateKeyPair` and `issueGrant` are NOT here: they make keys at a deployment and
115
116
  // need `node:crypto` for a gesture WebCrypto has no equal of. They sit on `/node`.
package/src/node.ts CHANGED
@@ -1,21 +1,7 @@
1
- /** What Fougere does with a filesystem the half of core that a Worker cannot run. */
2
- export { boot } from './boot/boot.js';
3
-
4
- export { scanProject, frondAliases, watchPathsOf } from './scan/scanner.js';
5
- export {
6
- type Conventions, type ConventionsInput, DEFAULT_CONVENTIONS,
7
- resolveConventions, frondPackage, frondDirsOf, providerDirsOf,
8
- } from './scan/conventions.js';
9
- export { RUNTIME_PACKAGES } from './scan/bundling.js';
10
- export { emitScan, type EmitOptions } from './scan/emit.js';
11
- export { emitStatement } from './scan/statement.js';
1
+ /** What Fougere does with a filesystem, minus the scan that is `@fougere/compiler`. */
12
2
  export { setModuleLoader, getModuleLoader } from './loader.js';
13
3
  export { loadConfig, loadCascadedConfig } from './config-loader.js';
14
- export { defineFrond } from './frond-config.js';
15
- export { crossFrondImports } from './imports.js';
16
- export { handlerDeclarations } from './declarations.js';
17
- export { outsideConventions } from './placement.js';
18
- export { adaptersOf } from './scan/adapters.js';
4
+ export { defineFrond, loadFrondConfig } from './frond-config.js';
19
5
 
20
6
  // Making a key and binding a name to it happen once, at a deployment, on a machine with
21
7
  // a filesystem — the CLI speaking. Verifying happens per call, everywhere, and stays on
@@ -1,5 +1,5 @@
1
1
  import { lowerFirst, type EntityConstructor, type SchemaView } from '@fougere/schema';
2
- import type { Storage, ListOptions, ListResult } from '../storage.js';
2
+ import type { Storage, ListOptions, ListResult } from '../storage/port.js';
3
3
  import type { OperationContract } from '../wire/operation.js';
4
4
  import { targetOf } from './prefab.js';
5
5
 
@@ -1,26 +1,27 @@
1
- import { Lifecycle, type EntityConstructor, type Fields } from '@fougere/schema';
2
- import type { Storage } from '../storage.js';
1
+ import type { EntityConstructor } from '@fougere/schema';
2
+ import type { Storage } from '../storage/port.js';
3
3
 
4
- /** A paginated local copy of a source that cannot be queried directly. */
5
4
  /** What one refresh did — enough to log it, and to decide whether to run again. */
6
5
  export interface Refreshed {
7
6
  /** Instances written, counting a replaced one once. */
8
7
  written: number;
9
- /** The age the pull was asked to start from — absent on the first ever run. */
8
+ /** The age the pull was asked to start from — absent when it asked for everything. */
10
9
  since?: Date;
11
10
  /** How long the whole pass took, pull included. */
12
11
  ms: number;
13
12
  }
14
13
 
14
+ /** A paginated local copy of a source that cannot be queried directly. */
15
15
  export interface MirrorOf<T> {
16
- /** The copy's own storage — where a page lands, and where its age is read. */
16
+ /** The copy's own storage — where a page lands. */
17
17
  storage: Storage<T>;
18
18
  /** Pages of rows to write. The one thing a mirror's author supplies. */
19
19
  pull(since?: Date): AsyncIterable<Partial<T>[]>;
20
- /** Run one pass: read the high-water mark, pull from there, write each page. */
21
- refresh(): Promise<Refreshed>;
22
- /** When the freshest row here was written `undefined` while the copy is empty. */
23
- freshness(): Promise<Date | undefined>;
20
+ /**
21
+ * Pull from `since` and write every page. The mark is the CALLER's: only it knows
22
+ * whether a pass completed, and a pass that throws must not advance it.
23
+ */
24
+ refresh(since?: Date): Promise<Refreshed>;
24
25
  }
25
26
 
26
27
  export interface MirrorConstructor<T> {
@@ -31,16 +32,6 @@ export interface MirrorConstructor<T> {
31
32
  export function Mirror<E extends EntityConstructor>(shape: E): MirrorConstructor<InstanceType<E>> {
32
33
  type T = InstanceType<E>;
33
34
 
34
- // Refuse an undated copy before it can be used as if it held live rows.
35
- const declared = ageFieldOf(shape);
36
- if (declared === undefined) {
37
- throw new Error(
38
- `Mirror(${(shape as { name?: string }).name ?? '?'}): the shape carries no \`updated()\` field — ` +
39
- `a copy has to be able to say when it was pulled, and \`refresh\` reads its high-water mark from it.`,
40
- );
41
- }
42
- const age: string = declared;
43
-
44
35
  abstract class MirrorBase implements MirrorOf<T> {
45
36
  static readonly __entity = shape;
46
37
 
@@ -48,35 +39,18 @@ export function Mirror<E extends EntityConstructor>(shape: E): MirrorConstructor
48
39
 
49
40
  abstract pull(since?: Date): AsyncIterable<Partial<T>[]>;
50
41
 
51
- /** The freshest persisted stamp; no process-local freshness state is kept. */
52
- async freshness(): Promise<Date | undefined> {
53
- const [newest] = await this.storage.list({ orderBy: age, order: 'desc', limit: 1 });
54
- const value = (newest as Record<string, unknown> | undefined)?.[age];
55
- return value instanceof Date ? value : undefined;
56
- }
57
-
58
- async refresh(): Promise<Refreshed> {
42
+ async refresh(since?: Date): Promise<Refreshed> {
59
43
  const started = Date.now();
60
- const since = await this.freshness();
61
44
  let written = 0;
62
45
  // Preserve the source's page boundaries: one page becomes one upsert.
63
46
  for await (const page of this.pull(since)) {
64
47
  if (page.length === 0) continue;
65
48
  written += await this.storage.upsertAll(page);
66
49
  }
50
+
67
51
  return { written, since, ms: Date.now() - started };
68
52
  }
69
53
  }
70
54
 
71
55
  return MirrorBase as unknown as MirrorConstructor<T>;
72
56
  }
73
-
74
- /** The field whose lifecycle stamps every update. */
75
- export function ageFieldOf(shape: unknown): string | undefined {
76
- const fields = (shape as { getFields?: () => Fields }).getFields?.();
77
- if (!fields) return undefined;
78
- for (const [name, field] of Object.entries(fields)) {
79
- if (Lifecycle.of(field).stampedOnUpdate) return name;
80
- }
81
- return undefined;
82
- }
@@ -1,5 +1,5 @@
1
1
  import { upperFirst, type EntityConstructor } from '@fougere/schema';
2
- import type { Storage, ListOptions, ListResult, SelectOption } from '../storage.js';
2
+ import type { Storage, ListOptions, ListResult, SelectOption } from '../storage/port.js';
3
3
  import type { SchemaView } from '@fougere/schema';
4
4
 
5
5
  /** Repository(…entities) — who owns an entity's storage, and where its questions are named. */
@@ -1,4 +1,4 @@
1
- import type { Fronds } from '../descriptor/Fronds.js';
1
+ import type { Fronds } from './descriptor/Fronds.js';
2
2
 
3
3
  /** Result of scanning a project directory. */
4
4
  /** Something the scan could NOT do — recorded instead of swallowed. */
package/src/source.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Registry, Role, type SchemaView } from '@fougere/schema';
2
- import type { StorageFactory } from './storage.js';
2
+ import type { StorageFactory } from './storage/port.js';
3
3
 
4
4
  /** A promise the judge at the door cannot keep, because it is about rows it never sees. */
5
5
  export type Constraint = 'unique';
@@ -35,8 +35,8 @@ export type ComparisonName = (typeof COMPARISONS)[number];
35
35
  */
36
36
  export function comparisonOf(field: Field | undefined, asked: unknown): Comparison | undefined {
37
37
  if (asked === null || typeof asked !== 'object' || Array.isArray(asked)) return undefined;
38
- // `Shapes.of` answers with `null` already taken out `optional(json())` is an object.
39
- if (!field || Shapes.of(field.shape).base?.type === 'object') return undefined;
38
+ // The type is read off the base, so `optional(json())` still answers `object`.
39
+ if (!field || Shapes.typeOf(field.shape) === 'object') return undefined;
40
40
 
41
41
  return asked as Comparison;
42
42
  }
@@ -45,15 +45,30 @@ const LIST_OPTION_KEYS = [
45
45
  'limit', 'offset', 'page', 'after', 'orderBy', 'order', 'count', 'where', 'select',
46
46
  ] as const;
47
47
 
48
- /** Refuse an option the port does not answer to, naming it and what was expected. */
49
- export function assertListOptions(options: object | undefined, entity: string): void {
48
+ /**
49
+ * Refuse an option the port does not answer to, and an order by a field the entity does not
50
+ * declare — an unhonoured `orderBy` returns the page in whatever order the engine chose.
51
+ */
52
+ export function assertListOptions(
53
+ options: object | undefined,
54
+ entity: string,
55
+ declared: readonly string[],
56
+ ): void {
50
57
  if (!options) return;
51
58
  const legal = new Set<string>(LIST_OPTION_KEYS);
52
59
  const strangers = Object.keys(options).filter((key) => !legal.has(key));
53
- if (strangers.length === 0) return;
60
+ if (strangers.length > 0) {
61
+ throw new Error(
62
+ `${entity}.list(): unknown option ${strangers.map((s) => `\`${s}\``).join(', ')}. ` +
63
+ `Known options are ${LIST_OPTION_KEYS.join(', ')} — to filter, pass \`where: { ${strangers[0]}: … }\`.`,
64
+ );
65
+ }
66
+
67
+ const { orderBy } = options as ListOptions;
68
+ if (orderBy === undefined || declared.includes(orderBy)) return;
69
+
54
70
  throw new Error(
55
- `${entity}.list(): unknown option ${strangers.map((s) => `\`${s}\``).join(', ')}. ` +
56
- `Known options are ${LIST_OPTION_KEYS.join(', ')} — to filter, pass \`where: { ${strangers[0]}: … }\`.`,
71
+ `${entity}.list(): unknown orderBy \`${orderBy}\`. ${entity} declares ${declared.join(', ')}.`,
57
72
  );
58
73
  }
59
74
 
@@ -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 './storage.js';
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
- // Same contract as SQL: the key and the creation stamps survive an overwrite.
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 this.upsert(input);
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/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 '../emit.js';
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';
@@ -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 = 'FougereError';
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
- && typeof (entry as ValidationError).path === 'string'
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;
@@ -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
@@ -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
@@ -1 +0,0 @@
1
- {"version":3,"file":"boot.js","sourceRoot":"","sources":["../../src/boot/boot.ts"],"names":[],"mappings":"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"}
@@ -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"}