@afora/core 0.0.9 → 0.0.12

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 (186) hide show
  1. package/README.md +62 -189
  2. package/dist/adapters.js +31 -55
  3. package/dist/core/application/application.d.ts +30 -0
  4. package/dist/core/application/application.js +1291 -0
  5. package/dist/core/application/exceptions.js +85 -0
  6. package/dist/core/application/migrate.js +67 -0
  7. package/dist/core/application/providers.js +108 -0
  8. package/dist/core/application/registry.js +23 -0
  9. package/dist/core/application/schema.js +398 -0
  10. package/dist/core/application/start.js +162 -0
  11. package/dist/core/application/types/application.interface.d.ts +23 -3
  12. package/dist/core/auth/jwt.js +200 -0
  13. package/dist/core/auth/types/jwt.interface.d.ts +10 -2
  14. package/dist/core/blueprint/blueprint-plugin.js +7 -0
  15. package/dist/core/blueprint/blueprint.js +146 -0
  16. package/dist/core/blueprint/callable.js +13 -0
  17. package/dist/core/blueprint/exceptions.js +20 -0
  18. package/dist/core/blueprint/is-blueprint.js +4 -0
  19. package/dist/core/blueprint/list.js +19 -0
  20. package/dist/core/blueprint/optional.js +69 -0
  21. package/dist/core/blueprint/record-field.js +14 -0
  22. package/dist/core/blueprint/slice.js +127 -0
  23. package/dist/core/blueprint/types/blueprint.interface.d.ts +16 -0
  24. package/dist/core/blueprint/variant.js +72 -0
  25. package/dist/core/command/command.js +428 -0
  26. package/dist/core/command/exceptions.js +30 -0
  27. package/dist/core/command/types/command.interface.d.ts +10 -1
  28. package/dist/core/entity/abstract-entity.d.ts +19 -0
  29. package/dist/core/entity/abstract-entity.js +181 -0
  30. package/dist/core/entity/entity.js +209 -0
  31. package/dist/core/entity/event.d.ts +39 -0
  32. package/dist/core/entity/event.js +80 -0
  33. package/dist/core/entity/exceptions.js +27 -0
  34. package/dist/core/entity/trust.js +7 -0
  35. package/dist/core/entity/version.js +13 -0
  36. package/dist/core/environment/environment.d.ts +26 -3
  37. package/dist/core/environment/environment.js +71 -0
  38. package/dist/core/event-policy/event-policy.js +76 -0
  39. package/dist/core/event-policy/exceptions.js +12 -0
  40. package/dist/core/event-policy/publish.js +98 -0
  41. package/dist/core/event-policy/publishers.js +18 -0
  42. package/dist/core/event-policy/types/event-policy.interface.d.ts +8 -2
  43. package/dist/core/exception/enums/exception-layers.js +15 -0
  44. package/dist/core/exception/exception.d.ts +15 -0
  45. package/dist/core/exception/exception.js +128 -0
  46. package/dist/core/exception/exported.js +49 -0
  47. package/dist/core/exception/guard.d.ts +20 -1
  48. package/dist/core/exception/guard.js +16 -0
  49. package/dist/core/exception/types/exception.interface.d.ts +13 -0
  50. package/dist/core/json.js +19 -0
  51. package/dist/core/logger/exceptions.js +7 -0
  52. package/dist/core/logger/logger.d.ts +14 -1
  53. package/dist/core/logger/logger.js +178 -0
  54. package/dist/core/openapi/exceptions.js +7 -0
  55. package/dist/core/openapi/openapi.js +132 -0
  56. package/dist/core/openapi/types/openapi.interface.d.ts +7 -1
  57. package/dist/core/output/access.js +66 -0
  58. package/dist/core/output/coerce.js +38 -0
  59. package/dist/core/output/exceptions.js +22 -0
  60. package/dist/{index-y280ew0k.js → core/output/http.js} +35 -80
  61. package/dist/core/output/openapi-sink.d.ts +10 -2
  62. package/dist/{index-hg1z2s2v.js → core/output/openapi-sink.js} +60 -544
  63. package/dist/core/output/output.js +192 -0
  64. package/dist/core/output/problem.js +30 -0
  65. package/dist/core/output/select.js +28 -0
  66. package/dist/core/output/stage.js +111 -0
  67. package/dist/core/output/status.js +52 -0
  68. package/dist/core/output/types/http.interface.d.ts +5 -1
  69. package/dist/core/output/types/output.interface.d.ts +24 -0
  70. package/dist/core/parse/issue.js +31 -0
  71. package/dist/core/parse/parse.d.ts +8 -1
  72. package/dist/core/parse/parse.js +323 -0
  73. package/dist/core/parse/strip.js +48 -0
  74. package/dist/core/property/abstract-property.js +37 -0
  75. package/dist/core/property/define-property.js +209 -0
  76. package/dist/core/property/enums/property-states.js +8 -0
  77. package/dist/core/property/exceptions.js +12 -0
  78. package/dist/core/property/input.js +10 -0
  79. package/dist/core/property/is-property.js +3 -0
  80. package/dist/core/property/lineage.js +8 -0
  81. package/dist/core/property/property.d.ts +27 -0
  82. package/dist/core/property/property.js +46 -0
  83. package/dist/core/property/refine.js +103 -0
  84. package/dist/core/record/abstract-record.d.ts +2 -1
  85. package/dist/core/record/abstract-record.js +307 -0
  86. package/dist/core/record/exceptions.js +49 -0
  87. package/dist/core/record/marks.js +7 -0
  88. package/dist/core/record/mask.js +60 -0
  89. package/dist/core/record/name.js +23 -0
  90. package/dist/core/record/plugin-catalog.js +115 -0
  91. package/dist/core/record/plugin.js +198 -0
  92. package/dist/core/record/record.js +117 -0
  93. package/dist/core/record/types/record.interface.d.ts +5 -0
  94. package/dist/core/repository/cursor.js +83 -0
  95. package/dist/core/repository/exceptions.js +72 -0
  96. package/dist/core/repository/in-memory.js +196 -0
  97. package/dist/core/repository/migrate.js +254 -0
  98. package/dist/core/repository/plan.js +27 -0
  99. package/dist/core/repository/provider.js +29 -0
  100. package/dist/core/repository/query.js +153 -0
  101. package/dist/core/repository/references.js +196 -0
  102. package/dist/core/repository/repository.d.ts +22 -2
  103. package/dist/core/repository/repository.js +720 -0
  104. package/dist/core/repository/state.js +138 -0
  105. package/dist/core/repository/types/query.interface.d.ts +13 -0
  106. package/dist/core/repository/types/repository.interface.d.ts +20 -8
  107. package/dist/core/repository/types/schema.interface.d.ts +8 -2
  108. package/dist/core/repository/upcast.js +179 -0
  109. package/dist/core/schema/schema.d.ts +9 -0
  110. package/dist/core/schema/schema.js +542 -0
  111. package/dist/core/standard/standard-schema.js +1 -0
  112. package/dist/core/standard/standard.js +23 -0
  113. package/dist/core/symbols/demo.d.ts +4 -0
  114. package/dist/core/symbols/demo.js +1 -0
  115. package/dist/core/symbols/kind.js +1 -0
  116. package/dist/core/symbols/meta.js +1 -0
  117. package/dist/core/symbols/state.d.ts +5 -0
  118. package/dist/core/symbols/state.js +1 -0
  119. package/dist/core/tracing/exceptions.d.ts +4 -0
  120. package/dist/core/tracing/exceptions.js +7 -0
  121. package/dist/core/tracing/tracing.d.ts +72 -0
  122. package/dist/core/tracing/tracing.js +101 -0
  123. package/dist/core/use-case/access.js +56 -0
  124. package/dist/core/use-case/decorators.js +65 -0
  125. package/dist/core/use-case/exceptions.d.ts +5 -1
  126. package/dist/core/use-case/exceptions.js +48 -0
  127. package/dist/core/use-case/plugin-catalog.js +68 -0
  128. package/dist/core/use-case/plugin.js +133 -0
  129. package/dist/core/use-case/route.js +200 -0
  130. package/dist/core/use-case/scope.d.ts +5 -0
  131. package/dist/core/use-case/scope.js +4 -0
  132. package/dist/core/use-case/steps/describe.d.ts +5 -1
  133. package/dist/core/use-case/steps/describe.js +24 -0
  134. package/dist/core/use-case/steps/references.js +105 -0
  135. package/dist/core/use-case/steps/run.js +139 -0
  136. package/dist/core/use-case/steps/types/check.interface.d.ts +27 -8
  137. package/dist/core/use-case/steps/types/steps.interface.d.ts +8 -1
  138. package/dist/core/use-case/steps/validate.js +368 -0
  139. package/dist/core/use-case/target.js +100 -0
  140. package/dist/core/use-case/types/route.interface.d.ts +25 -5
  141. package/dist/core/use-case/use-case.d.ts +77 -2
  142. package/dist/core/use-case/use-case.js +493 -0
  143. package/dist/experimental.d.ts +5 -0
  144. package/dist/experimental.js +18 -161
  145. package/dist/index.d.ts +7 -5
  146. package/dist/index.js +213 -367
  147. package/dist/std/blueprint-plugin.js +42 -0
  148. package/dist/std/blueprint.d.ts +21 -0
  149. package/dist/std/blueprint.js +3 -0
  150. package/dist/std/command.js +3 -0
  151. package/dist/std/entity.d.ts +20 -1
  152. package/dist/std/entity.js +30 -0
  153. package/dist/std/event-policies.js +3 -0
  154. package/dist/std/properties/contact.d.ts +3 -0
  155. package/dist/std/properties/contact.js +29 -0
  156. package/dist/std/properties/enum.js +26 -0
  157. package/dist/std/properties/exceptions.js +14 -0
  158. package/dist/std/properties/headless.js +45 -0
  159. package/dist/std/properties/identity.js +28 -0
  160. package/dist/std/properties/json.js +161 -0
  161. package/dist/std/properties/password.js +79 -0
  162. package/dist/std/properties/primitives.d.ts +4 -0
  163. package/dist/std/properties/primitives.js +28 -0
  164. package/dist/std/properties/time.js +55 -0
  165. package/dist/std/record-plugins.js +73 -0
  166. package/dist/std/record.d.ts +20 -1
  167. package/dist/std/record.js +3 -0
  168. package/dist/std/resource.js +39 -0
  169. package/dist/std/runtime.js +193 -0
  170. package/dist/std/stages.js +4 -0
  171. package/dist/std/use-cases/auth.js +193 -0
  172. package/dist/std/use-cases/crud.js +261 -0
  173. package/dist/std/use-cases/index.js +12 -0
  174. package/dist/std/use-cases/lifecycle.js +97 -0
  175. package/dist/std/use-cases/shared.js +232 -0
  176. package/dist/std/use-cases/types.d.ts +5 -1
  177. package/dist/std/use-cases/types.js +0 -0
  178. package/dist/testing/http-provider-contract.js +344 -0
  179. package/dist/testing/index.js +3 -1435
  180. package/dist/testing/memory-publisher.js +12 -0
  181. package/dist/testing/provider-contract.d.ts +12 -3
  182. package/dist/testing/provider-contract.js +1071 -0
  183. package/package.json +17 -5
  184. package/dist/index-3aae5jfq.js +0 -2997
  185. package/dist/index-ny3as79r.js +0 -4567
  186. package/dist/index-xegv6a1p.js +0 -4291
