@afora/core 0.0.8 → 0.0.11

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 (226) hide show
  1. package/README.md +149 -23
  2. package/dist/adapters.d.ts +25 -0
  3. package/dist/adapters.js +32 -0
  4. package/dist/core/application/application.d.ts +30 -0
  5. package/dist/core/application/application.js +1291 -0
  6. package/dist/core/application/exceptions.d.ts +17 -0
  7. package/dist/core/application/exceptions.js +85 -0
  8. package/dist/core/application/migrate.d.ts +19 -0
  9. package/dist/core/application/migrate.js +67 -0
  10. package/dist/core/application/providers.js +108 -0
  11. package/dist/core/application/registry.js +23 -0
  12. package/dist/core/application/schema.d.ts +30 -0
  13. package/dist/core/application/schema.js +398 -0
  14. package/dist/core/application/start.js +162 -0
  15. package/dist/core/application/types/application.interface.d.ts +60 -3
  16. package/dist/core/auth/jwt.d.ts +30 -0
  17. package/dist/core/auth/jwt.js +200 -0
  18. package/dist/core/auth/types/jwt.interface.d.ts +74 -0
  19. package/dist/core/blueprint/blueprint-plugin.js +7 -0
  20. package/dist/core/blueprint/blueprint.js +146 -0
  21. package/dist/core/blueprint/callable.js +13 -0
  22. package/dist/core/blueprint/exceptions.d.ts +5 -0
  23. package/dist/core/blueprint/exceptions.js +20 -0
  24. package/dist/core/blueprint/is-blueprint.js +4 -0
  25. package/dist/core/blueprint/list.js +19 -0
  26. package/dist/core/blueprint/optional.d.ts +3 -1
  27. package/dist/core/blueprint/optional.js +69 -0
  28. package/dist/core/blueprint/record-field.js +14 -0
  29. package/dist/core/blueprint/slice.js +127 -0
  30. package/dist/core/blueprint/types/blueprint.interface.d.ts +95 -5
  31. package/dist/core/blueprint/variant.d.ts +32 -0
  32. package/dist/core/blueprint/variant.js +72 -0
  33. package/dist/core/command/command.js +428 -0
  34. package/dist/core/command/exceptions.js +30 -0
  35. package/dist/core/command/types/command.interface.d.ts +10 -1
  36. package/dist/core/entity/abstract-entity.d.ts +24 -0
  37. package/dist/core/entity/abstract-entity.js +181 -0
  38. package/dist/core/entity/entity.d.ts +1 -1
  39. package/dist/core/entity/entity.js +209 -0
  40. package/dist/core/entity/event.d.ts +39 -0
  41. package/dist/core/entity/event.js +80 -0
  42. package/dist/core/entity/exceptions.d.ts +9 -0
  43. package/dist/core/entity/exceptions.js +27 -0
  44. package/dist/core/entity/trust.d.ts +24 -0
  45. package/dist/core/entity/trust.js +7 -0
  46. package/dist/core/entity/types/entity.interface.d.ts +30 -0
  47. package/dist/core/entity/version.js +13 -0
  48. package/dist/core/environment/environment.d.ts +26 -3
  49. package/dist/core/environment/environment.js +71 -0
  50. package/dist/core/event-policy/event-policy.js +76 -0
  51. package/dist/core/event-policy/exceptions.js +12 -0
  52. package/dist/core/event-policy/publish.js +98 -0
  53. package/dist/core/event-policy/publishers.js +18 -0
  54. package/dist/core/event-policy/types/event-policy.interface.d.ts +8 -2
  55. package/dist/core/exception/enums/exception-layers.js +15 -0
  56. package/dist/core/exception/exception.d.ts +15 -0
  57. package/dist/core/exception/exception.js +128 -0
  58. package/dist/core/exception/exported.js +49 -0
  59. package/dist/core/exception/guard.d.ts +20 -1
  60. package/dist/core/exception/guard.js +16 -0
  61. package/dist/core/exception/types/exception.interface.d.ts +13 -0
  62. package/dist/core/json.js +19 -0
  63. package/dist/core/logger/exceptions.js +7 -0
  64. package/dist/core/logger/logger.d.ts +14 -1
  65. package/dist/core/logger/logger.js +178 -0
  66. package/dist/core/openapi/exceptions.js +7 -0
  67. package/dist/core/openapi/openapi.js +132 -0
  68. package/dist/core/openapi/types/openapi.interface.d.ts +7 -1
  69. package/dist/core/output/access.d.ts +16 -0
  70. package/dist/core/output/access.js +66 -0
  71. package/dist/core/output/coerce.js +38 -0
  72. package/dist/core/output/exceptions.d.ts +16 -0
  73. package/dist/core/output/exceptions.js +22 -0
  74. package/dist/core/output/http.d.ts +36 -0
  75. package/dist/core/output/http.js +351 -0
  76. package/dist/core/output/openapi-sink.d.ts +33 -4
  77. package/dist/core/output/openapi-sink.js +571 -0
  78. package/dist/core/output/output.js +192 -0
  79. package/dist/core/output/problem.js +30 -0
  80. package/dist/core/output/select.js +28 -0
  81. package/dist/core/output/stage.d.ts +7 -2
  82. package/dist/core/output/stage.js +111 -0
  83. package/dist/core/output/status.d.ts +1 -1
  84. package/dist/core/output/status.js +52 -0
  85. package/dist/core/output/types/http.interface.d.ts +134 -0
  86. package/dist/core/output/types/output.interface.d.ts +49 -5
  87. package/dist/core/parse/issue.d.ts +28 -3
  88. package/dist/core/parse/issue.js +31 -0
  89. package/dist/core/parse/parse.d.ts +16 -0
  90. package/dist/core/parse/parse.js +323 -0
  91. package/dist/core/parse/strip.js +48 -0
  92. package/dist/core/property/abstract-property.d.ts +9 -0
  93. package/dist/core/property/abstract-property.js +37 -0
  94. package/dist/core/property/define-property.d.ts +34 -6
  95. package/dist/core/property/define-property.js +209 -0
  96. package/dist/core/property/enums/property-states.js +8 -0
  97. package/dist/core/property/exceptions.js +12 -0
  98. package/dist/core/property/input.js +10 -0
  99. package/dist/core/property/is-property.js +3 -0
  100. package/dist/core/property/lineage.js +8 -0
  101. package/dist/core/property/property.d.ts +27 -0
  102. package/dist/core/property/property.js +46 -0
  103. package/dist/core/property/refine.js +103 -0
  104. package/dist/core/property/types/property-options.interface.d.ts +10 -0
  105. package/dist/core/property/types/property-type.interface.d.ts +4 -0
  106. package/dist/core/record/abstract-record.d.ts +8 -0
  107. package/dist/core/record/abstract-record.js +307 -0
  108. package/dist/core/record/exceptions.js +49 -0
  109. package/dist/core/record/marks.js +7 -0
  110. package/dist/core/record/mask.js +60 -0
  111. package/dist/core/record/name.js +23 -0
  112. package/dist/core/record/plugin-catalog.js +115 -0
  113. package/dist/core/record/plugin.js +198 -0
  114. package/dist/core/record/record.js +117 -0
  115. package/dist/core/record/types/record.interface.d.ts +17 -1
  116. package/dist/core/repository/cursor.js +83 -0
  117. package/dist/core/repository/exceptions.d.ts +13 -0
  118. package/dist/core/repository/exceptions.js +72 -0
  119. package/dist/core/repository/in-memory.d.ts +2 -2
  120. package/dist/core/repository/in-memory.js +196 -0
  121. package/dist/core/repository/migrate.d.ts +20 -0
  122. package/dist/core/repository/migrate.js +254 -0
  123. package/dist/core/repository/plan.js +27 -0
  124. package/dist/core/repository/provider.js +29 -0
  125. package/dist/core/repository/query.js +153 -0
  126. package/dist/core/repository/references.js +196 -0
  127. package/dist/core/repository/repository.d.ts +22 -2
  128. package/dist/core/repository/repository.js +720 -0
  129. package/dist/core/repository/state.d.ts +2 -0
  130. package/dist/core/repository/state.js +138 -0
  131. package/dist/core/repository/types/query.interface.d.ts +13 -0
  132. package/dist/core/repository/types/repository.interface.d.ts +50 -5
  133. package/dist/core/repository/types/schema.interface.d.ts +132 -0
  134. package/dist/core/repository/upcast.d.ts +64 -0
  135. package/dist/core/repository/upcast.js +179 -0
  136. package/dist/core/schema/schema.d.ts +37 -0
  137. package/dist/core/schema/schema.js +542 -0
  138. package/dist/core/standard/standard-schema.js +1 -0
  139. package/dist/core/standard/standard.js +23 -0
  140. package/dist/core/symbols/demo.d.ts +4 -0
  141. package/dist/core/symbols/demo.js +1 -0
  142. package/dist/core/symbols/kind.d.ts +1 -1
  143. package/dist/core/symbols/kind.js +1 -0
  144. package/dist/core/symbols/meta.js +1 -0
  145. package/dist/core/symbols/state.d.ts +5 -0
  146. package/dist/core/symbols/state.js +1 -0
  147. package/dist/core/tracing/exceptions.d.ts +4 -0
  148. package/dist/core/tracing/exceptions.js +7 -0
  149. package/dist/core/tracing/tracing.d.ts +72 -0
  150. package/dist/core/tracing/tracing.js +101 -0
  151. package/dist/core/use-case/access.d.ts +12 -0
  152. package/dist/core/use-case/access.js +56 -0
  153. package/dist/core/use-case/decorators.d.ts +40 -0
  154. package/dist/core/use-case/decorators.js +65 -0
  155. package/dist/core/use-case/exceptions.d.ts +5 -1
  156. package/dist/core/use-case/exceptions.js +48 -0
  157. package/dist/core/use-case/plugin-catalog.js +68 -0
  158. package/dist/core/use-case/plugin.js +133 -0
  159. package/dist/core/use-case/route.d.ts +18 -0
  160. package/dist/core/use-case/route.js +200 -0
  161. package/dist/core/use-case/scope.d.ts +5 -0
  162. package/dist/core/use-case/scope.js +4 -0
  163. package/dist/core/use-case/steps/describe.d.ts +5 -1
  164. package/dist/core/use-case/steps/describe.js +24 -0
  165. package/dist/core/use-case/steps/references.js +105 -0
  166. package/dist/core/use-case/steps/run.js +139 -0
  167. package/dist/core/use-case/steps/types/check.interface.d.ts +233 -0
  168. package/dist/core/use-case/steps/types/steps.interface.d.ts +8 -1
  169. package/dist/core/use-case/steps/validate.js +368 -0
  170. package/dist/core/use-case/target.js +100 -0
  171. package/dist/core/use-case/types/access.interface.d.ts +39 -0
  172. package/dist/core/use-case/types/route.interface.d.ts +86 -0
  173. package/dist/core/use-case/use-case.d.ts +127 -2
  174. package/dist/core/use-case/use-case.js +493 -0
  175. package/dist/experimental.d.ts +18 -1
  176. package/dist/experimental.js +18 -123
  177. package/dist/index.d.ts +49 -51
  178. package/dist/index.js +213 -443
  179. package/dist/std/blueprint-plugin.js +42 -0
  180. package/dist/std/blueprint.d.ts +21 -0
  181. package/dist/std/blueprint.js +3 -0
  182. package/dist/std/command.js +3 -0
  183. package/dist/std/entity.d.ts +20 -1
  184. package/dist/std/entity.js +30 -0
  185. package/dist/std/event-policies.js +3 -0
  186. package/dist/std/properties/contact.d.ts +3 -0
  187. package/dist/std/properties/contact.js +29 -0
  188. package/dist/std/properties/enum.js +26 -0
  189. package/dist/std/properties/exceptions.js +14 -0
  190. package/dist/std/properties/headless.js +45 -0
  191. package/dist/std/properties/identity.js +28 -0
  192. package/dist/std/properties/json.js +161 -0
  193. package/dist/std/properties/password.d.ts +0 -2
  194. package/dist/std/properties/password.js +79 -0
  195. package/dist/std/properties/primitives.d.ts +4 -0
  196. package/dist/std/properties/primitives.js +28 -0
  197. package/dist/std/properties/time.js +55 -0
  198. package/dist/std/record-plugins.d.ts +2 -2
  199. package/dist/std/record-plugins.js +73 -0
  200. package/dist/std/record.d.ts +20 -1
  201. package/dist/std/record.js +3 -0
  202. package/dist/std/resource.d.ts +31 -0
  203. package/dist/std/resource.js +39 -0
  204. package/dist/std/runtime.d.ts +6 -0
  205. package/dist/std/runtime.js +193 -0
  206. package/dist/std/stages.js +4 -0
  207. package/dist/std/use-cases/auth.d.ts +5 -1
  208. package/dist/std/use-cases/auth.js +193 -0
  209. package/dist/std/use-cases/crud.js +261 -0
  210. package/dist/std/use-cases/index.d.ts +1 -1
  211. package/dist/std/use-cases/index.js +12 -0
  212. package/dist/std/use-cases/lifecycle.js +97 -0
  213. package/dist/std/use-cases/shared.d.ts +2 -2
  214. package/dist/std/use-cases/shared.js +232 -0
  215. package/dist/std/use-cases/types.d.ts +102 -2
  216. package/dist/std/use-cases/types.js +0 -0
  217. package/dist/testing/http-provider-contract.d.ts +32 -0
  218. package/dist/testing/http-provider-contract.js +344 -0
  219. package/dist/testing/index.d.ts +2 -0
  220. package/dist/testing/index.js +3 -944
  221. package/dist/testing/memory-publisher.js +12 -0
  222. package/dist/testing/provider-contract.d.ts +26 -1
  223. package/dist/testing/provider-contract.js +1071 -0
  224. package/package.json +23 -3
  225. package/dist/index-qxfkyd6k.js +0 -1721
  226. package/dist/index-t5qwtyj5.js +0 -8194
