@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
@@ -0,0 +1,69 @@
1
+ import { Type } from "typebox";
2
+ import { recordPropertyLineage } from "../property/lineage.js";
3
+ import { derivePropertyOf } from "../property/refine.js";
4
+ import { rawTypeOf, schemaOf } from "../schema/schema.js";
5
+ import { withStandard } from "../standard/standard.js";
6
+ import { Kind } from "../symbols/kind.js";
7
+ import { fieldOf } from "./callable.js";
8
+ import { isBlueprint } from "./is-blueprint.js";
9
+ import { isBlueprintList, standardListOf } from "./list.js";
10
+ import { isOptionalRecord, isRecordClass } from "./record-field.js";
11
+ import { isBlueprintVariant, standardVariantOf } from "./variant.js";
12
+ const cache = new WeakMap;
13
+ export function optionalOf(given) {
14
+ const field = fieldOf(given);
15
+ const cached = cache.get(field);
16
+ if (cached)
17
+ return cached;
18
+ if (isOptionalRecord(field))
19
+ return field;
20
+ if (isRecordClass(field)) {
21
+ const optional = Object.freeze(withStandard({
22
+ [Kind]: "record",
23
+ record: field,
24
+ optional: true
25
+ }, (value) => value === undefined ? { value } : field.safeParse(value)));
26
+ cache.set(field, optional);
27
+ return optional;
28
+ }
29
+ if (isBlueprint(field)) {
30
+ if (field.optional)
31
+ return field;
32
+ const optional = {
33
+ ...field,
34
+ optional: true,
35
+ safeParse: (value) => value === undefined ? { value } : field.safeParse(value)
36
+ };
37
+ Object.freeze(withStandard(optional, (value) => optional.safeParse(value)));
38
+ cache.set(field, optional);
39
+ return optional;
40
+ }
41
+ if (isBlueprintList(field)) {
42
+ if (field.optional)
43
+ return field;
44
+ const optional = standardListOf({ ...field, optional: true });
45
+ cache.set(field, optional);
46
+ return optional;
47
+ }
48
+ if (isBlueprintVariant(field)) {
49
+ if (field.optional)
50
+ return field;
51
+ const optional = standardVariantOf({ ...field, optional: true });
52
+ cache.set(field, optional);
53
+ return optional;
54
+ }
55
+ const Property = field;
56
+ if (Property.type.optional)
57
+ return Property;
58
+ const base = Property.type;
59
+ const SchemaConstructor = schemaOf(base.name, Type.Optional(rawTypeOf(base.schema)));
60
+ const type = {
61
+ ...base,
62
+ schema: new SchemaConstructor,
63
+ optional: true
64
+ };
65
+ const Optional = derivePropertyOf(Property, type);
66
+ recordPropertyLineage(Optional, { kind: "optional", base: Property });
67
+ cache.set(Property, Optional);
68
+ return Optional;
69
+ }
@@ -0,0 +1,14 @@
1
+ import { Kind } from "../symbols/kind.js";
2
+ export function isRecordClass(value) {
3
+ return typeof value === "function" && value[Kind] === "record";
4
+ }
5
+ export function isOptionalRecord(value) {
6
+ return typeof value === "object" && value !== null && value[Kind] === "record";
7
+ }
8
+ export function recordFieldOf(field) {
9
+ if (isRecordClass(field))
10
+ return { record: field, optional: false };
11
+ if (isOptionalRecord(field))
12
+ return field;
13
+ return;
14
+ }
@@ -0,0 +1,127 @@
1
+ import { AbstractRecord } from "../record/abstract-record.js";
2
+ import { recordNameOf } from "../record/name.js";
3
+ import { declareRecord } from "../record/record.js";
4
+ import { blueprintFromProperties } from "./blueprint.js";
5
+ import {
6
+ InvalidBlueprintVariant,
7
+ UndeclaredBlueprintProperty
8
+ } from "./exceptions.js";
9
+ import { isBlueprint } from "./is-blueprint.js";
10
+ import { isBlueprintList, listOf } from "./list.js";
11
+ import { optionalOf } from "./optional.js";
12
+ import { isRecordClass, recordFieldOf } from "./record-field.js";
13
+ import { isBlueprintVariant } from "./variant.js";
14
+ function propertiesOfField(field) {
15
+ if (field === undefined)
16
+ return;
17
+ if (isBlueprintList(field))
18
+ return propertiesOfField(field.item);
19
+ const record = recordFieldOf(field);
20
+ if (record)
21
+ return record.record.blueprint.properties;
22
+ return isBlueprint(field) ? field.properties : undefined;
23
+ }
24
+ function maskOf(selector, against) {
25
+ if (isRecordClass(selector))
26
+ return maskOf(selector.blueprint, against);
27
+ if (isBlueprint(selector)) {
28
+ return Object.fromEntries(Object.entries(selector.properties).map(([key, field]) => [key, fieldMaskOf(field, against?.[key])]));
29
+ }
30
+ return selector;
31
+ }
32
+ function fieldMaskOf(field, other) {
33
+ if (isBlueprintList(field)) {
34
+ return fieldMaskOf(field.item, isBlueprintList(other) ? other.item : other);
35
+ }
36
+ const record = recordFieldOf(field);
37
+ if (record) {
38
+ if (record.record === recordFieldOf(other)?.record)
39
+ return true;
40
+ return maskOf(record.record, propertiesOfField(other));
41
+ }
42
+ if (isBlueprint(field)) {
43
+ return field === other ? true : maskOf(field, propertiesOfField(other));
44
+ }
45
+ return true;
46
+ }
47
+ function sliceCollection(properties, mask, path) {
48
+ const sliced = {};
49
+ for (const [key, selected] of Object.entries(mask)) {
50
+ if (!selected)
51
+ continue;
52
+ if (!Object.hasOwn(properties, key)) {
53
+ throw new UndeclaredBlueprintProperty({
54
+ source: "blueprint",
55
+ details: { key: path + key }
56
+ });
57
+ }
58
+ sliced[key] = sliceField(properties[key], selected, path + key);
59
+ }
60
+ return sliced;
61
+ }
62
+ function slicedRecordOf(Original, mask, path) {
63
+ const source = Original.blueprint;
64
+ const blueprint = blueprintFromProperties(source.plugins, sliceCollection(source.properties, mask, `${path}.`));
65
+ const kept = (keys) => keys.filter((key) => Object.hasOwn(blueprint.properties, key));
66
+ const { sensitive, unique, change } = Original.options;
67
+ const Sliced = declareRecord(AbstractRecord, blueprint, {
68
+ sensitive: kept(sensitive),
69
+ unique: kept(unique),
70
+ change: kept(change)
71
+ }, recordNameOf(Original));
72
+ Object.defineProperty(Sliced, Symbol.hasInstance, {
73
+ value(value) {
74
+ return Function.prototype[Symbol.hasInstance].call(this, value) || value instanceof Original;
75
+ }
76
+ });
77
+ return Sliced;
78
+ }
79
+ function sliceField(field, selected, path) {
80
+ if (selected === true)
81
+ return field;
82
+ if (isBlueprintList(field)) {
83
+ const list = listOf(sliceField(field.item, selected, path), {
84
+ minItems: field.minItems,
85
+ maxItems: field.maxItems
86
+ });
87
+ return field.optional ? optionalOf(list) : list;
88
+ }
89
+ const record = recordFieldOf(field);
90
+ if (record) {
91
+ const sliced = slicedRecordOf(record.record, selected, path);
92
+ return record.optional ? optionalOf(sliced) : sliced;
93
+ }
94
+ if (isBlueprint(field)) {
95
+ const sliced = blueprintFromProperties(field.plugins, sliceCollection(field.properties, selected, `${path}.`));
96
+ return field.optional ? optionalOf(sliced) : sliced;
97
+ }
98
+ if (isBlueprintVariant(field)) {
99
+ throw new InvalidBlueprintVariant({
100
+ source: "blueprint",
101
+ details: {
102
+ key: field.key,
103
+ reason: `"${path}" cannot be sliced by its keys yet, only picked whole`
104
+ }
105
+ });
106
+ }
107
+ throw new UndeclaredBlueprintProperty({
108
+ source: "blueprint",
109
+ details: { key: `${path}.${Object.keys(selected)[0] ?? ""}` }
110
+ });
111
+ }
112
+ export const sliceOf = (blueprint, selector) => blueprintFromProperties(blueprint.plugins, sliceCollection(blueprint.properties, maskOf(selector, blueprint.properties), ""));
113
+ export const sliceValue = (value, selector) => pick(value, maskOf(selector));
114
+ function pick(value, mask) {
115
+ if (Array.isArray(value))
116
+ return value.map((item) => pick(item, mask));
117
+ if (typeof value !== "object" || value === null)
118
+ return value;
119
+ const source = isRecordClass(value.constructor) ? value.toJSON() : value;
120
+ const picked = {};
121
+ for (const [key, selected] of Object.entries(mask)) {
122
+ if (!selected || !Object.hasOwn(source, key))
123
+ continue;
124
+ picked[key] = selected === true ? source[key] : pick(source[key], selected);
125
+ }
126
+ return picked;
127
+ }
@@ -277,7 +277,19 @@ export type OptionalProperties<Properties> = {
277
277
  readonly variants: infer Variants extends BlueprintVariants;
278
278
  } ? IBlueprintVariant<Name, Variants, true> : never;