@@ -1,509 +1,27 @@
1
+ import { isBlueprint } from "../blueprint/is-blueprint.js";
2
+ import { isBlueprintList } from "../blueprint/list.js";
3
+ import { recordFieldOf } from "../blueprint/record-field.js";
4
+ import { isBlueprintVariant } from "../blueprint/variant.js";
5
+ import { ExceptionLayers } from "../exception/enums/exception-layers.js";
6
+ import { Exception } from "../exception/exception.js";
7
+ import { toOpenAPI } from "../openapi/openapi.js";
8
+ import { isProperty } from "../property/is-property.js";
9
+ import { recordNameOf } from "../record/name.js";
1
10
  import {
2
- isProperty,
3
- isBlueprint,
4
- recordFieldOf,
5
- Exception2,
6
- isBlueprintVariant,
7
- recordNameOf2,
8
- isBlueprintList,
9
- toOpenAPI2,
10
11
  HEADER_NAME,
11
- isRoutePath,
12
- parametersOfPath,
12
+ isRoutePath as isPath,
13
+ isScalarKey as isScalarInputKey,
13
14
  isScalarSchema,
14
- isScalarKey,
15
- InvalidOutputStage2,
16
- sinkOf2
17
- } from "./index-xegv6a1p.js";
18
-
19
- // src/core/application/schema.ts
20
- var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
21
- function sorted(value) {
22
- if (Array.isArray(value))
23
- return value.map(sorted);
24
- if (!isObject(value))
25
- return value;
26
- return Object.fromEntries(Object.keys(value).filter((key) => !key.startsWith("~") && value[key] !== undefined).sort().map((key) => [key, sorted(value[key])]));
27
- }
28
- function evolutionOf(property, description, found = {}, depth = 0) {
29
- if (property === undefined || depth > 64)
30
- return found;
31
- const resolved = "ref" in property ? description.properties[property.ref] : property;
32
- const lineage = resolved?.lineage;
33
- if (lineage === undefined || lineage.kind === "factory")
34
- return found;
35
- if (lineage.kind === "refined") {
36
- const { fill, renamedFrom } = lineage.options;
37
- if (!("fill" in found) && fill !== undefined)
38
- found.fill = fill;
39
- if (found.renamedFrom === undefined && typeof renamedFrom === "string") {
40
- found.renamedFrom = renamedFrom;
41
- }
42
- }
43
- return evolutionOf(lineage.base, description, found, depth + 1);
44
- }
45
- function fieldsOf(fields, description) {
46
- if (fields === undefined)
47
- return;
48
- return Object.fromEntries(Object.keys(fields).sort().map((key) => [
49
- key,
50
- lockFieldOf(fields[key], description)
51
- ]));
52
- }
53
- function lockFieldOf(field, description) {
54
- switch (field.kind) {
55
- case "property": {
56
- const property = "ref" in field ? description.properties[field.ref] : field;
57
- const evolution = evolutionOf("ref" in field ? { ref: field.ref } : field, description);
58
- return {
59
- schema: sorted(property?.schema ?? {}),
60
- optional: field.optional,
61
- ...property?.unique ? { unique: true } : {},
62
- ..."fill" in evolution ? { fill: sorted(evolution.fill) } : {},
63
- ...evolution.renamedFrom === undefined ? {} : { renamedFrom: evolution.renamedFrom }
64
- };
65
- }
66
- case "list": {
67
- const item = lockFieldOf(field.item, description);
68
- return {
69
- schema: sorted({
70
- type: "array",
71
- items: item.schema,
72
- minItems: field.minItems,
73
- maxItems: field.maxItems
74
- }),
75
- optional: field.optional,
76
- ...item.fields === undefined ? {} : { fields: item.fields }
77
- };
78
- }
79
- case "blueprint": {
80
- const fields = "ref" in field ? description.blueprints[field.ref]?.fields : field.fields;
81
- return {
82
- schema: { type: "object" },
83
- optional: field.optional,
84
- fields: fieldsOf(fields, description) ?? {}
85
- };
86
- }
87
- case "record": {
88
- const fields = description.records[field.ref]?.fields;
89
- return {
90
- schema: { type: "object" },
91
- optional: field.optional,
92
- fields: fieldsOf(fields, description) ?? {}
93
- };
94
- }
95
- case "variant":
96
- return {
97
- schema: { discriminator: field.key, type: "object" },
98
- optional: field.optional,
99
- fields: Object.fromEntries(Object.keys(field.variants).sort().map((tag) => [
100
- tag,
101
- {
102
- ...lockFieldOf(field.variants[tag], description),
103
- optional: true
104
- }
105
- ]))
106
- };
107
- case "entity":
108
- return {
109
- schema: { entity: field.ref, type: "string" },
110
- optional: field.optional
111
- };
112
- }
113
- }
114
- function lockEntityOf(entity, description) {
115
- const declared = fieldsOf(entity.fields, description) ?? {};
116
- const unique = new Set(entity.options.unique.filter((key) => key !== "id"));
117
- for (const [key, field] of Object.entries(declared)) {
118
- if (field.unique)
119
- unique.add(key);
120
- }
121
- const fields = Object.fromEntries(Object.entries(declared).map(([key, field]) => [
122
- key,
123
- unique.has(key) ? { ...field, unique: true } : field
124
- ]));
125
- return {
126
- schemaVersion: entity.schemaVersion ?? 1,
127
- previousNames: [...entity.previousNames ?? []].sort(),
128
- unique: [...unique].sort(),
129
- fields,
130
- ...entity.upgrade === undefined || entity.upgrade.length === 0 ? {} : { upgrade: [...entity.upgrade].sort((a, b) => a - b) }
131
- };
132
- }
133
- function schemaLockOf2(description) {
134
- return {
135
- lockVersion: 1,
136
- entities: sorted(Object.fromEntries(Object.keys(description.entities).map((name) => [
137
- name,
138
- lockEntityOf(description.entities[name], description)
139
- ])))
140
- };
141
- }
142
- var METADATA = new Set([
143
- "title",
144
- "description",
145
- "examples",
146
- "default",
147
- "deprecated",
148
- "readOnly",
149
- "writeOnly",
150
- "$comment"
151
- ]);
152
- var UPPER = new Set([
153
- "maximum",
154
- "exclusiveMaximum",
155
- "maxLength",
156
- "maxItems",
157
- "maxProperties"
158
- ]);
159
- var LOWER = new Set([
160
- "minimum",
161
- "exclusiveMinimum",
162
- "minLength",
163
- "minItems",
164
- "minProperties"
165
- ]);
166
- var NARROWING = new Set([
167
- "pattern",
168
- "format",
169
- "multipleOf",
170
- "allOf",
171
- "const"
172
- ]);
173
- var same = (a, b) => JSON.stringify(sorted(a)) === JSON.stringify(sorted(b));
174
- function literalsOf(schema) {
175
- if (Array.isArray(schema.enum)) {
176
- return schema.enum.map((value) => JSON.stringify(value));
177
- }
178
- if (Array.isArray(schema.anyOf) && schema.anyOf.every((item) => isObject(item) && ("const" in item))) {
179
- return schema.anyOf.map((item) => JSON.stringify(item.const));
180
- }
181
- return;
182
- }
183
- function compareSchemas(previous, next) {
184
- if (same(previous, next))
185
- return "same";
186
- const strip = (schema) => Object.fromEntries(Object.entries(schema).filter(([key]) => !METADATA.has(key)));
187
- const [a, b] = [strip(previous), strip(next)];
188
- if (same(a, b))
189
- return "metadata";
190
- if (!same(a.type, b.type) || !same(a.entity, b.entity))
191
- return "type-changed";
192
- const [before, after] = [literalsOf(a), literalsOf(b)];
193
- let loosened = false;
194
- let tightened = false;
195
- if (before !== undefined || after !== undefined) {
196
- if (before === undefined || after === undefined)
197
- return "type-changed";
198
- const kept = before.every((value) => after.includes(value));
199
- const gained = after.some((value) => !before.includes(value));
200
- if (!kept)
201
- tightened = true;
202
- if (gained)
203
- loosened = true;
204
- }
205
- const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
206
- for (const key of keys) {
207
- if (["type", "entity", "enum", "anyOf"].includes(key))
208
- continue;
209
- if (same(a[key], b[key]))
210
- continue;
211
- const [x, y] = [a[key], b[key]];
212
- if (key === "items") {
213
- const items = compareSchemas(isObject(x) ? x : {}, isObject(y) ? y : {});
214
- if (items === "type-changed")
215
- return "type-changed";
216
- if (items === "tightened")
217
- tightened = true;
218
- if (items === "loosened")
219
- loosened = true;
220
- } else if (UPPER.has(key) || LOWER.has(key)) {
221
- if (x === undefined)
222
- tightened = true;
223
- else if (y === undefined)
224
- loosened = true;
225
- else if (typeof x !== "number" || typeof y !== "number")
226
- return "type-changed";
227
- else if (UPPER.has(key) ? y > x : y < x)
228
- loosened = true;
229
- else
230
- tightened = true;
231
- } else if (NARROWING.has(key)) {
232
- if (y === undefined)
233
- loosened = true;
234
- else
235
- tightened = true;
236
- } else {
237
- return "type-changed";
238
- }
239
- }
240
- if (tightened)
241
- return "tightened";
242
- return loosened ? "loosened" : "metadata";
243
- }
244
- function push(context, change, klass, satisfied, extra = {}) {
245
- context.changes.push({
246
- entity: context.entity,
247
- ...extra.key === undefined ? {} : { key: extra.key },
248
- change,
249
- class: klass,
250
- satisfied,
251
- destructive: extra.destructive ?? false,
252
- ...extra.from === undefined ? {} : { from: extra.from },
253
- ...extra.detail === undefined ? {} : { detail: extra.detail }
254
- });
255
- }
256
- var STEP = "an upgrade step (bump schemaVersion and add upgrade[n])";
257
- function diffFields(context, previous, next, path) {
258
- const join = (key) => path ? `${path}.${key}` : key;
259
- const renamedFrom = new Map;
260
- for (const [key, field] of Object.entries(next)) {
261
- const from = field.renamedFrom;
262
- if (from !== undefined && !(key in previous) && from in previous && !(from in next)) {
263
- renamedFrom.set(key, from);
264
- }
265
- }
266
- const moved = new Set(renamedFrom.values());
267
- const keys = [...new Set([...Object.keys(previous), ...Object.keys(next)])].filter((key) => !moved.has(key)).sort();
268
- for (const key of keys) {
269
- const was = previous[key];
270
- const is = next[key];
271
- if (is === undefined) {
272
- push(context, "removed", "automatic", true, {
273
- key: join(key),
274
- destructive: true,
275
- detail: "Left out on read; a backfill removes it only with destructive: true. Rename it with renamedFrom to keep the data."
276
- });
277
- continue;
278
- }
279
- const from = renamedFrom.get(key);
280
- if (from !== undefined) {
281
- push(context, "renamed", "declared", true, {
282
- key: join(key),
283
- from: join(from)
284
- });
285
- diffField(context, previous[from], is, join(key));
286
- continue;
287
- }
288
- if (was === undefined) {
289
- if (is.optional) {
290
- push(context, "added-optional", "automatic", true, { key: join(key) });
291
- } else {
292
- const satisfied = "fill" in is || context.stepped;
293
- push(context, "added-required", "declared", satisfied, {
294
- key: join(key),
295
- ...satisfied ? {} : {
296
- detail: `Needs a fill (.with({ fill })) or ${STEP} that sets it.`
297
- }
298
- });
299
- }
300
- continue;
301
- }
302
- diffField(context, was, is, join(key));
303
- }
304
- }
305
- function diffField(context, was, is, key) {
306
- const compared = compareSchemas(was.schema, is.schema);
307
- if (compared === "type-changed") {
308
- push(context, "type-changed", "declared", context.stepped, {
309
- key,
310
- ...context.stepped ? {} : { detail: `Needs ${STEP} that converts the stored values.` }
311
- });
312
- } else if (compared === "tightened") {
313
- const satisfied = context.stepped || "fill" in is;
314
- push(context, "tightened", "declared", satisfied, {
315
- key,
316
- detail: satisfied ? "Run app.migrate({ mode: 'check' }) to list the rows that violate it." : `Needs ${STEP} or a fill; app.migrate({ mode: 'check' }) lists the rows that violate it.`
317
- });
318
- } else if (compared === "loosened") {
319
- push(context, "loosened", "automatic", true, { key });
320
- } else if (compared === "metadata") {
321
- push(context, "metadata", "automatic", true, { key });
322
- }
323
- if (was.optional && !is.optional) {
324
- const satisfied = context.stepped || "fill" in is;
325
- push(context, "made-required", "declared", satisfied, {
326
- key,
327
- ...satisfied ? {} : {
328
- detail: `Needs a fill (.with({ fill })) or ${STEP} for the rows without it.`
329
- }
330
- });
331
- } else if (!was.optional && is.optional) {
332
- push(context, "made-optional", "automatic", true, { key });
333
- }
334
- if (!was.unique && is.unique) {
335
- push(context, "unique-added", "check", true, {
336
- key,
337
- detail: "Run app.migrate({ mode: 'check' }) and look for duplicates before it is enforced."
338
- });
339
- } else if (was.unique && !is.unique) {
340
- push(context, "unique-removed", "automatic", true, { key });
341
- }
342
- if (was.fields !== undefined || is.fields !== undefined) {
343
- diffFields(context, was.fields ?? {}, is.fields ?? {}, key);
344
- }
345
- }
346
- function diffEntity(entity, from, to, changes) {
347
- const stepped = to.schemaVersion > from.schemaVersion && (to.upgrade ?? []).some((version) => version > from.schemaVersion && version <= to.schemaVersion);
348
- const context = { entity, from, to, stepped, changes };
349
- diffFields(context, from.fields, to.fields, "");
350
- }
351
- function diffSchemas2(lock, current) {
352
- const changes = [];
353
- const claimed = new Set;
354
- for (const name of Object.keys(current.entities).sort()) {
355
- const to = current.entities[name];
356
- let from = lock.entities[name];
357
- if (from === undefined) {
358
- const previous = to.previousNames.find((old) => lock.entities[old] !== undefined && !current.entities[old]);
359
- if (previous === undefined) {
360
- changes.push({
361
- entity: name,
362
- change: "entity-added",
363
- class: "automatic",
364
- satisfied: true,
365
- destructive: false
366
- });
367
- continue;
368
- }
369
- claimed.add(previous);
370
- from = lock.entities[previous];
371
- changes.push({
372
- entity: name,
373
- change: "entity-renamed",
374
- class: "declared",
375
- satisfied: true,
376
- destructive: true,
377
- from: previous,
378
- detail: "app.migrate moves its rows; it removes them from the previous name only with destructive: true."
379
- });
380
- }
381
- diffEntity(name, from, to, changes);
382
- }
383
- for (const name of Object.keys(lock.entities).sort()) {
384
- if (current.entities[name] !== undefined || claimed.has(name))
385
- continue;
386
- changes.push({
387
- entity: name,
388
- change: "entity-removed",
389
- class: "declared",
390
- satisfied: false,
391
- destructive: true,
392
- detail: `No entity is named "${name}": list it in the previousNames of the entity that replaces it, or remove it from the lock if it is gone.`
393
- });
394
- }
395
- return changes;
396
- }
397
- function schemaLockProblemsOf2(lock, current) {
398
- const problems = [];
399
- const renamed = new Map;
400
- for (const [name, entity] of Object.entries(current.entities)) {
401
- for (const old of entity.previousNames) {
402
- if (!renamed.has(old))
403
- renamed.set(old, name);
404
- }
405
- }
406
- for (const name of Object.keys(lock.entities).sort()) {
407
- const locked = lock.entities[name];
408
- const now = current.entities[name] === undefined ? renamed.get(name) : name;
409
- const entity = now === undefined ? undefined : current.entities[now];
410
- if (entity === undefined) {
411
- problems.push(`The lock holds the entity "${name}", which no entity is named or lists in previousNames.`);
412
- } else if (entity.schemaVersion < locked.schemaVersion) {
413
- problems.push(`The schemaVersion of "${now}" (${entity.schemaVersion}) is lower than the lock's (${locked.schemaVersion}).`);
414
- }
415
- }
416
- return problems;
417
- }
418
-
419
- // src/core/output/status.ts
420
- var INVALID_INPUT = new Set([
421
- "InvalidUseCaseInput",
422
- "InvalidUseCaseContext",
423
- "InvalidCommandContext"
424
- ]);
425
- var CONFIGURATION = new Set(["InvalidCommandEnvironment"]);
426
- var NOT_FOUND = new Set([
427
- "RepositoryEntityNotFound",
428
- "UnknownCommandOperation",
429
- "UseCaseEntityNotFound"
430
- ]);
431
- var CONFLICT = new Set([
432
- "RepositoryUniqueViolation",
433
- "RepositoryConcurrencyConflict",
434
- "UseCaseEntityConflict"
435
- ]);
436
- function raisedOf(error) {
437
- let raised = error;
438
- for (let current = error.cause;current instanceof Exception2; current = current.cause) {
439
- if (current.name === error.name)
440
- raised = current;
441
- }
442
- return raised;
443
- }
444
- function statusOf2(error, operation, statuses) {
445
- if (!(error instanceof Exception2))
446
- return 500;
447
- const { name } = error;
448
- if (statuses && Object.hasOwn(statuses, name))
449
- return statuses[name];
450
- if (INVALID_INPUT.has(name))
451
- return 400;
452
- if (CONFIGURATION.has(name))
453
- return 500;
454
- if (Array.isArray(raisedOf(error).details?.issues)) {
455
- return 400;
456
- }
457
- if (NOT_FOUND.has(name))
458
- return 404;
459
- if (CONFLICT.has(name))
460
- return 409;
461
- if (name === "UseCaseInvalidCredentials" || name === "Unauthenticated") {
462
- return 401;
463
- }
464
- if (name === "Forbidden")
465
- return 403;
466
- if (operation?.errors.some((Declared) => error.is(Declared) || Declared.name === name)) {
467
- return 422;
468
- }
469
- return 500;
470
- }
471
-
472
- // src/core/output/problem.ts
473
- var PROBLEM_MEDIA_TYPE2 = "application/problem+json";
474
- var INTERNAL = "Internal error.";
475
- function problemOf2(error, options) {
476
- const { status, debug = false } = options;
477
- const exception = error instanceof Exception2 ? error : undefined;
478
- const title = exception?.name ?? "UnexpectedError";
479
- const message = exception?.message ?? (error instanceof Error ? error.message : String(error));
480
- const raised = exception && raisedOf(exception);
481
- const rawIssues = raised?.details?.issues;
482
- const issues = status === 400 && Array.isArray(rawIssues) ? rawIssues.map((issue) => ({
483
- path: [...issue.path],
484
- code: issue.code,
485
- message: issue.message
486
- })) : undefined;
487
- return {
488
- type: `urn:afora:exception:${title}`,
489
- title,
490
- status,
491
- detail: status >= 500 && !debug ? INTERNAL : message,
492
- ...raised ? { layer: raised.layer } : {},
493
- ...issues ? { issues } : {},
494
- ...debug ? { trace: exception ? exception.toString() : String(error) } : {}
495
- };
496
- }
497
- function outputValueOf2(value) {
498
- const text = JSON.stringify(value);
499
- return text === undefined ? undefined : JSON.parse(text);
500
- }
501
-
502
- // src/core/output/openapi-sink.ts
503
- var METHODS = ["get", "post", "put", "patch", "delete"];
504
- var SUCCESS_STATUSES = [200, 201, 202, 204];
505
- var REQUEST_ID_HEADER = "x-request-id";
506
- function isObject2(value) {
15
+ parametersOfPath
16
+ } from "../use-case/route.js";
17
+ import { InvalidOutputStage } from "./exceptions.js";
18
+ import { PROBLEM_MEDIA_TYPE } from "./problem.js";
19
+ import { sinkOf } from "./stage.js";
20
+ import { statusOf } from "./status.js";
21
+ const METHODS = ["get", "post", "put", "patch", "delete"];
22
+ const SUCCESS_STATUSES = [200, 201, 202, 204];
23
+ const REQUEST_ID_HEADER = "x-request-id";
24
+ function isObject(value) {
507
25
  return typeof value === "object" && value !== null && !Array.isArray(value);
508
26
  }