@@ -1,9 +1,16 @@
1
1
  import type { Static, TSchema } from "typebox";
2
- import type { ParseResult } from "../parse/types/parse.interface.js";
2
+ import type { Issue, ParseResult } from "../parse/types/parse.interface.js";
3
3
  import { State } from "../symbols/state.js";
4
4
  import { PropertyStates } from "./enums/property-states.js";
5
5
  import type { IDefineProperty } from "./types/define-property.interface.js";
6
6
  import type { IPropertyType } from "./types/property-type.interface.js";
7
+ /**
8
+ * Adds to `issues` those of the value a pipeline has just rejected, each
9
+ * under `path`, where the value is. An issue of the value itself has `path`
10
+ * as it is, not a copy.
11
+ * @internal
12
+ */
13
+ export declare function takeRejectionIssues(path: readonly (string | number)[], issues: Issue[]): void;
7
14
  /** How a property handles its value; `Value` is the value of its schema, as in `ISchema`. */
8
15
  export declare abstract class AbstractDefineProperty<SchemaType extends TSchema, Value = Static<SchemaType>> implements IDefineProperty<SchemaType, Value> {
9
16
  [State]: PropertyStates;
@@ -27,9 +34,13 @@ export declare abstract class AbstractDefineProperty<SchemaType extends TSchema,
27
34
  protected afterHandle(value: Value): Value;
28
35
  /** The value, or `MISMATCH` when the schema rejects it. */
29
36
  protected handle(value: Value): Value;
30
- /** `attempt`, with the error of any step as a failure. */
37
+ /** `attempt`, with the error of any step as a rejection. */
31
38
  private attemptWithoutThrowing;
32
- /** Runs the pipeline, updating the state, and tells why it stopped if it did. */
39
+ /**
40
+ * Runs the pipeline, updating the state: the handled value, or `REJECTED`
41
+ * with the reason in `rejection`. A handler that is not declared is not
42
+ * run, and neither is the shape check that protects it.
43
+ */
33
44
  private attempt;
34
45
  /**
35
46
  * Runs a handler: an `Exception` it throws goes up as it is, any other
@@ -38,11 +49,28 @@ export declare abstract class AbstractDefineProperty<SchemaType extends TSchema,
38
49
  private runHandler;
39
50
  /** The `InvalidPropertyValue` of an error that is not an `Exception`, as its cause. */
40
51
  private invalidValue;
41
- /** The failure of an `exception` that a step threw. */
52
+ /** Rejects the value with an `exception` that a step threw. */
42
53
  private raise;
43
54
  /**
44
- * The failure of `value`, which the schema rejects: an issue for each of its
45
- * errors, found once and kept for the details of the exception too.
55
+ * Rejects `value`, which the schema rejects, with its errors, found once
56
+ * and kept for the details of the exception too.
46
57
  */
47
58
  private mismatch;
48
59
  }
