velocious 1.0.552 → 1.0.555

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 (117) hide show
  1. package/README.md +2 -0
  2. package/build/background-jobs/status-reporter.js +15 -2
  3. package/build/background-jobs/worker.js +5 -1
  4. package/build/frontend-models/base.js +105 -47
  5. package/build/frontend-models/transport-deadline.js +66 -0
  6. package/build/src/background-jobs/status-reporter.d.ts +3 -1
  7. package/build/src/background-jobs/status-reporter.d.ts.map +1 -1
  8. package/build/src/background-jobs/status-reporter.js +16 -3
  9. package/build/src/background-jobs/worker.d.ts.map +1 -1
  10. package/build/src/background-jobs/worker.js +6 -2
  11. package/build/src/frontend-models/base.d.ts +10 -1
  12. package/build/src/frontend-models/base.d.ts.map +1 -1
  13. package/build/src/frontend-models/base.js +71 -26
  14. package/build/src/frontend-models/transport-deadline.d.ts +26 -0
  15. package/build/src/frontend-models/transport-deadline.d.ts.map +1 -0
  16. package/build/src/frontend-models/transport-deadline.js +61 -0
  17. package/build/src/testing/factory/association-declaration.d.ts +37 -0
  18. package/build/src/testing/factory/association-declaration.d.ts.map +1 -0
  19. package/build/src/testing/factory/association-declaration.js +41 -0
  20. package/build/src/testing/factory/declarations.d.ts +190 -0
  21. package/build/src/testing/factory/declarations.d.ts.map +1 -0
  22. package/build/src/testing/factory/declarations.js +98 -0
  23. package/build/src/testing/factory/definition-builder.d.ts +132 -0
  24. package/build/src/testing/factory/definition-builder.d.ts.map +1 -0
  25. package/build/src/testing/factory/definition-builder.js +417 -0
  26. package/build/src/testing/factory/errors.d.ts +62 -0
  27. package/build/src/testing/factory/errors.d.ts.map +1 -0
  28. package/build/src/testing/factory/errors.js +67 -0
  29. package/build/src/testing/factory/evaluation-context.d.ts +95 -0
  30. package/build/src/testing/factory/evaluation-context.d.ts.map +1 -0
  31. package/build/src/testing/factory/evaluation-context.js +175 -0
  32. package/build/src/testing/factory/events.d.ts +21 -0
  33. package/build/src/testing/factory/events.d.ts.map +1 -0
  34. package/build/src/testing/factory/events.js +26 -0
  35. package/build/src/testing/factory/factory-definition.d.ts +39 -0
  36. package/build/src/testing/factory/factory-definition.d.ts.map +1 -0
  37. package/build/src/testing/factory/factory-definition.js +35 -0
  38. package/build/src/testing/factory/factory-registry.d.ts +263 -0
  39. package/build/src/testing/factory/factory-registry.d.ts.map +1 -0
  40. package/build/src/testing/factory/factory-registry.js +438 -0
  41. package/build/src/testing/factory/factory-runner.d.ts +179 -0
  42. package/build/src/testing/factory/factory-runner.d.ts.map +1 -0
  43. package/build/src/testing/factory/factory-runner.js +266 -0
  44. package/build/src/testing/factory/index.d.ts +18 -0
  45. package/build/src/testing/factory/index.d.ts.map +1 -0
  46. package/build/src/testing/factory/index.js +21 -0
  47. package/build/src/testing/factory/linter.d.ts +55 -0
  48. package/build/src/testing/factory/linter.d.ts.map +1 -0
  49. package/build/src/testing/factory/linter.js +106 -0
  50. package/build/src/testing/factory/model-contract.d.ts +11 -0
  51. package/build/src/testing/factory/model-contract.d.ts.map +1 -0
  52. package/build/src/testing/factory/model-contract.js +26 -0
  53. package/build/src/testing/factory/node/load-definitions.d.ts +24 -0
  54. package/build/src/testing/factory/node/load-definitions.d.ts.map +1 -0
  55. package/build/src/testing/factory/node/load-definitions.js +87 -0
  56. package/build/src/testing/factory/sequence.d.ts +73 -0
  57. package/build/src/testing/factory/sequence.d.ts.map +1 -0
  58. package/build/src/testing/factory/sequence.js +78 -0
  59. package/build/src/testing/factory/strategies/attributes-for.d.ts +21 -0
  60. package/build/src/testing/factory/strategies/attributes-for.d.ts.map +1 -0
  61. package/build/src/testing/factory/strategies/attributes-for.js +22 -0
  62. package/build/src/testing/factory/strategies/base.d.ts +101 -0
  63. package/build/src/testing/factory/strategies/base.d.ts.map +1 -0
  64. package/build/src/testing/factory/strategies/base.js +191 -0
  65. package/build/src/testing/factory/strategies/build.d.ts +20 -0
  66. package/build/src/testing/factory/strategies/build.d.ts.map +1 -0
  67. package/build/src/testing/factory/strategies/build.js +34 -0
  68. package/build/src/testing/factory/strategies/create.d.ts +32 -0
  69. package/build/src/testing/factory/strategies/create.d.ts.map +1 -0
  70. package/build/src/testing/factory/strategies/create.js +57 -0
  71. package/build/src/testing/factory/trait-definition.d.ts +22 -0
  72. package/build/src/testing/factory/trait-definition.d.ts.map +1 -0
  73. package/build/src/testing/factory/trait-definition.js +22 -0
  74. package/build/testing/factory/association-declaration.js +50 -0
  75. package/build/testing/factory/declarations.js +110 -0
  76. package/build/testing/factory/definition-builder.js +476 -0
  77. package/build/testing/factory/errors.js +79 -0
  78. package/build/testing/factory/evaluation-context.js +199 -0
  79. package/build/testing/factory/events.js +30 -0
  80. package/build/testing/factory/factory-definition.js +41 -0
  81. package/build/testing/factory/factory-registry.js +501 -0
  82. package/build/testing/factory/factory-runner.js +296 -0
  83. package/build/testing/factory/index.js +24 -0
  84. package/build/testing/factory/linter.js +119 -0
  85. package/build/testing/factory/model-contract.js +31 -0
  86. package/build/testing/factory/node/load-definitions.js +103 -0
  87. package/build/testing/factory/sequence.js +91 -0
  88. package/build/testing/factory/strategies/attributes-for.js +24 -0
  89. package/build/testing/factory/strategies/base.js +209 -0
  90. package/build/testing/factory/strategies/build.js +42 -0
  91. package/build/testing/factory/strategies/create.js +68 -0
  92. package/build/testing/factory/trait-definition.js +24 -0
  93. package/build/tsconfig.tsbuildinfo +1 -1
  94. package/package.json +1 -1
  95. package/src/background-jobs/status-reporter.js +15 -2
  96. package/src/background-jobs/worker.js +5 -1
  97. package/src/frontend-models/base.js +105 -47
  98. package/src/frontend-models/transport-deadline.js +66 -0
  99. package/src/testing/factory/association-declaration.js +50 -0
  100. package/src/testing/factory/declarations.js +110 -0
  101. package/src/testing/factory/definition-builder.js +476 -0
  102. package/src/testing/factory/errors.js +79 -0
  103. package/src/testing/factory/evaluation-context.js +199 -0
  104. package/src/testing/factory/events.js +30 -0
  105. package/src/testing/factory/factory-definition.js +41 -0
  106. package/src/testing/factory/factory-registry.js +501 -0
  107. package/src/testing/factory/factory-runner.js +296 -0
  108. package/src/testing/factory/index.js +24 -0
  109. package/src/testing/factory/linter.js +119 -0
  110. package/src/testing/factory/model-contract.js +31 -0
  111. package/src/testing/factory/node/load-definitions.js +103 -0
  112. package/src/testing/factory/sequence.js +91 -0
  113. package/src/testing/factory/strategies/attributes-for.js +24 -0
  114. package/src/testing/factory/strategies/base.js +209 -0
  115. package/src/testing/factory/strategies/build.js +42 -0
  116. package/src/testing/factory/strategies/create.js +68 -0
  117. package/src/testing/factory/trait-definition.js +24 -0