509
27
  function onlyKeys(value, allowed, where) {
@@ -513,7 +31,7 @@ function onlyKeys(value, allowed, where) {
513
31
  }
514
32
  return;
515
33
  }
516
- var COMPONENT_NAME = /^[A-Za-z0-9._-]+$/;
34
+ const COMPONENT_NAME = /^[A-Za-z0-9._-]+$/;
517
35
  function isHeaderValue(value) {
518
36
  if (typeof value !== "string")
519
37
  return false;
@@ -527,7 +45,7 @@ function isHeaderValue(value) {
527
45
  function isScopes(value) {
528
46
  return value === undefined || Array.isArray(value) && value.every((scope) => typeof scope === "string" && scope !== "");
529
47
  }
530
- var SCHEME_KEYS = {
48
+ const SCHEME_KEYS = {
531
49
  http: ["scheme", "bearerFormat"],
532
50
  apiKey: ["name", "in"],
533
51
  oauth2: ["flows"],
@@ -535,7 +53,7 @@ var SCHEME_KEYS = {
535
53
  mutualTLS: []
536
54
  };
537
55
  function schemeIssue(scheme, where) {
538
- if (!isObject2(scheme) || typeof scheme.type !== "string") {
56
+ if (!isObject(scheme) || typeof scheme.type !== "string") {
539
57
  return `Expected ${where} to be a security scheme with a "type".`;
540
58
  }
541
59
  const keys = Object.hasOwn(SCHEME_KEYS, scheme.type) ? SCHEME_KEYS[scheme.type] : undefined;
@@ -566,7 +84,7 @@ function schemeIssue(scheme, where) {
566
84
  }
567
85
  return;
568
86
  case "oauth2":
569
- return isObject2(scheme.flows) ? undefined : `Expected ${where}.flows to be an object.`;
87
+ return isObject(scheme.flows) ? undefined : `Expected ${where}.flows to be an object.`;
570
88
  case "openIdConnect":
571
89
  return typeof scheme.openIdConnectUrl === "string" && scheme.openIdConnectUrl ? undefined : `Expected ${where}.openIdConnectUrl to be a URL.`;
572
90
  default:
@@ -574,7 +92,7 @@ function schemeIssue(scheme, where) {
574
92
  }
575
93
  }
576
94
  function requirementIssue(requirement, schemes, where) {
577
- if (!isObject2(requirement) || onlyKeys(requirement, ["scheme", "scopes"], where) || typeof requirement.scheme !== "string" || !isScopes(requirement.scopes)) {
95
+ if (!isObject(requirement) || onlyKeys(requirement, ["scheme", "scopes"], where) || typeof requirement.scheme !== "string" || !isScopes(requirement.scopes)) {
578
96
  return `Expected ${where} to be { scheme, scopes? }.`;
579
97
  }
580
98
  if (!Object.hasOwn(schemes, requirement.scheme)) {
@@ -583,13 +101,13 @@ function requirementIssue(requirement, schemes, where) {
583
101
  return;
584
102
  }
585
103
  function securityIssue(security, where) {
586
- if (!isObject2(security))
104
+ if (!isObject(security))
587
105
  return `Expected ${where} to be an object.`;
588
106
  const bad = onlyKeys(security, ["schemes", "operations", "default"], where);
589
107
  if (bad)
590
108
  return bad;
591
109
  const { schemes, operations } = security;
592
- if (!isObject2(schemes))
110
+ if (!isObject(schemes))
593
111
  return `Expected ${where}.schemes to be an object.`;
594
112
  for (const [name, scheme] of Object.entries(schemes)) {
595
113
  if (!COMPONENT_NAME.test(name)) {
@@ -600,7 +118,7 @@ function securityIssue(security, where) {
600
118
  return schemeBad;
601
119
  }
602
120
  if (operations !== undefined) {
603
- if (!isObject2(operations)) {
121
+ if (!isObject(operations)) {
604
122
  return `Expected ${where}.operations to be an object.`;
605
123
  }
606
124
  for (const [id, requirement] of Object.entries(operations)) {
@@ -616,30 +134,30 @@ function securityIssue(security, where) {
616
134
  }
617
135
  return;
618
136
  }
619
- var ROUTE_OPTION_KEYS2 = [
137
+ export const ROUTE_OPTION_KEYS = [
620
138
  "basePath",
621
139
  "route",
622
140
  "responses",
623
141
  "requestId",
624
142
  "security"
625
143
  ];
626
- function routeOptionsIssue2(options, where) {
144
+ export function routeOptionsIssue(options, where) {
627
145
  const { basePath, route, responses, requestId, security } = options;
628
- if (basePath !== undefined && (typeof basePath !== "string" || basePath !== "" && !isRoutePath(basePath, false))) {
146
+ if (basePath !== undefined && (typeof basePath !== "string" || basePath !== "" && !isPath(basePath, false))) {
629
147
  return `Expected ${where}.basePath to be "" or a path such as "/api".`;
630
148
  }
631
149
  if (route !== undefined) {
632
- if (!isObject2(route))
150
+ if (!isObject(route))
633
151
  return `Expected ${where}.route to be an object.`;
634
152
  for (const [id, entry] of Object.entries(route)) {
635
- if (!isObject2(entry) || onlyKeys(entry, ["method", "path", "status"], "route")) {
153
+ if (!isObject(entry) || onlyKeys(entry, ["method", "path", "status"], "route")) {
636
154
  return `Expected ${where}.route["${id}"] to be { method?, path?, status? }.`;
637
155
  }
638
156
  if (entry.method !== undefined && !METHODS.includes(entry.method)) {
639
157
  return `Expected ${where}.route["${id}"].method to be one of ${METHODS.join(", ")}.`;
640
158
  }
641
159
  if (entry.path !== undefined) {
642
- if (!isRoutePath(entry.path)) {
160
+ if (!isPath(entry.path)) {
643
161
  return `Expected ${where}.route["${id}"].path to start with "/", with parameters only as whole "{name}" segments and no query.`;
644
162
  }
645
163
  const names = parametersOfPath(entry.path);
@@ -653,12 +171,12 @@ function routeOptionsIssue2(options, where) {
653
171
  }
654
172
  }
655
173
  if (responses !== undefined) {
656
- if (!isObject2(responses)) {
174
+ if (!isObject(responses)) {
657
175
  return `Expected ${where}.responses to be an object.`;
658
176
  }
659
177
  for (const [id, entry] of Object.entries(responses)) {
660
178
  const at = `${where}.responses["${id}"]`;
661
- if (!isObject2(entry) || onlyKeys(entry, ["headers"], at) || entry.headers !== undefined && !isObject2(entry.headers)) {
179
+ if (!isObject(entry) || onlyKeys(entry, ["headers"], at) || entry.headers !== undefined && !isObject(entry.headers)) {
662
180
  return `Expected ${at} to be { headers?: { name: value } }.`;
663
181
  }
664
182
  for (const [name, value] of Object.entries(entry.headers ?? {})) {
@@ -682,15 +200,15 @@ function routeOptionsIssue2(options, where) {
682
200
  }
683
201
  return;
684
202
  }
685
- function requestIdHeaderOf2(options) {
203
+ export function requestIdHeaderOf(options) {
686
204
  return options.requestId === true ? REQUEST_ID_HEADER : options.requestId ?? undefined;
687
205
  }
688
206
  function validate(options) {
689
- const bad = onlyKeys(options, ["info", "servers", ...ROUTE_OPTION_KEYS2], "openapi");
207
+ const bad = onlyKeys(options, ["info", "servers", ...ROUTE_OPTION_KEYS], "openapi");
690
208
  if (bad)
691
209
  return bad;
692
210
  const { info, servers } = options;
693
- if (!isObject2(info))
211
+ if (!isObject(info))
694
212
  return "Expected openapi.info to be an object.";
695
213
  const infoBad = onlyKeys(info, ["title", "version", "description"], "info");
696
214
  if (infoBad)
@@ -707,23 +225,23 @@ function validate(options) {
707
225
  if (!Array.isArray(servers))
708
226
  return "Expected openapi.servers to be a list.";
709
227
  for (const server of servers) {
710
- if (!isObject2(server) || typeof server.url !== "string" || !server.url || server.description !== undefined && typeof server.description !== "string" || onlyKeys(server, ["url", "description"], "server")) {
228
+ if (!isObject(server) || typeof server.url !== "string" || !server.url || server.description !== undefined && typeof server.description !== "string" || onlyKeys(server, ["url", "description"], "server")) {
711
229
  return "Expected each openapi.servers entry to be { url, description? }.";
712
230
  }
713
231
  }
714
232
  }
715
- return routeOptionsIssue2(options, "openapi");
233
+ return routeOptionsIssue(options, "openapi");
716
234
  }
717
235
  function invalid(reason, source = "openapi") {
718
- throw new InvalidOutputStage2({ source, details: { reason } });
236
+ throw new InvalidOutputStage({ source, details: { reason } });
719
237
  }
720
238
  function kebab(text) {
721
239
  return text.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
722
240
  }
723
- function isScalarKey2(operation, name) {
724
- return isScalarKey(operation.input, name);
241
+ function isScalarKey(operation, name) {
242
+ return isScalarInputKey(operation.input, name);
725
243
  }
726
- function operationRoutes2(operations, options, source = "openapi") {
244
+ export function operationRoutes(operations, options, source = "openapi") {
727
245
  const base = options.basePath ?? "";
728
246
  const route = options.route ?? {};
729
247
  const responses = options.responses ?? {};
@@ -751,7 +269,7 @@ function operationRoutes2(operations, options, source = "openapi") {
751
269
  const requestHeaders = declared?.headers ?? {};
752
270
  const cookies = declared?.cookie ?? {};
753
271
  for (const name of parameters) {
754
- if (!isScalarKey2(operation, name)) {
272
+ if (!isScalarKey(operation, name)) {
755
273
  invalid(`${source}.route["${operation.id}"].path has the parameter "{${name}}", which is not a scalar key of the input of ${operation.id}.`, source);
756
274
  }
757
275
  if (query.includes(name) || Object.hasOwn(requestHeaders, name) || Object.hasOwn(cookies, name)) {
@@ -833,11 +351,11 @@ function problemSchema() {
833
351
  required: ["type", "title", "status", "detail"]
834
352
  };
835
353
  }
836
- var PROBLEM_REF = "#/components/schemas/Problem";
837
- var problemContent = {
838
- [PROBLEM_MEDIA_TYPE2]: { schema: { $ref: PROBLEM_REF } }
354
+ const PROBLEM_REF = "#/components/schemas/Problem";
355
+ const problemContent = {
356
+ [PROBLEM_MEDIA_TYPE]: { schema: { $ref: PROBLEM_REF } }
839
357
  };
840
- var STATUS_TEXT = {
358
+ const STATUS_TEXT = {
841
359
  400: "Invalid input or context.",
842
360
  401: "Authentication is required.",
843
361
  403: "The caller may not do this.",
@@ -846,7 +364,7 @@ var STATUS_TEXT = {
846
364
  422: "Declared error of the operation.",
847
365
  500: "Internal error."
848
366
  };
849
- var SUCCESS_TEXT = {
367
+ const SUCCESS_TEXT = {
850
368
  200: "Success.",
851
369
  201: "Created.",
852
370
  202: "Accepted.",
@@ -864,13 +382,13 @@ function responsesOf(operation, statuses, response, route, requestIdHeader) {
864
382
  names.set(403, []);
865
383
  }
866
384
  for (const Declared of operation.errors) {
867
- const synthetic = new Exception2({
868
- layer: "use-case" /* UseCase */,
385
+ const synthetic = new Exception({
386
+ layer: ExceptionLayers.UseCase,
869
387
  name: Declared.name,
870
388
  source: "openapi",
871
389
  message: Declared.name
872
390
  });
873
- const status = statusOf2(synthetic, operation, statuses);
391
+ const status = statusOf(synthetic, operation, statuses);
874
392
  const list = names.get(status) ?? [];
875
393
  if (!list.includes(Declared.name))
876
394
  list.push(Declared.name);
@@ -948,12 +466,12 @@ function withoutKeys(schema, keys) {
948
466
  function requirementOf(requirement) {
949
467
  return { [requirement.scheme]: [...requirement.scopes ?? []] };
950
468
  }
951
- var openapi2 = sinkOf2({
469
+ export const openapi = sinkOf({
952
470
  name: "openapi",
953
471
  validate,
954
472
  build: (operations, options, { output }) => {
955
- const routes = operationRoutes2(operations, options);
956
- const requestIdHeader = requestIdHeaderOf2(options);
473
+ const routes = operationRoutes(operations, options);
474
+ const requestIdHeader = requestIdHeaderOf(options);
957
475
  const security = options.security;
958
476
  const records = new Set;
959
477
  for (const operation of operations) {
@@ -963,7 +481,7 @@ var openapi2 = sinkOf2({
963
481
  const models = {};
964
482
  const classes = new Map;
965
483
  for (const record of records) {
966
- const name = recordNameOf2(record);
484
+ const name = recordNameOf(record);
967
485
  if (!COMPONENT_NAME.test(name) || name === "Problem") {
968
486
  invalid(`The record class "${name}" cannot be a component name; give the class a name that is not "Problem".`);
969
487
  }
@@ -977,7 +495,7 @@ var openapi2 = sinkOf2({
977
495
  models[`${operation.id}#input`] = operation.input;
978
496
  models[`${operation.id}#response`] = operation.response;
979
497
  }
980
- const { schemas } = toOpenAPI2(models);
498
+ const { schemas } = toOpenAPI(models);
981
499
  const paths = {};
982
500
  const operationIds = new Set;
983
501
  const components = {};
@@ -1051,5 +569,3 @@ var openapi2 = sinkOf2({
1051
569
  };
1052
570
  }
1053
571
  });
1054
-
1055
- export { schemaLockOf2, diffSchemas2, schemaLockProblemsOf2, statusOf2, PROBLEM_MEDIA_TYPE2, problemOf2, outputValueOf2, ROUTE_OPTION_KEYS2, routeOptionsIssue2, requestIdHeaderOf2, operationRoutes2, openapi2 };