60
+ /**
61
+ * Tells that the definitions of `prototype` are as `propertyOf` declares them.
62
+ * @internal
63
+ */
64
+ export declare function declarePipeline(prototype: object): void;
65
+ /**
66
+ * `definition.parse` without its result object: a function giving the handled
67
+ * value, or `REJECTED`, with the issues for `takeRejectionIssues` to take.
68
+ * `undefined` when `definition` has a `parse` of its own, which must be
69
+ * called instead.
70
+ *
71
+ * For a definition declared by `propertyOf`, the function is the pipeline of
72
+ * `attempt` with what never changes read once: which steps there are, the
73
+ * schema, and no state, which nobody can read.
74
+ * @internal
75
+ */
76
+ export declare function parserOf(definition: AbstractDefineProperty<TSchema>): ((value: unknown) => unknown) | undefined;
@@ -0,0 +1,209 @@
1
+ import { Exception } from "../exception/exception.js";
2
+ import { LazyIssue, REJECTED } from "../parse/issue.js";
3
+ import {
4
+ checksOfSchema,
5
+ describeError,
6
+ errorsOfSchema
7
+ } from "../schema/schema.js";
8
+ import { State } from "../symbols/state.js";
9
+ import { PropertyStates } from "./enums/property-states.js";
10
+ import { InvalidPropertyValue, PropertyRequired } from "./exceptions.js";
11
+ const MISMATCH = Symbol("mismatch");
12
+
13
+ class Failure {
14
+ source;
15
+ raised;
16
+ errors;
17
+ cause;
18
+ constructor(source, raised, errors) {
19
+ this.source = source;
20
+ this.raised = raised;
21
+ this.errors = errors;
22
+ this.cause = raised;
23
+ }
24
+ exception() {
25
+ if (this.cause === undefined) {
26
+ const { source, errors } = this;
27
+ this.cause = errors ? new InvalidPropertyValue({
28
+ source,
29
+ details: { errors: errors.map(describeError) }
30
+ }) : new PropertyRequired({ source });
31
+ }
32
+ return this.cause;
33
+ }
34
+ }
35
+ let rejection;
36
+ function reject(failure) {
37
+ rejection = failure;
38
+ return REJECTED;
39
+ }
40
+ function segmentsOf(pointer) {
41
+ return pointer.slice(1).split("/").map((segment) => {
42
+ const key = segment.replaceAll("~1", "/").replaceAll("~0", "~");
43
+ return /^(0|[1-9]\d*)$/.test(key) ? Number(key) : key;
44
+ });
45
+ }
46
+ function issueOf(failure, message, path, code) {
47
+ return new LazyIssue(message, path, code, failure.source, failure);
48
+ }
49
+ export function takeRejectionIssues(path, issues) {
50
+ const failure = rejection;
51
+ rejection = undefined;
52
+ const { raised, errors, source } = failure;
53
+ if (raised) {
54
+ issues.push({
55
+ message: raised.message,
56
+ path,
57
+ code: "invalid_value",
58
+ source,
59
+ cause: raised
60
+ });
61
+ } else if (!errors) {
62
+ issues.push(issueOf(failure, "is required", path, "required"));
63
+ } else if (errors.length === 0) {
64
+ issues.push(issueOf(failure, "is invalid", path, "invalid_value"));
65
+ } else {
66
+ for (const { message, instancePath } of errors) {
67
+ issues.push(issueOf(failure, message, instancePath === "" ? path : [...path, ...segmentsOf(instancePath)], "invalid_value"));
68
+ }
69
+ }
70
+ }
71
+
72
+ export class AbstractDefineProperty {
73
+ [State] = PropertyStates.Declared;
74
+ make(value) {
75
+ const handled = this.attempt(value);
76
+ if (handled !== REJECTED)
77
+ return handled;
78
+ const failure = rejection;
79
+ rejection = undefined;
80
+ throw failure.exception();
81
+ }
82
+ parse(value) {
83
+ const handled = this.attemptWithoutThrowing(value);
84
+ if (handled !== REJECTED)
85
+ return { value: handled };
86
+ const issues = [];
87
+ takeRejectionIssues([], issues);
88
+ return { issues };
89
+ }
90
+ preHandle(value) {
91
+ return value;
92
+ }
93
+ afterHandle(value) {
94
+ return value;
95
+ }
96
+ handle(value) {
97
+ return this.type.schema.match(value) ? value : MISMATCH;
98
+ }
99
+ attemptWithoutThrowing(value) {
100
+ try {
101
+ return this.attempt(value);
102
+ } catch (error) {
103
+ return this.raise(error instanceof Exception ? error : this.invalidValue(error));
104
+ }
105
+ }
106
+ attempt(value) {
107
+ const { name, optional, schema } = this.type;
108
+ this[State] = PropertyStates.Declared;
109
+ if (value === undefined) {
110
+ if (!optional)
111
+ return reject(new Failure(name, undefined, undefined));
112
+ this[State] = PropertyStates.Done;
113
+ return value;
114
+ }
115
+ const preHandles = this.preHandle !== PASS.preHandle;
116
+ const handles = this.handle !== PASS.handle;
117
+ if ((preHandles || handles) && !schema.matchShape(value)) {
118
+ return this.mismatch(value);
119
+ }
120
+ try {
121
+ if (preHandles) {
122
+ this[State] = PropertyStates.PreHandling;
123
+ value = this.runHandler(this.preHandle, value);
124
+ }
125
+ this[State] = PropertyStates.Handling;
126
+ if (handles) {
127
+ const handled = this.handle(value);
128
+ if (handled === MISMATCH)
129
+ return this.mismatch(value);
130
+ value = handled;
131
+ } else if (!schema.match(value)) {
132
+ if (!preHandles && !schema.matchShape(value)) {
133
+ this[State] = PropertyStates.Declared;
134
+ }
135
+ return this.mismatch(value);
136
+ }
137
+ if (this.afterHandle !== PASS.afterHandle) {
138
+ this[State] = PropertyStates.AfterHandling;
139
+ value = this.runHandler(this.afterHandle, value);
140
+ }
141
+ } catch (error) {
142
+ if (error instanceof Exception)
143
+ return this.raise(error);
144
+ throw error;
145
+ }
146
+ this[State] = PropertyStates.Done;
147
+ return value;
148
+ }
149
+ runHandler(handler, value) {
150
+ try {
151
+ return handler.call(this, value);
152
+ } catch (error) {
153
+ if (error instanceof Exception)
154
+ throw error;
155
+ throw this.invalidValue(error);
156
+ }
157
+ }
158
+ invalidValue(error) {
159
+ return new InvalidPropertyValue({
160
+ source: this.type.name,
161
+ details: {
162
+ errors: [error instanceof Error ? error.message : String(error)]
163
+ },
164
+ cause: error
165
+ });
166
+ }
167
+ raise(exception) {
168
+ return reject(new Failure(this.type.name, exception, undefined));
169
+ }
170
+ mismatch(value) {
171
+ const { name, schema } = this.type;
172
+ return reject(new Failure(name, undefined, errorsOfSchema(schema, value)));
173
+ }
174
+ }
175
+ const PASS = AbstractDefineProperty.prototype;
176
+ const declared = new WeakSet;
177
+ export function declarePipeline(prototype) {
178
+ declared.add(prototype);
179
+ }
180
+ export function parserOf(definition) {
181
+ const pipeline = definition;
182
+ if (pipeline.parse !== AbstractDefineProperty.prototype.parse) {
183
+ return;
184
+ }
185
+ if (!declared.has(Object.getPrototypeOf(definition)) || pipeline.handle !== PASS.handle || Object.hasOwn(definition, "preHandle") || Object.hasOwn(definition, "afterHandle")) {
186
+ return (value) => pipeline.attemptWithoutThrowing(value);
187
+ }
188
+ const { name, optional, schema } = pipeline.type;
189
+ const { match, matchShape } = checksOfSchema(schema);
190
+ const preHandle = pipeline.preHandle === PASS.preHandle ? undefined : pipeline.preHandle;
191
+ const afterHandle = pipeline.afterHandle === PASS.afterHandle ? undefined : pipeline.afterHandle;
192
+ return (value) => {
193
+ if (value === undefined) {
194
+ return optional ? value : reject(new Failure(name, undefined, undefined));
195
+ }
196
+ try {
197
+ if (preHandle !== undefined) {
198
+ if (!matchShape(value))
199
+ return pipeline.mismatch(value);
200
+ value = preHandle.call(pipeline, value);
201
+ }
202
+ if (!match(value))
203
+ return pipeline.mismatch(value);
204
+ return afterHandle === undefined ? value : afterHandle.call(pipeline, value);
205
+ } catch (error) {
206
+ return pipeline.raise(error instanceof Exception ? error : pipeline.invalidValue(error));
207
+ }
208
+ };
209
+ }
@@ -0,0 +1,8 @@
1
+ export var PropertyStates;
2
+ ((PropertyStates) => {
3
+ PropertyStates[PropertyStates["Declared"] = 0] = "Declared";
4
+ PropertyStates[PropertyStates["PreHandling"] = 1] = "PreHandling";
5
+ PropertyStates[PropertyStates["Handling"] = 2] = "Handling";
6
+ PropertyStates[PropertyStates["AfterHandling"] = 3] = "AfterHandling";
7
+ PropertyStates[PropertyStates["Done"] = 4] = "Done";
8
+ })(PropertyStates ||= {});
@@ -0,0 +1,12 @@
1
+ import { ExceptionLayers } from "../exception/enums/exception-layers.js";
2
+ import { exceptionOf } from "../exception/exception.js";
3
+ export const PropertyRequired = exceptionOf({
4
+ layer: ExceptionLayers.Property,
5
+ name: "PropertyRequired",
6
+ message: (_, source) => `Property "${source}" is required.`
7
+ });
8
+ export const InvalidPropertyValue = exceptionOf({
9
+ layer: ExceptionLayers.Property,
10
+ name: "InvalidPropertyValue",
11
+ message: ({ errors }, source) => `Invalid value for property "${source}": ${errors.join("; ")}`
12
+ });
@@ -0,0 +1,10 @@
1
+ import { fieldOf } from "../blueprint/callable.js";
2
+ import { isProperty } from "./is-property.js";
3
+ export const PropertyInput = Symbol("propertyInput");
4
+ export function propertyInputOf(field) {
5
+ const property = fieldOf(field);
6
+ if (!isProperty(property))
7
+ return;
8
+ const declared = property[PropertyInput];
9
+ return typeof declared === "object" && declared !== null && isProperty(declared.accepts) && typeof declared.convert === "function" ? declared : undefined;
10
+ }
@@ -0,0 +1,3 @@
1
+ export function isProperty(value) {
2
+ return typeof value === "function" && typeof value.type === "object";
3
+ }
@@ -0,0 +1,8 @@
1
+ const lineages = new WeakMap;
2
+ export function recordPropertyLineage(Property, lineage) {
3
+ if (!lineages.has(Property))
4
+ lineages.set(Property, lineage);
5
+ }
6
+ export function propertyLineageOf(Property) {
7
+ return typeof Property === "function" ? lineages.get(Property) : undefined;
8
+ }
@@ -53,5 +53,32 @@ export interface PropertyClass<SchemaType extends TSchema, Value = Static<Schema
53
53
  with<Self extends AnyPropertyConstructor>(this: Self, options: PropertyOptions<SchemaType, Value>): Self;