@@ -0,0 +1,199 @@
1
+ // @ts-check
2
+
3
+ import {FactoryCycleError, UndefinedAttributeError} from "./errors.js"
4
+
5
+ /**
6
+ * A single factory run's evaluation state. It resolves attributes/transients/
7
+ * associations lazily and memoizes each name exactly once per run (sharing an
8
+ * in-flight promise between concurrent dependents). Cycle detection uses a
9
+ * per-chain path so genuine recursion is reported while concurrent sibling reads
10
+ * of the same name are allowed.
11
+ */
12
+ export default class EvaluationContext {
13
+ /**
14
+ * Builds an evaluation context.
15
+ * @param {object} args - Options.
16
+ * @param {import("./factory-registry.js").default} args.registry - Owning registry.
17
+ * @param {import("./factory-runner.js").CompiledPlan} args.plan - Compiled run plan.
18
+ * @param {"attributesFor" | "build" | "create"} args.strategy - Active strategy.
19
+ */
20
+ constructor({registry, plan, strategy}) {
21
+ /** @type {import("./factory-registry.js").default} - Owning registry. */
22
+ this.registry = registry
23
+
24
+ /** @type {import("./factory-runner.js").CompiledPlan} - Compiled run plan. */
25
+ this.plan = plan
26
+
27
+ /** @type {"attributesFor" | "build" | "create"} - Active strategy. */
28
+ this.strategy = strategy
29
+
30
+ /** @type {Map<string, ?>} - Per-run memoized values / in-flight promises. */
31
+ this._memo = new Map()
32
+ }
33
+
34
+ /**
35
+ * Builds the named evaluator context handed to lazy values and callbacks for a
36
+ * given dependency path.
37
+ * @param {string[]} path - Current resolution path (for cycle detection).
38
+ * @returns {{get: (name: string) => Promise<?>, generate: (name: string) => Promise<?>, association: (factory: string, ...args: Array<?>) => Promise<?>}} - The evaluator context.
39
+ */
40
+ contextFor(path) {
41
+ return {
42
+ get: (name) => this._get(name, path),
43
+ generate: (name) => this.registry._generateScoped(name, this.plan.chainNames),
44
+ association: (factory, ...args) => this._explicitAssociation(factory, args, path)
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Resolves an attribute/transient/association by name, memoizing the result.
50
+ * @param {string} name - Name to resolve.
51
+ * @param {string[]} path - Current resolution path.
52
+ * @returns {Promise<?>} - The resolved value.
53
+ */
54
+ _get(name, path) {
55
+ if (path.includes(name)) {
56
+ throw new FactoryCycleError(`Attribute dependency cycle detected: ${[...path, name].join(" -> ")}`)
57
+ }
58
+
59
+ if (this._memo.has(name)) return this._memo.get(name)
60
+
61
+ const slot = this.plan.resolved.get(name)
62
+
63
+ if (!slot) {
64
+ throw new UndefinedAttributeError(`Unknown attribute "${name}" referenced while evaluating factory "${this.plan.factoryName}"`)
65
+ }
66
+
67
+ const promise = this._evaluateSlot(slot, [...path, name])
68
+
69
+ this._memo.set(name, promise)
70
+ promise.then((value) => this._memo.set(name, value), () => {})
71
+
72
+ return promise
73
+ }
74
+
75
+ /**
76
+ * Evaluates a resolved slot, honouring lazy functions and overrides.
77
+ * @param {import("./factory-runner.js").Slot} slot - Slot to evaluate.
78
+ * @param {string[]} childPath - Path including this slot's name.
79
+ * @returns {Promise<?>} - The evaluated value.
80
+ */
81
+ async _evaluateSlot(slot, childPath) {
82
+ if (slot.slotKind === "association") {
83
+ return await this._resolveAssociationSlot(slot)
84
+ }
85
+
86
+ if (typeof slot.value === "function" && !slot.isOverride) {
87
+ return await slot.value(this.contextFor(childPath))
88
+ }
89
+
90
+ return slot.value
91
+ }
92
+
93
+ /**
94
+ * Resolves a declared/overridden association slot. An explicit object/null
95
+ * override suppresses nested factory execution and is returned verbatim.
96
+ * @param {import("./factory-runner.js").Slot} slot - Association slot.
97
+ * @returns {Promise<?>} - The associated record (or override value).
98
+ */
99
+ async _resolveAssociationSlot(slot) {
100
+ if (slot.isOverride) return slot.value
101
+
102
+ if (this.strategy === "attributesFor") return null
103
+
104
+ const declaration = /** @type {import("./association-declaration.js").default} */ (slot.value)
105
+ const associationStrategy = declaration.strategy || (this.strategy === "create" ? "build" : this.strategy)
106
+
107
+ return await this.registry._runFactory({
108
+ factoryName: declaration.factory,
109
+ traits: declaration.traits,
110
+ overrides: declaration.overrides,
111
+ strategy: /** @type {"build" | "create"} */ (associationStrategy)
112
+ })
113
+ }
114
+
115
+ /**
116
+ * Runs an explicitly-invoked association from a lazy value's `association(...)`.
117
+ * @param {string} factoryName - Factory to run.
118
+ * @param {Array<?>} args - Traits and/or an overrides object.
119
+ * @param {string[]} _path - Current resolution path (unused; associations open a fresh run).
120
+ * @returns {Promise<?>} - The associated record, or null under attributesFor.
121
+ */
122
+ _explicitAssociation(factoryName, args, _path) {
123
+ if (this.strategy === "attributesFor") return Promise.resolve(null)
124
+
125
+ /** @type {string[]} */
126
+ const traits = []
127
+ /** @type {Record<string, ?>} */
128
+ let overrides = {}
129
+
130
+ for (const arg of args) {
131
+ if (typeof arg === "string") traits.push(arg)
132
+ else if (arg && typeof arg === "object") overrides = arg
133
+ }
134
+
135
+ const associationStrategy = this.strategy === "create" ? "build" : this.strategy
136
+
137
+ return this.registry._runFactory({factoryName, traits, overrides, strategy: associationStrategy})
138
+ }
139
+
140
+ /**
141
+ * Resolves every plain attribute slot (used by attributesFor). Transients and
142
+ * associations are omitted, though transients may still be evaluated on demand
143
+ * as dependencies.
144
+ * @returns {Promise<Record<string, ?>>} - The resolved attributes.
145
+ */
146
+ async resolveAttributes() {
147
+ /** @type {Record<string, ?>} */
148
+ const attributes = {}
149
+
150
+ for (const [name, slot] of this.plan.resolved) {
151
+ if (slot.slotKind === "attribute") {
152
+ attributes[name] = await this._get(name, [])
153
+ }
154
+ }
155
+
156
+ return attributes
157
+ }
158
+
159
+ /**
160
+ * Resolves every transient before callbacks that expose them as plain properties.
161
+ * @returns {Promise<Record<string, ?>>} - Evaluated transient values.
162
+ */
163
+ async resolveTransients() {
164
+ /** @type {Record<string, ?>} */
165
+ const transients = {}
166
+
167
+ for (const [name, slot] of this.plan.resolved) {
168
+ if (slot.slotKind === "transient") transients[name] = await this._get(name, [])
169
+ }
170
+
171
+ return transients
172
+ }
173
+
174
+ /**
175
+ * Resolves everything needed to construct a record: public attributes,
176
+ * transients, and associated records.
177
+ * @returns {Promise<{publicAttributes: Record<string, ?>, transients: Record<string, ?>, associations: Array<{name: string, record: ?}>}>} - Resolved construction inputs.
178
+ */
179
+ async resolveForConstruction() {
180
+ /** @type {Record<string, ?>} */
181
+ const publicAttributes = {}
182
+ /** @type {Record<string, ?>} */
183
+ const transients = {}
184
+ /** @type {Array<{name: string, record: ?}>} */
185
+ const associations = []
186
+
187
+ for (const [name, slot] of this.plan.resolved) {
188
+ if (slot.slotKind === "attribute") {
189
+ publicAttributes[name] = await this._get(name, [])
190
+ } else if (slot.slotKind === "transient") {
191
+ transients[name] = await this._get(name, [])
192
+ } else if (slot.slotKind === "association") {
193
+ associations.push({name, record: await this._get(name, [])})
194
+ }
195
+ }
196
+
197
+ return {publicAttributes, transients, associations}
198
+ }
199
+ }
@@ -0,0 +1,30 @@
1
+ // @ts-check
2
+
3
+ import EventEmitter from "../../utils/event-emitter.js"
4
+
5
+ /**
6
+ * A small factory event emitter used for debug/performance hooks. It emits
7
+ * `start`, `success` and `failure` events carrying the factory name, strategy,
8
+ * requested traits, a per-invocation correlation id and (on completion) a
9
+ * duration. It deliberately never emits resolved attribute values, which may
10
+ * contain secrets.
11
+ */
12
+ export default class FactoryEventEmitter extends EventEmitter {
13
+ /** Builds the emitter. */
14
+ constructor() {
15
+ super()
16
+
17
+ /** @type {number} - Monotonic invocation counter for correlation ids. */
18
+ this._invocationCounter = 0
19
+ }
20
+
21
+ /**
22
+ * Allocates the next per-invocation correlation id.
23
+ * @returns {string} - A unique-per-registry correlation id.
24
+ */
25
+ nextInvocationId() {
26
+ this._invocationCounter += 1
27
+
28
+ return `factory-invocation-${this._invocationCounter}`
29
+ }
30
+ }
@@ -0,0 +1,41 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * An immutable compiled factory. Definitions never mutate after compilation;
5
+ * `modify` produces a replacement rather than editing an existing one. Parent and
6
+ * trait references are resolved lazily at evaluation time, so a child may be
7
+ * declared before its parent.
8
+ */
9
+ export default class FactoryDefinition {
10
+ /**
11
+ * Builds a factory definition.
12
+ * @param {object} args - Options.
13
+ * @param {string} args.name - Factory name.
14
+ * @param {(new (attributes?: Record<string, ?>) => ?) | null} args.modelClass - Model class, or null to inherit from a parent.
15
+ * @param {string | null} args.parentName - Parent factory name, or null.
16
+ * @param {string[]} args.aliases - Alias names that reference this same definition.
17
+ * @param {import("./declarations.js").Declaration[]} args.declarations - Ordered own declarations.
18
+ * @param {Map<string, import("./trait-definition.js").default>} args.localTraits - Factory-local traits keyed by name.
19
+ */
20
+ constructor({name, modelClass, parentName, aliases, declarations, localTraits}) {
21
+ /** @type {string} - Factory name. */
22
+ this.name = name
23
+
24
+ /** @type {(new (attributes?: Record<string, ?>) => ?) | null} - Model class or null. */
25
+ this.modelClass = modelClass
26
+
27
+ /** @type {string | null} - Parent factory name or null. */
28
+ this.parentName = parentName
29
+
30
+ /** @type {Array<string>} - Alias names. */
31
+ this.aliases = /** @type {Array<string>} */ (Object.freeze([...aliases]))
32
+
33
+ /** @type {Array<import("./declarations.js").Declaration>} - Ordered own declarations. */
34
+ this.declarations = /** @type {Array<import("./declarations.js").Declaration>} */ (Object.freeze([...declarations]))
35
+
36
+ /** @type {Map<string, import("./trait-definition.js").default>} - Factory-local traits. */
37
+ this.localTraits = localTraits
38
+
39
+ Object.freeze(this)
40
+ }
41
+ }