279
279
  };
280
+ /**
281
+ * The function {@link blueprintOf} takes: it gets the context `ctx` of the
282
+ * sources (the factories of their plugins, `listOf`, `optionalOf`, `propertyOf`
283
+ * and `variantOf`) and gives the fields of the blueprint.
284
+ */
280
285
  export type BlueprintDefinition<Sources extends readonly BlueprintSource[], Properties extends IBlueprintCollection> = (ctx: BlueprintContext<Sources>) => Properties;
286
+ /**
287
+ * A blueprint: an object shape of named fields, made by {@link blueprintOf}. It
288
+ * parses a value with `safeParse` or its Standard Schema (`~standard`), joins
289
+ * others with `join`, and is a field of another blueprint or the base of a
290
+ * record (see {@link recordOf}). `Optional` is `true` for one that, as a field,
291
+ * accepts `undefined`.
292
+ */
281
293
  export interface IBlueprint<Properties extends IBlueprintCollection, Optional extends boolean = false> {
282
294
  readonly [Kind]: "blueprint";
283
295
  /** The plugins it was built from, its joined blueprints' included. */
@@ -323,6 +335,10 @@ export interface BlueprintBuilder<Base extends readonly BlueprintSource[]> {
323
335
  }
324
336
  /** `Blueprint` as a field that accepts `undefined`. */
325
337
  export type OptionalBlueprint<Blueprint extends AnyBlueprint> = Blueprint extends IBlueprint<infer Properties, boolean> ? IBlueprint<Properties, true> : never;
338
+ /**
339
+ * The bounds of a list field, as `ctx.listOf(item, { minItems, maxItems })`
340
+ * takes them: the fewest and the most items it accepts.
341
+ */
326
342
  export interface BlueprintListOptions {
327
343
  readonly minItems?: number;
328
344
  readonly maxItems?: number;
@@ -0,0 +1,72 @@
1
+ import { parseField } from "../parse/parse.js";
2
+ import { withStandard } from "../standard/standard.js";
3
+ import { Kind } from "../symbols/kind.js";
4
+ import { InvalidBlueprintVariant } from "./exceptions.js";
5
+ import { isBlueprint } from "./is-blueprint.js";
6
+ import { isRecordClass } from "./record-field.js";
7
+ export function variantOf(key, variants) {
8
+ const fail = (reason) => {
9
+ throw new InvalidBlueprintVariant({
10
+ source: "blueprint",
11
+ details: { key: String(key), reason }
12
+ });
13
+ };
14
+ if (typeof key !== "string" || key === "") {
15
+ fail("its key must be a string that is not empty");
16
+ }
17
+ const tags = Object.keys(variants);
18
+ if (tags.length === 0)
19
+ fail("it needs at least one variant");
20
+ const classes = new Set;
21
+ for (const tag of tags) {
22
+ const variant = variants[tag];
23
+ if (!isBlueprint(variant) && !isRecordClass(variant)) {
24
+ fail(`the variant "${tag}" is not a blueprint nor a record class`);
25
+ }
26
+ if (classes.has(variant)) {
27
+ fail(`the variant "${tag}" is a class another variant already is`);
28
+ }
29
+ if (isRecordClass(variant))
30
+ classes.add(variant);
31
+ if (Object.hasOwn(blueprintOfVariant(variant).properties, key)) {
32
+ fail(`the variant "${tag}" declares "${key}", which the field adds`);
33
+ }
34
+ }
35
+ return standardVariantOf({
36
+ [Kind]: "variant",
37
+ key,
38
+ variants: Object.freeze({ ...variants }),
39
+ optional: false
40
+ });
41
+ }
42
+ export function standardVariantOf(variant) {
43
+ return Object.freeze(withStandard(variant, (value) => parseField(variant, value, [], "variant")));
44
+ }
45
+ export function blueprintOfVariant(variant) {
46
+ return isRecordClass(variant) ? variant.blueprint : variant;
47
+ }
48
+ export function namedVariantOf(field, value) {
49
+ if (typeof value !== "object" || value === null)
50
+ return;
51
+ const tag = value[field.key];
52
+ const variants = field.variants;
53
+ return typeof tag === "string" && Object.hasOwn(variants, tag) ? variants[tag] : undefined;
54
+ }
55
+ export function variantOfValue(field, value) {
56
+ const variant = namedVariantOf(field, value);
57
+ return variant && blueprintOfVariant(variant);
58
+ }
59
+ export function variantNameOf(field, instance) {
60
+ if (typeof instance !== "object" || instance === null)
61
+ return;
62
+ const variants = field.variants;
63
+ for (const tag of Object.keys(variants)) {
64
+ const variant = variants[tag];
65
+ if (isRecordClass(variant) && instance instanceof variant)
66
+ return tag;
67
+ }
68
+ return;
69
+ }
70
+ export function isBlueprintVariant(value) {
71
+ return typeof value === "object" && value !== null && value[Kind] === "variant";
72
+ }