54
54
  demo<Self extends AbstractProperty<any>>(this: new (value: never) => Self): Self;
55
55
  }
56
+ /**
57
+ * Declares a property: a class that holds one value, run through
58
+ * `preHandle`, the validation against the TypeBox `schema` and
59
+ * `afterHandle`. `optional`, `sensitive` and `unique` flag it for the
60
+ * blueprints and records that hold it, and `default` is its `demo()` value.
61
+ * Extend the class to add behavior, or narrow it with `.with(options)`. A
62
+ * value its schema rejects makes the constructor throw
63
+ * {@link InvalidPropertyValue}, and `undefined` for a required one
64
+ * {@link PropertyRequired}.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * import { propertyOf } from "@afora/core";
69
+ * import { Type } from "typebox";
70
+ *
71
+ * const Name = propertyOf({
72
+ * name: "name",
73
+ * schema: Type.String({ minLength: 3 }),
74
+ * preHandle: (value) => value.trim(),
75
+ * default: "Jane", // used by Name.demo()
76
+ * });
77
+ *
78
+ * new Name(" Alice ").value; // "Alice"
79
+ * Name.demo().value; // "Jane"
80
+ * // new Name("a") throws InvalidPropertyValue
81
+ * ```
82
+ */
56
83
  export declare function propertyOf<SchemaType extends TSchema, Optional extends boolean = false, const Unique extends boolean = false, const Sensitive extends boolean = false>({ name, schema, optional, sensitive, unique, default: _default, preHandle: onPreHandle, afterHandle: onAfterHandle, }: PropertyOfArgs<SchemaType, Optional, Unique, Sensitive>): PropertyClass<SchemaValueType<SchemaType, Optional>, Static<SchemaType>> & UniqueMark<Unique> & SensitiveMark<Sensitive>;
57
84
  export {};
@@ -0,0 +1,46 @@
1
+ import { Type } from "typebox";
2
+ import { schemaOf } from "../schema/schema.js";
3
+ import { Demo } from "../symbols/demo.js";
4
+ import { AbstractProperty } from "./abstract-property.js";
5
+ import { AbstractDefineProperty, declarePipeline } from "./define-property.js";
6
+ export function propertyOf({
7
+ name,
8
+ schema,
9
+ optional,
10
+ sensitive = false,
11
+ unique = false,
12
+ default: _default,
13
+ preHandle: onPreHandle,
14
+ afterHandle: onAfterHandle
15
+ }) {
16
+ const valueSchema = optional ? Type.Optional(schema) : schema;
17
+ const SchemaConstructor = schemaOf(name, valueSchema);
18
+ const type = {
19
+ [Demo]: _default,
20
+ name,
21
+ schema: new SchemaConstructor,
22
+ optional: optional ?? false,
23
+ sensitive,
24
+ unique
25
+ };
26
+
27
+ class DefineProperty extends AbstractDefineProperty {
28
+ get type() {
29
+ return type;
30
+ }
31
+ }
32
+ const steps = DefineProperty.prototype;
33
+ if (onPreHandle)
34
+ steps.preHandle = (value) => onPreHandle(value);
35
+ if (onAfterHandle)
36
+ steps.afterHandle = (value) => onAfterHandle(value);
37
+ declarePipeline(DefineProperty.prototype);
38
+
39
+ class Property extends AbstractProperty {
40
+ static type = type;
41
+ createDefinition() {
42
+ return new DefineProperty;
43
+ }
44
+ }
45
+ return Property;
46
+ }
@@ -0,0 +1,103 @@
1
+ import { rawTypeOf, schemaOf } from "../schema/schema.js";
2
+ import { Demo } from "../symbols/demo.js";
3
+ import { recordPropertyLineage } from "./lineage.js";
4
+ const METADATA_KEYS = [
5
+ "title",
6
+ "description",
7
+ "examples",
8
+ "deprecated",
9
+ "readOnly",
10
+ "writeOnly"
11
+ ];
12
+ const LOWER_BOUNDS = {
13
+ min: ["minimum", "minLength"],
14
+ exclusiveMin: ["exclusiveMinimum"]
15
+ };
16
+ const UPPER_BOUNDS = {
17
+ max: ["maximum", "maxLength"],
18
+ exclusiveMax: ["exclusiveMaximum"]
19
+ };
20
+ export function derivePropertyOf(Property, type) {
21
+ const Base = Property;
22
+
23
+ class Derived extends Base {
24
+ static type = type;
25
+ createDefinition() {
26
+ const definition = super.createDefinition();
27
+ Object.defineProperty(definition, "type", {
28
+ value: type,
29
+ configurable: true
30
+ });
31
+ return definition;
32
+ }
33
+ }
34
+ Object.defineProperty(Derived, "name", { value: Property.name });
35
+ return Derived;
36
+ }
37
+ function copyOf(schema) {
38
+ return Object.defineProperties({}, Object.getOwnPropertyDescriptors(schema));
39
+ }
40
+ function addAllOf(schema, constraint) {
41
+ schema.allOf = [...schema.allOf ?? [], constraint];
42
+ }
43
+ function refinedSchemaOf(base, options) {
44
+ const schema = copyOf(base);
45
+ const keyword = (keys) => keys.length === 1 || schema.type !== "string" ? keys[0] : keys[1];
46
+ for (const key of METADATA_KEYS) {
47
+ if (options[key] !== undefined)
48
+ schema[key] = options[key];
49
+ }
50
+ for (const [option, keys] of Object.entries(LOWER_BOUNDS)) {
51
+ const value = options[option];
52
+ if (value === undefined)
53
+ continue;
54
+ const name = keyword(keys);
55
+ const current = schema[name];
56
+ schema[name] = current === undefined ? value : Math.max(current, value);
57
+ }
58
+ for (const [option, keys] of Object.entries(UPPER_BOUNDS)) {
59
+ const value = options[option];
60
+ if (value === undefined)
61
+ continue;
62
+ const name = keyword(keys);
63
+ const current = schema[name];
64
+ schema[name] = current === undefined ? value : Math.min(current, value);
65
+ }
66
+ if (options.multipleOf !== undefined) {
67
+ if (schema.multipleOf === undefined)
68
+ schema.multipleOf = options.multipleOf;
69
+ else
70
+ addAllOf(schema, { multipleOf: options.multipleOf });
71
+ }
72
+ if (options.pattern !== undefined) {
73
+ const pattern = options.pattern instanceof RegExp ? options.pattern.source : options.pattern;
74
+ if (schema.pattern === undefined)
75
+ schema.pattern = pattern;
76
+ else
77
+ addAllOf(schema, { pattern });
78
+ }
79
+ return schema;
80
+ }
81
+ export function refinePropertyOf(Property, options) {
82
+ const base = Property.type;
83
+ const settings = options;
84
+ const schema = refinedSchemaOf(rawTypeOf(base.schema), settings);
85
+ const SchemaConstructor = schemaOf(base.name, schema);
86
+ const examples = settings.examples;
87
+ const type = {
88
+ ...base,
89
+ [Demo]: settings.default ?? examples?.[0] ?? base[Demo],
90
+ schema: new SchemaConstructor,
91
+ ...settings.fill !== undefined && { fill: settings.fill },
92
+ ...typeof settings.renamedFrom === "string" && {
93
+ renamedFrom: settings.renamedFrom
94
+ }
95
+ };
96
+ const Refined = derivePropertyOf(Property, type);
97
+ recordPropertyLineage(Refined, {
98
+ kind: "refined",
99
+ base: Property,
100
+ options: Object.freeze({ ...settings })
101
+ });
102
+ return Refined;
103
+ }
@@ -14,6 +14,16 @@ export interface PropertyMetadata<Value> {
14
14
  readonly writeOnly?: boolean;
15
15
  /** The demo value, as `default` in `propertyOf`; it is not written to the schema. */
16
16
  readonly default?: Value;
17
+ /**
18
+ * The value a repository gives the key when a stored row lacks it, on read
19
+ * and in a backfill (`app.migrate`); unlike `default`, it fills real data.
20
+ */
21
+ readonly fill?: Value;
22
+ /**
23
+ * The key that held the value in rows stored before the key was renamed:
24
+ * a repository moves it on read and in a backfill.
25
+ */
26
+ readonly renamedFrom?: string;
17
27
  }
18
28
  /**
19
29
  * Bounds of a number. They only narrow the property: a bound looser than one
@@ -15,6 +15,10 @@ export interface IPropertyType<SchemaType extends TSchema, Value = Static<Schema
15
15
  readonly sensitive?: boolean;
16
16
  /** Whether a record lists a key holding it in `options.unique`, for repositories to enforce. */
17
17
  readonly unique?: boolean;
18
+ /** `fill` of `.with()`: the value given to the key when a stored row lacks it. */
19
+ readonly fill?: Value;
20
+ /** `renamedFrom` of `.with()`: the key that held the value in older rows. */
21
+ readonly renamedFrom?: string;
18
22
  }
19
23
  /**
20
24
  * The type of a property declared `unique`, as `Slug`, so that the keys
@@ -1,4 +1,5 @@
1
1
  import type { BlueprintField, BlueprintInput, BlueprintValue, IBlueprint, IBlueprintCollection } from "../blueprint/types/blueprint.interface.js";
2
+ import { type Complete } from "../parse/parse.js";
2
3
  import type { ParseResult } from "../parse/types/parse.interface.js";
3
4
  import type { StandardSchemaV1 } from "../standard/standard-schema.js";
4
5
  import { Meta } from "../symbols/meta.js";
@@ -15,6 +16,13 @@ interface RecordDeclaration<Properties extends IBlueprintCollection> {
15
16
  export declare const RESERVED_RECORD_KEYS: readonly string[];
16
17
  /** Makes each of `keys` a member of the records of `prototype`, e.g. `user.name`. */
17
18
  export declare function exposeRecordKeys(prototype: object, keys: readonly string[]): void;
19
+ /**
20
+ * Tells the record whose constructor runs next that the values of `keys` are
21
+ * valid as they are. For a class that makes values for its own record on the
22
+ * way to `super()`, as an entity does of its id.
23
+ * @internal
24
+ */
25
+ export declare function vouchFor(keys: readonly string[], complete?: Complete): void;
18
26
  /** How `recordDataOf` stores the records a record holds. */
19
27
  export interface RecordDataOptions {
20
28
  /**