@joakimbugge/typeorm-seeder 0.5.0 → 0.6.1
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.
- package/README.md +109 -9
- package/dist/index.cjs +53 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -46
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +90 -46
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +50 -34
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Decorator-based entity seeding for TypeORM. Annotate your entity properties with `@Seed()`, then create or persist fully populated entity graphs with a single function call — including relations, embedded types, and circular guards. Organise complex seeding scenarios into `@Seeder` classes with declared dependencies that are automatically ordered and executed for you.
|
|
4
4
|
|
|
5
|
+
[](https://github.com/joakimbugge/to-seeder/actions/workflows/ci.yml)
|
|
6
|
+
[](https://codecov.io/gh/joakimbugge/to-seeder)
|
|
7
|
+
|
|
5
8
|
Coded by AI. Reviewed by humans.
|
|
6
9
|
|
|
7
10
|
---
|
|
@@ -9,12 +12,20 @@ Coded by AI. Reviewed by humans.
|
|
|
9
12
|
- [Installation](#installation)
|
|
10
13
|
- [Decorating entities](#decorating-entities)
|
|
11
14
|
- [Seeding entities](#seeding-entities)
|
|
15
|
+
- [Saving](#saving)
|
|
16
|
+
- [Without saving](#without-saving)
|
|
17
|
+
- [Multiple entity types at once](#multiple-entity-types-at-once)
|
|
18
|
+
- [Skipping relations](#skipping-relations)
|
|
19
|
+
- [Passing a DataSource to factories](#passing-a-datasource-to-factories)
|
|
20
|
+
- [Overriding seeded values](#overriding-seeded-values)
|
|
21
|
+
- [Depending on earlier properties](#depending-on-earlier-properties)
|
|
12
22
|
- [Seeder suites](#seeder-suites)
|
|
13
23
|
- [Seeding without `@Seed()`](#seeding-without-seed)
|
|
14
24
|
- [Logging](#logging)
|
|
15
25
|
- [Hooks](#hooks)
|
|
16
26
|
- [Skipping seeders](#skipping-seeders)
|
|
17
27
|
- [Running seed scripts](#running-seed-scripts)
|
|
28
|
+
- [TypeScript execution](#typescript-execution)
|
|
18
29
|
- [API reference](#api-reference)
|
|
19
30
|
|
|
20
31
|
---
|
|
@@ -173,6 +184,66 @@ If a factory needs to query the database, the `dataSource` you provide in option
|
|
|
173
184
|
role!: Role
|
|
174
185
|
```
|
|
175
186
|
|
|
187
|
+
> [!TIP]
|
|
188
|
+
> For anything more complex than a simple lookup — such as picking a random element from a result set — prefer the [`values` option](#overriding-seeded-values) instead. It keeps that logic in the call site rather than the entity decorator.
|
|
189
|
+
|
|
190
|
+
### Overriding seeded values
|
|
191
|
+
|
|
192
|
+
Pass a `values` map to inject specific values after all `@Seed` factories have run:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
// Status is set even if Booking has no @Seed on it
|
|
196
|
+
const booking = await seed(Booking).create({ values: { status: 'confirmed' } })
|
|
197
|
+
const booking = await seed(Booking).save({ dataSource, values: { user, status: 'confirmed' } })
|
|
198
|
+
// All 5 get the same user
|
|
199
|
+
const bookings = await seed(Booking).createMany(5, { values: { user } })
|
|
200
|
+
const bookings = await seed(Booking).saveMany(5, { dataSource, values: { user } })
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Each property in `values` can also be a factory function — it is called once per entity, so every instance can receive a unique generated value:
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
const bookings = await seed(Booking).saveMany(10, {
|
|
207
|
+
dataSource,
|
|
208
|
+
values: {
|
|
209
|
+
// Unique per booking
|
|
210
|
+
price: () => faker.number.float({ min: 10, max: 500 }),
|
|
211
|
+
// Same for all
|
|
212
|
+
status: 'confirmed',
|
|
213
|
+
},
|
|
214
|
+
})
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Factory entries in `values` receive the same `(context, self)` arguments as `@Seed` factories, so you can read already-applied properties from `self` or query the database via `context.dataSource`.
|
|
218
|
+
|
|
219
|
+
`values` wins unconditionally: if a property has a `@Seed` factory, the factory still runs but its result is overwritten. `values` also works for properties with no `@Seed` decorator at all.
|
|
220
|
+
|
|
221
|
+
> [!NOTE]
|
|
222
|
+
> `values` are applied **after** all `@Seed` factories have finished, so they are never visible on `self` inside a `@Seed` factory callback.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### Depending on earlier properties
|
|
227
|
+
|
|
228
|
+
Properties are seeded in declaration order. Each factory receives the partially-built entity as its second argument (`self`), so a property can read any value that was seeded above it:
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
@Entity()
|
|
232
|
+
class Event {
|
|
233
|
+
@Seed(() => faker.date.past())
|
|
234
|
+
@Column()
|
|
235
|
+
beginDate!: Date
|
|
236
|
+
|
|
237
|
+
@Seed((_, self: Event) => faker.date.future({ refDate: self.beginDate }))
|
|
238
|
+
@Column()
|
|
239
|
+
endDate!: Date
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Annotating `self` with the entity class (`self: Event` above) gives full type inference and autocompletion. Without the annotation `self` is typed as `any`, so property access still works — the annotation is only needed for type safety.
|
|
244
|
+
|
|
245
|
+
Properties declared *below* the current property are not yet set and will be `undefined` on `self` at that point.
|
|
246
|
+
|
|
176
247
|
---
|
|
177
248
|
|
|
178
249
|
## Seeder suites
|
|
@@ -210,21 +281,22 @@ Circular dependencies between seeders are detected at runtime and throw an error
|
|
|
210
281
|
|
|
211
282
|
## Seeding without `@Seed()`
|
|
212
283
|
|
|
213
|
-
`@Seed()` is a convenience — it is not required.
|
|
284
|
+
`@Seed()` is a convenience — it is not required. Complex seeding logic that would clutter entity decorators belongs in the seeder suite instead. Use the [`values` option](#overriding-seeded-values) to inject the result at call time, keeping your entities simple:
|
|
214
285
|
|
|
215
286
|
```ts
|
|
216
|
-
@Seeder()
|
|
217
|
-
class
|
|
287
|
+
@Seeder({ dependencies: [UserSeeder] })
|
|
288
|
+
class BookingSeeder implements SeederInterface {
|
|
218
289
|
async run({ dataSource }: SeedContext): Promise<void> {
|
|
219
|
-
await dataSource!.getRepository(User).
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
290
|
+
const users = await dataSource!.getRepository(User).find()
|
|
291
|
+
const user = faker.helpers.arrayElement(users)
|
|
292
|
+
|
|
293
|
+
// user is resolved here and injected — Booking stays simple
|
|
294
|
+
await seed(Booking).saveMany(10, { dataSource, values: { user } })
|
|
223
295
|
}
|
|
224
296
|
}
|
|
225
297
|
```
|
|
226
298
|
|
|
227
|
-
|
|
299
|
+
If you need full control — inserting specific rows, running raw queries, or using TypeORM's `EntityManager` — the `dataSource` from `SeedContext` gives you direct access to any TypeORM API.
|
|
228
300
|
|
|
229
301
|
---
|
|
230
302
|
|
|
@@ -326,11 +398,23 @@ Property decorator. Marks a property for automatic seeding.
|
|
|
326
398
|
|
|
327
399
|
| Signature | Behaviour |
|
|
328
400
|
|---|---|
|
|
329
|
-
| `@Seed(factory)` | Calls `factory(context)` and assigns the result |
|
|
401
|
+
| `@Seed(factory)` | Calls `factory(context, self)` and assigns the result |
|
|
330
402
|
| `@Seed(factory, options)` | Same, with additional options |
|
|
331
403
|
| `@Seed(options)` | Relation seed with options (e.g. `count`) |
|
|
332
404
|
| `@Seed()` | Bare relation seed — auto-creates one related entity |
|
|
333
405
|
|
|
406
|
+
**`SeedFactory<T, TEntity>`**
|
|
407
|
+
|
|
408
|
+
```ts
|
|
409
|
+
type SeedFactory<T = unknown, TEntity = any> = (context: SeedContext, self: TEntity) => T | Promise<T>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
`self` is the entity instance as it exists when the factory runs — properties declared above this one are already populated, properties below are `undefined`. Annotate `self` with the entity class to get type inference:
|
|
413
|
+
|
|
414
|
+
```ts
|
|
415
|
+
@Seed((_, self: MyEntity) => ...)
|
|
416
|
+
```
|
|
417
|
+
|
|
334
418
|
**`SeedOptions`**
|
|
335
419
|
|
|
336
420
|
| Property | Type | Description |
|
|
@@ -359,6 +443,22 @@ seed([Author, Book]).save(options): Promise<[Author, Book]>
|
|
|
359
443
|
seed([Author, Book]).saveMany(count, options): Promise<[Author[], Book[]]>
|
|
360
444
|
```
|
|
361
445
|
|
|
446
|
+
**`CreateOptions<T>`** — passed to `create()` and `createMany()` on the single-class form
|
|
447
|
+
|
|
448
|
+
| Property | Type | Description |
|
|
449
|
+
|---|---|---|
|
|
450
|
+
| `dataSource` | `DataSource?` | Forwarded to factory functions via `SeedContext`. |
|
|
451
|
+
| `relations` | `boolean?` | Set to `false` to skip relation seeding. Defaults to `true`. |
|
|
452
|
+
| `values` | `SeedValues<T>?` | Property values applied after all `@Seed` factories have run. Each entry can be a static value or a factory called once per entity. Wins unconditionally — `@Seed` factories still execute but their output is overwritten. Also works for properties with no `@Seed` decorator. |
|
|
453
|
+
|
|
454
|
+
**`SaveOptions<T>`** — passed to `save()` and `saveMany()` on the single-class form
|
|
455
|
+
|
|
456
|
+
| Property | Type | Description |
|
|
457
|
+
|---|---|---|
|
|
458
|
+
| `dataSource` | `DataSource` | Required. Active TypeORM data source used to persist entities. |
|
|
459
|
+
| `relations` | `boolean?` | Set to `false` to skip relation seeding. Defaults to `true`. |
|
|
460
|
+
| `values` | `SeedValues<T>?` | Property values applied after seeding and before persisting. Each entry can be a static value or a factory called once per entity. Wins unconditionally — `@Seed` factories still execute but their output is overwritten. Also works for properties with no `@Seed` decorator. |
|
|
461
|
+
|
|
362
462
|
---
|
|
363
463
|
|
|
364
464
|
### `@Seeder(options?)`
|
package/dist/index.cjs
CHANGED
|
@@ -42,6 +42,18 @@ function Seed(factoryOrOptions, options) {
|
|
|
42
42
|
function getAncestors(context) {
|
|
43
43
|
return context._ancestors ?? /* @__PURE__ */ new Set();
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Applies a {@link SeedValues} map to an instance.
|
|
47
|
+
* Factory entries are called once per instance so each entity can get unique values.
|
|
48
|
+
*/
|
|
49
|
+
async function applyValues(instance, values, context) {
|
|
50
|
+
const record = instance;
|
|
51
|
+
for (const key of Object.keys(values)) {
|
|
52
|
+
const value = values[key];
|
|
53
|
+
if (typeof value === "function") record[key] = await value(context, instance);
|
|
54
|
+
else record[key] = value;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
45
57
|
/** Returns a new context with `cls` added to the ancestor set, used to detect circular relation chains. */
|
|
46
58
|
function withAncestor(context, cls) {
|
|
47
59
|
const ancestors = getAncestors(context);
|
|
@@ -69,7 +81,7 @@ function getClassHierarchy(target) {
|
|
|
69
81
|
* 3. Bare relation decorators (`@Seed()` without a factory) — skipped when `relations` is `false`,
|
|
70
82
|
* and also skipped for any related class already present in the ancestor chain (circular guard).
|
|
71
83
|
*/
|
|
72
|
-
async function
|
|
84
|
+
async function createOne(EntityClass, context) {
|
|
73
85
|
const instance = new EntityClass();
|
|
74
86
|
const ancestors = getAncestors(context);
|
|
75
87
|
const childContext = withAncestor(context, EntityClass);
|
|
@@ -86,7 +98,7 @@ async function createOneSeed(EntityClass, context) {
|
|
|
86
98
|
if (seededProperties.has(embedded.propertyName)) continue;
|
|
87
99
|
const EmbeddedClass = embedded.type();
|
|
88
100
|
if (getSeeds(EmbeddedClass).length > 0) {
|
|
89
|
-
record[embedded.propertyName] = await
|
|
101
|
+
record[embedded.propertyName] = await createOne(EmbeddedClass, context);
|
|
90
102
|
seededProperties.add(embedded.propertyName);
|
|
91
103
|
}
|
|
92
104
|
}
|
|
@@ -97,38 +109,39 @@ async function createOneSeed(EntityClass, context) {
|
|
|
97
109
|
if (!relation || typeof relation.type !== "function") continue;
|
|
98
110
|
const RelatedClass = relation.type();
|
|
99
111
|
if (ancestors.has(RelatedClass)) continue;
|
|
100
|
-
if (relation.relationType === "one-to-many" || relation.relationType === "many-to-many") record[propertyKey] = await
|
|
112
|
+
if (relation.relationType === "one-to-many" || relation.relationType === "many-to-many") record[propertyKey] = await createMany(RelatedClass, {
|
|
101
113
|
count: options.count ?? 1,
|
|
102
114
|
...childContext
|
|
103
115
|
});
|
|
104
|
-
else record[propertyKey] = await
|
|
116
|
+
else record[propertyKey] = await createOne(RelatedClass, childContext);
|
|
105
117
|
seededProperties.add(propertyKey);
|
|
106
118
|
}
|
|
107
119
|
return instance;
|
|
108
120
|
}
|
|
109
|
-
async function
|
|
121
|
+
async function create(classOrClasses, options = {}) {
|
|
110
122
|
if (Array.isArray(classOrClasses)) {
|
|
111
123
|
const effectiveContext = {
|
|
112
124
|
relations: false,
|
|
113
|
-
...
|
|
125
|
+
...options
|
|
114
126
|
};
|
|
115
|
-
return await Promise.all(classOrClasses.map((cls) =>
|
|
127
|
+
return await Promise.all(classOrClasses.map((cls) => createOne(cls, effectiveContext)));
|
|
116
128
|
}
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return entity;
|
|
129
|
+
const { values, ...context } = options;
|
|
130
|
+
const instance = await createOne(classOrClasses, context);
|
|
131
|
+
if (values) await applyValues(instance, values, context);
|
|
132
|
+
return instance;
|
|
122
133
|
}
|
|
123
|
-
async function
|
|
134
|
+
async function createMany(classOrClasses, { count, values, ...context }) {
|
|
124
135
|
if (Array.isArray(classOrClasses)) {
|
|
125
136
|
const effectiveContext = {
|
|
126
137
|
relations: false,
|
|
127
138
|
...context
|
|
128
139
|
};
|
|
129
|
-
return await Promise.all(classOrClasses.map((cls) => Promise.all(Array.from({ length: count }, () =>
|
|
140
|
+
return await Promise.all(classOrClasses.map((cls) => Promise.all(Array.from({ length: count }, () => createOne(cls, effectiveContext)))));
|
|
130
141
|
}
|
|
131
|
-
|
|
142
|
+
const instances = await Promise.all(Array.from({ length: count }, () => createOne(classOrClasses, context)));
|
|
143
|
+
if (values) await Promise.all(instances.map((instance) => applyValues(instance, values, context)));
|
|
144
|
+
return instances;
|
|
132
145
|
}
|
|
133
146
|
//#endregion
|
|
134
147
|
//#region src/seed/persist.ts
|
|
@@ -178,40 +191,43 @@ function enableCascadeInsert(EntityClass, dataSource) {
|
|
|
178
191
|
function restoreCascade(states) {
|
|
179
192
|
for (const { relation, original } of states) relation.isCascadeInsert = original;
|
|
180
193
|
}
|
|
181
|
-
async function
|
|
194
|
+
async function save(classOrClasses, options) {
|
|
182
195
|
if (Array.isArray(classOrClasses)) {
|
|
183
196
|
const effectiveOptions = {
|
|
184
197
|
relations: false,
|
|
185
198
|
...options,
|
|
186
199
|
count: 1
|
|
187
200
|
};
|
|
188
|
-
return await Promise.all(classOrClasses.map((cls) =>
|
|
201
|
+
return await Promise.all(classOrClasses.map((cls) => saveBatch(cls, effectiveOptions).then(([entity]) => entity)));
|
|
189
202
|
}
|
|
190
|
-
const [entity] = await
|
|
203
|
+
const [entity] = await saveBatch(classOrClasses, {
|
|
191
204
|
...options,
|
|
192
205
|
count: 1
|
|
193
206
|
});
|
|
194
207
|
return entity;
|
|
195
208
|
}
|
|
196
|
-
async function
|
|
209
|
+
async function saveMany(classOrClasses, options) {
|
|
197
210
|
if (Array.isArray(classOrClasses)) {
|
|
198
211
|
const effectiveOptions = {
|
|
199
212
|
relations: false,
|
|
200
213
|
...options
|
|
201
214
|
};
|
|
202
|
-
return await Promise.all(classOrClasses.map((cls) =>
|
|
215
|
+
return await Promise.all(classOrClasses.map((cls) => saveBatch(cls, effectiveOptions)));
|
|
203
216
|
}
|
|
204
|
-
return await
|
|
217
|
+
return await saveBatch(classOrClasses, options);
|
|
205
218
|
}
|
|
206
219
|
/**
|
|
207
|
-
* Creates and persists `count` instances of a single entity class
|
|
220
|
+
* Creates and persists `count` instances of a single entity class in one batched
|
|
221
|
+
* `repository.save()` call. Batching is intentional — it is more efficient than
|
|
222
|
+
* saving each instance individually, as TypeORM can consolidate the inserts.
|
|
223
|
+
*
|
|
208
224
|
* Enables cascade inserts on every entity class in the object graph before saving,
|
|
209
225
|
* then restores the original flags — regardless of whether the save succeeds or fails.
|
|
210
226
|
*/
|
|
211
|
-
async function
|
|
227
|
+
async function saveBatch(EntityClass, options) {
|
|
212
228
|
const { count, dataSource } = options;
|
|
213
229
|
if (count === 0) return [];
|
|
214
|
-
const entities = await
|
|
230
|
+
const entities = await createMany(EntityClass, options);
|
|
215
231
|
const visited = /* @__PURE__ */ new Set();
|
|
216
232
|
const states = entities.flatMap((entity) => collectEntityClasses(entity, visited)).flatMap((cls) => enableCascadeInsert(cls, dataSource));
|
|
217
233
|
try {
|
|
@@ -226,13 +242,13 @@ function seed(classOrClasses) {
|
|
|
226
242
|
if (Array.isArray(classOrClasses)) {
|
|
227
243
|
const classes = classOrClasses;
|
|
228
244
|
return {
|
|
229
|
-
create: (context) =>
|
|
230
|
-
save: (options) =>
|
|
231
|
-
createMany: (count, context) =>
|
|
245
|
+
create: (context) => create(classes, context),
|
|
246
|
+
save: (options) => save(classes, options),
|
|
247
|
+
createMany: (count, context) => createMany(classes, {
|
|
232
248
|
count,
|
|
233
249
|
...context
|
|
234
250
|
}),
|
|
235
|
-
saveMany: (count, options) =>
|
|
251
|
+
saveMany: (count, options) => saveMany(classes, {
|
|
236
252
|
count,
|
|
237
253
|
...options
|
|
238
254
|
})
|
|
@@ -240,13 +256,13 @@ function seed(classOrClasses) {
|
|
|
240
256
|
}
|
|
241
257
|
const EntityClass = classOrClasses;
|
|
242
258
|
return {
|
|
243
|
-
create: (
|
|
244
|
-
save: (options) =>
|
|
245
|
-
createMany: (count,
|
|
259
|
+
create: (options) => create(EntityClass, options),
|
|
260
|
+
save: (options) => save(EntityClass, options),
|
|
261
|
+
createMany: (count, options) => createMany(EntityClass, {
|
|
246
262
|
count,
|
|
247
|
-
...
|
|
263
|
+
...options
|
|
248
264
|
}),
|
|
249
|
-
saveMany: (count, options) =>
|
|
265
|
+
saveMany: (count, options) => saveMany(EntityClass, {
|
|
250
266
|
count,
|
|
251
267
|
...options
|
|
252
268
|
})
|
|
@@ -357,11 +373,11 @@ async function runSeeders(seeders, options = {}) {
|
|
|
357
373
|
//#endregion
|
|
358
374
|
exports.Seed = Seed;
|
|
359
375
|
exports.Seeder = Seeder;
|
|
360
|
-
exports.
|
|
361
|
-
exports.
|
|
376
|
+
exports.create = create;
|
|
377
|
+
exports.createMany = createMany;
|
|
362
378
|
exports.runSeeders = runSeeders;
|
|
363
|
-
exports.
|
|
364
|
-
exports.
|
|
379
|
+
exports.save = save;
|
|
380
|
+
exports.saveMany = saveMany;
|
|
365
381
|
exports.seed = seed;
|
|
366
382
|
|
|
367
383
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["registry","DepGraph"],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/creator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seeder/registry.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"sourcesContent":["import type { DataSource } from 'typeorm';\n\n/** An entity instance — any class-based object managed by TypeORM. */\nexport type EntityInstance = object;\n\n/** A constructor that produces an entity instance. */\nexport type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;\n\n/** Context passed through a seed operation. Available inside factory callbacks and `SeederInterface.run`. */\nexport interface SeedContext {\n /**\n * The TypeORM DataSource. Automatically set by `save`/`saveMany` calls.\n * Also available in factory callbacks — useful for looking up existing\n * entities instead of creating new ones:\n *\n * @example\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\n dataSource?: DataSource;\n /**\n * Set to `false` to skip automatic relation seeding. Scalar and embedded\n * properties are still seeded; only relation properties decorated with a\n * bare `@Seed()` are skipped. Useful when you want to create flat entities\n * and wire relations yourself.\n *\n * @default true\n */\n relations?: boolean;\n}\n\n/**\n * Factory callback passed to `@Seed`. Receives the seed context and the partially built entity.\n *\n * Properties are seeded sequentially in declaration order, so any property declared above the\n * current one is already set on `self` and can be read to derive the current value:\n *\n * @example\n * @Seed(() => faker.date.past())\n * beginDate!: Date\n *\n * @Seed((_, self) => faker.date.future({ refDate: (self as MyEntity).beginDate }))\n * endDate!: Date\n */\nexport type SeedFactory<T = unknown> = (\n context: SeedContext,\n self: EntityInstance,\n) => T | Promise<T>;\n\n/** Options for the `@Seed` decorator. */\nexport interface SeedOptions {\n /**\n * Number of related entities to create. Only meaningful on one-to-many and\n * many-to-many relation properties. Ignored on scalar and single-entity relations.\n */\n count?: number;\n}\n\nexport interface SeedEntry {\n propertyKey: string | symbol;\n /** Undefined when @Seed is used without a factory (i.e. bare relation seed). */\n factory: SeedFactory | undefined;\n options: SeedOptions;\n}\n\nexport type MapToInstances<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I : never;\n};\n\nexport type MapToInstanceArrays<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never;\n};\n\n// Keyed by the entity class constructor.\nconst registry = new Map<Function, SeedEntry[]>();\n\n/** Registers a seed entry for the given class constructor. Called internally by the `@Seed` decorator. */\nexport function registerSeed(target: Function, entry: SeedEntry): void {\n const entries = registry.get(target) ?? [];\n\n entries.push(entry);\n registry.set(target, entries);\n}\n\n/**\n * Returns all seed entries for the given class, including those inherited from\n * parent classes. Parent entries come first, preserving declaration order.\n */\nexport function getSeeds(target: Function): SeedEntry[] {\n const entries: SeedEntry[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n const own = registry.get(current);\n\n if (own) {\n entries.unshift(...own);\n }\n\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return entries;\n}\n","import { registerSeed } from './registry.js';\nimport type { SeedFactory, SeedOptions } from './registry.js';\n\n/**\n * Marks a relation property for auto-seeding.\n *\n * The related entity class is inferred from TypeORM metadata. One instance is created\n * and recursively seeded (including its own `@Seed` properties).\n *\n * Circular back-references are broken automatically: if the related class is already\n * being seeded higher up in the same call chain, the property is left `undefined`.\n * TypeORM treats `undefined` as \"don't touch this column\" rather than setting it to null.\n */\nexport function Seed(): PropertyDecorator;\n/**\n * Marks a relation property for auto-seeding with options.\n *\n * Use `count` on one-to-many and many-to-many properties to control how many\n * related entities are created. Ignored for one-to-one and many-to-one.\n *\n * @example\n * @Seed({ count: 3 })\n * @OneToMany(() => Book, (b) => b.author)\n * books!: Book[]\n */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/**\n * Marks a property with a factory callback.\n *\n * The factory receives the current {@link SeedContext} and can return any value,\n * including a `Promise`. Use this for scalar properties or when you need full\n * control over how a related entity is resolved.\n *\n * @example\n * @Seed(() => faker.internet.email())\n * email!: string\n *\n * @example\n * // Look up an existing entity instead of creating a new one\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\nexport function Seed(factory: SeedFactory): PropertyDecorator;\n/** Marks a property with a factory callback and additional options. */\nexport function Seed(factory: SeedFactory, options: SeedOptions): PropertyDecorator;\nexport function Seed(\n factoryOrOptions?: SeedFactory | SeedOptions,\n options?: SeedOptions,\n): PropertyDecorator {\n const factory = typeof factoryOrOptions === 'function' ? factoryOrOptions : undefined;\n const opts: SeedOptions =\n (typeof factoryOrOptions === 'object' ? factoryOrOptions : options) ?? {};\n\n return (target, propertyKey) => {\n registerSeed(target.constructor as Function, { propertyKey, factory, options: opts });\n };\n}\n","import { getMetadataArgsStorage } from 'typeorm';\nimport { getSeeds } from './registry.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link createManySeed}. Extends {@link SeedContext} with a required instance count. */\nexport interface CreateManySeedOptions extends SeedContext {\n count: number;\n}\n\n// Internal extension of SeedContext — never exposed in the public API.\ninterface InternalContext extends SeedContext {\n _ancestors: Set<Function>;\n}\n\n/** Extracts the ancestor set from an internal context, returning an empty set for external callers. */\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\n/** Returns a new context with `cls` added to the ancestor set, used to detect circular relation chains. */\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\n/** Walks the prototype chain and returns all classes from `target` up to (but not including) `Function.prototype`. */\nfunction getClassHierarchy(target: Function): Function[] {\n const hierarchy: Function[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n hierarchy.push(current);\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return hierarchy;\n}\n\n/**\n * Creates one fully populated instance of `EntityClass` in memory.\n *\n * Runs in three steps:\n * 1. Factory-decorated properties (`@Seed(factory)`) — run first, in declaration order.\n * 2. Embedded types (`@Embedded`) — auto-seeded if the embedded class has any `@Seed` entries.\n * 3. Bare relation decorators (`@Seed()` without a factory) — skipped when `relations` is `false`,\n * and also skipped for any related class already present in the ancestor chain (circular guard).\n */\nasync function createOneSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context: SeedContext,\n): Promise<T> {\n const instance = new EntityClass();\n const ancestors = getAncestors(context);\n const childContext = withAncestor(context, EntityClass);\n const storage = getMetadataArgsStorage();\n const relations = storage.filterRelations(getClassHierarchy(EntityClass));\n const seededProperties = new Set<string | symbol>();\n const record = instance as Record<string | symbol, unknown>;\n\n // Step 1: Run @Seed entries that have an explicit factory.\n for (const { propertyKey, factory } of getSeeds(EntityClass)) {\n if (!factory) {\n continue;\n }\n\n record[propertyKey] = await factory(context, instance);\n seededProperties.add(propertyKey);\n }\n\n // Step 2: Auto-seed TypeORM embedded properties not already covered by Step 1.\n for (const embedded of storage.filterEmbeddeds(EntityClass)) {\n if (seededProperties.has(embedded.propertyName)) {\n continue;\n }\n\n const EmbeddedClass = embedded.type() as EntityConstructor;\n\n if (getSeeds(EmbeddedClass).length > 0) {\n record[embedded.propertyName] = await createOneSeed(EmbeddedClass, context);\n seededProperties.add(embedded.propertyName);\n }\n }\n\n // Step 3: Auto-seed @Seed entries without a factory (relation seeds).\n // Uses the ancestor guard to cut circular chains: if the related class is\n // already being seeded higher up in this call chain, the property is left\n // undefined rather than triggering infinite recursion.\n // Skipped entirely when context.relations === false.\n if (context.relations === false) {\n return instance;\n }\n\n for (const { propertyKey, factory, options } of getSeeds(EntityClass)) {\n if (factory || seededProperties.has(propertyKey)) {\n continue;\n }\n\n const relation = relations.find((r) => r.propertyName === String(propertyKey));\n\n if (!relation || typeof relation.type !== 'function') {\n continue;\n }\n\n const RelatedClass = (relation.type as () => Function)() as EntityConstructor;\n\n if (ancestors.has(RelatedClass)) {\n continue;\n }\n\n const isArray =\n relation.relationType === 'one-to-many' || relation.relationType === 'many-to-many';\n\n if (isArray) {\n record[propertyKey] = await createManySeed(RelatedClass, {\n count: options.count ?? 1,\n ...childContext,\n });\n } else {\n record[propertyKey] = await createOneSeed(RelatedClass, childContext);\n }\n\n seededProperties.add(propertyKey);\n }\n\n return instance;\n}\n\n/**\n * Creates one entity instance in memory without persisting it.\n *\n * When passed an array of classes, relation seeding is disabled by default\n * (pass `relations: true` in the context to override). Returns a tuple of\n * instances in the same order as the input array.\n */\nexport async function createSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context?: SeedContext,\n): Promise<T>;\nexport async function createSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n context?: SeedContext,\n): Promise<MapToInstances<T>>;\nexport async function createSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n context: SeedContext = {},\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => createOneSeed(cls, effectiveContext)),\n )) as EntityInstance[];\n }\n\n const [entity] = await createManySeed(classOrClasses as EntityConstructor<T>, {\n count: 1,\n ...context,\n });\n\n return entity!;\n}\n\n/**\n * Creates multiple entity instances in memory without persisting them.\n *\n * When passed an array of classes, returns a tuple of arrays — one per class — each\n * containing `count` instances. Relation seeding is disabled by default for the\n * array variant; pass `relations: true` in the options to override.\n */\nexport async function createManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: CreateManySeedOptions,\n): Promise<T[]>;\nexport async function createManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: CreateManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function createManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n { count, ...context }: CreateManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n Promise.all(Array.from({ length: count }, () => createOneSeed(cls, effectiveContext))),\n ),\n )) as EntityInstance[][];\n }\n\n return await Promise.all(\n Array.from({ length: count }, () =>\n createOneSeed(classOrClasses as EntityConstructor<T>, context),\n ),\n );\n}\n","import { type DataSource } from 'typeorm';\n\nimport { createManySeed } from './creator.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link saveSeed}. Extends {@link SeedContext} with a required DataSource. */\nexport interface SaveSeedOptions extends SeedContext {\n dataSource: DataSource;\n}\n\n/** Options for {@link saveManySeed}. Extends {@link SaveSeedOptions} with a required instance count. */\nexport interface SaveManySeedOptions extends SaveSeedOptions {\n count: number;\n}\n\ntype RelationMetadata = DataSource extends { getMetadata(...args: never[]): infer M }\n ? M extends { relations: Array<infer R> }\n ? R\n : never\n : never;\n\ninterface CascadeState {\n relation: RelationMetadata;\n original: boolean;\n}\n\n/**\n * Walks an entity object graph and collects every unique entity class encountered.\n * Used to discover all entity classes that need cascade-insert temporarily enabled\n * before saving so that the full in-memory graph is persisted in one shot.\n */\nfunction collectEntityClasses(entity: EntityInstance, visited = new Set<Function>()): Function[] {\n const EntityClass = entity.constructor as Function;\n\n if (visited.has(EntityClass)) {\n return [];\n }\n\n visited.add(EntityClass);\n\n const classes: Function[] = [EntityClass];\n\n for (const value of Object.values(entity)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object' && item.constructor !== Object) {\n classes.push(...collectEntityClasses(item, visited));\n }\n }\n } else if (value && typeof value === 'object' && value.constructor !== Object) {\n classes.push(...collectEntityClasses(value as EntityInstance, visited));\n }\n }\n\n return classes;\n}\n\n/**\n * Temporarily enables `isCascadeInsert` on every TypeORM relation for the given class.\n * Returns the previous flag values so they can be restored after saving.\n *\n * This is necessary because the seeder builds the full object graph in memory before\n * calling `save()`. Without cascade inserts, TypeORM would only persist the root entity\n * and ignore any nested relations that weren't already configured with `cascade: true`.\n *\n * Classes not registered as TypeORM entities (e.g. embedded value objects) are silently skipped.\n */\nfunction enableCascadeInsert(EntityClass: Function, dataSource: DataSource): CascadeState[] {\n const states: CascadeState[] = [];\n\n try {\n const relations = dataSource.getMetadata(EntityClass).relations;\n\n for (const relation of relations) {\n states.push({ relation, original: relation.isCascadeInsert });\n relation.isCascadeInsert = true;\n }\n } catch {\n // Class is not registered as an entity with this DataSource (e.g. embedded class).\n }\n\n return states;\n}\n\n/**\n * Restores `isCascadeInsert` flags to their original values.\n * Always called in a `finally` block to guarantee cleanup even when saving throws.\n */\nfunction restoreCascade(states: CascadeState[]): void {\n for (const { relation, original } of states) {\n relation.isCascadeInsert = original;\n }\n}\n\n/**\n * Creates and persists a seed entity and all its seeded relations.\n * Delegates to {@link saveManySeed} with `count: 1` and unwraps the result.\n */\nexport async function saveSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveSeedOptions,\n): Promise<T>;\n/**\n * Creates and persists one instance of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveSeedOptions,\n): Promise<MapToInstances<T>>;\nexport async function saveSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveSeedOptions,\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options, count: 1 };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n saveManySeed(cls, effectiveOptions).then(([entity]) => entity!),\n ),\n )) as EntityInstance[];\n }\n\n const [entity] = await saveManySeed(classOrClasses as EntityConstructor<T>, {\n ...options,\n count: 1,\n });\n\n return entity!;\n}\n\n/**\n * Creates and persists multiple seed entities of the same class.\n * Applies the same logic as {@link saveSeed} for each entity.\n */\nexport async function saveManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]>;\n/**\n * Creates and persists multiple instances of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function saveManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => saveManySeedOne(cls, effectiveOptions)),\n )) as EntityInstance[][];\n }\n\n return await saveManySeedOne(classOrClasses as EntityConstructor<T>, options);\n}\n\n/**\n * Creates and persists `count` instances of a single entity class.\n * Enables cascade inserts on every entity class in the object graph before saving,\n * then restores the original flags — regardless of whether the save succeeds or fails.\n */\nasync function saveManySeedOne<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]> {\n const { count, dataSource } = options;\n\n if (count === 0) {\n return [];\n }\n\n const entities = await createManySeed(EntityClass, options);\n\n const visited = new Set<Function>();\n const states = entities\n .flatMap((entity) => collectEntityClasses(entity, visited))\n .flatMap((cls) => enableCascadeInsert(cls, dataSource));\n\n try {\n return (await dataSource.getRepository(EntityClass).save(entities)) as T[];\n } finally {\n restoreCascade(states);\n }\n}\n","import { createManySeed, createSeed } from './creator.js';\nimport { saveManySeed, saveSeed } from './persist.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\nimport type { SaveSeedOptions } from './persist.js';\n\n/** Seed builder for a single entity class. Returned by {@link seed} when passed one class. */\ninterface SingleSeed<T extends EntityInstance> {\n /** Creates a single instance in memory without persisting. */\n create(context?: SeedContext): Promise<T>;\n /** Creates and persists a single instance. */\n save(options: SaveSeedOptions): Promise<T>;\n /** Creates multiple instances in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<T[]>;\n /** Creates and persists multiple instances. */\n saveMany(count: number, options: SaveSeedOptions): Promise<T[]>;\n}\n\n/**\n * Seed builder for multiple entity classes. Returned by {@link seed} when passed an array.\n * Each method returns a tuple of instances in the same order as the input array.\n * Relation seeding is disabled by default; pass `relations: true` in the context to enable it.\n */\ninterface MultiSeed<T extends readonly EntityConstructor[]> {\n /** Creates one instance of each class in memory without persisting. */\n create(context?: SeedContext): Promise<MapToInstances<T>>;\n /** Creates and persists one instance of each class. */\n save(options: SaveSeedOptions): Promise<MapToInstances<T>>;\n /** Creates `count` instances of each class in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<MapToInstanceArrays<T>>;\n /** Creates and persists `count` instances of each class. */\n saveMany(count: number, options: SaveSeedOptions): Promise<MapToInstanceArrays<T>>;\n}\n\n/**\n * Entry point for creating and persisting seed data.\n *\n * Pass a single entity class to get a {@link SingleSeed} builder, or an array of classes\n * to get a {@link MultiSeed} builder that operates on all of them at once.\n *\n * @example\n * // Create one Author in memory (no DB)\n * const author = await seed(Author).create()\n *\n * @example\n * // Persist one Author with all its seeded relations\n * const author = await seed(Author).save({ dataSource })\n *\n * @example\n * // Persist 10 Authors\n * const authors = await seed(Author).saveMany(10, { dataSource })\n *\n * @example\n * // Create multiple entity classes at once (relations disabled by default)\n * const [user, post] = await seed([User, Post]).create()\n */\nexport function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;\nexport function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;\nexport function seed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n): SingleSeed<T> | MultiSeed<readonly EntityConstructor[]> {\n if (Array.isArray(classOrClasses)) {\n const classes = classOrClasses as readonly EntityConstructor[];\n\n return {\n create: (context?: SeedContext) =>\n createSeed(classes as [...typeof classes], context) as Promise<\n MapToInstances<typeof classes>\n >,\n save: (options: SaveSeedOptions) =>\n saveSeed(classes as [...typeof classes], options) as Promise<\n MapToInstances<typeof classes>\n >,\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(classes as [...typeof classes], { count, ...context }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(classes as [...typeof classes], { count, ...options }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n };\n }\n\n const EntityClass = classOrClasses as EntityConstructor<T>;\n\n return {\n create: (context?: SeedContext) => createSeed(EntityClass, context),\n save: (options: SaveSeedOptions) => saveSeed(EntityClass, options),\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(EntityClass, { count, ...context }),\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(EntityClass, { count, ...options }),\n };\n}\n","interface SeederMeta {\n dependencies: Function[];\n}\n\nconst registry = new WeakMap<Function, SeederMeta>();\n\n/** Registers seeder metadata for the given class constructor. Called internally by the `@Seeder` decorator. */\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\n/** Returns the metadata registered for the given seeder class, or `undefined` if not registered. */\nexport function getSeederMeta(target: Function): SeederMeta | undefined {\n return registry.get(target);\n}\n","import { registerSeeder } from './registry.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/**\n * Interface that seeder classes must implement.\n *\n * The `run` method receives the seed context (which includes the DataSource when\n * called via `runSeeders`) and performs the seeding logic — typically by calling\n * `seed().save()` or other seeding utilities.\n */\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\n/** Configuration options for the {@link Seeder} decorator. */\nexport interface SeederOptions {\n /**\n * Seeder classes that must complete before this one runs.\n * Resolved transitively — dependencies of dependencies are included automatically.\n * {@link runSeeders} topologically sorts the full set and detects circular dependencies.\n */\n dependencies?: (new () => SeederInterface)[];\n}\n\n/**\n * Marks a class as a seeder and registers its dependency metadata.\n *\n * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves\n * all transitive dependencies, sorts them topologically, and executes them in order.\n *\n * @example\n * @Seeder({ dependencies: [UserSeeder] })\n * class PostSeeder implements SeederInterface {\n * async run(ctx: SeedContext) {\n * await seed(Post).saveMany(50, ctx)\n * }\n * }\n */\nexport function Seeder(options: SeederOptions = {}): ClassDecorator {\n return (target) => {\n registerSeeder(target, { dependencies: options.dependencies ?? [] });\n };\n}\n","import { DepGraph } from 'dependency-graph';\nimport { getSeederMeta } from './registry.js';\nimport type { SeederInterface } from './decorator.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/** Constructor type for a class decorated with `@Seeder`. */\nexport type SeederCtor = new () => SeederInterface;\n\n/** Options for {@link runSeeders}. Extends {@link SeedContext} with lifecycle hooks and logging control. */\nexport interface RunSeedersOptions extends SeedContext {\n /**\n * Enable console logging for each seeder. Set to `false` to silence output,\n * e.g. when using callbacks to handle logging yourself.\n *\n * @default true\n */\n logging?: boolean;\n /** Called before each seeder runs, in execution order. */\n onBefore?: (seeder: SeederCtor) => void | Promise<void>;\n /** Called after each seeder completes successfully, with the time it took in milliseconds. */\n onAfter?: (seeder: SeederCtor, durationMs: number) => void | Promise<void>;\n /** Called when a seeder throws. The error is re-thrown after this callback returns. */\n onError?: (seeder: SeederCtor, error: unknown) => void | Promise<void>;\n /** Called for each seeder before it runs. Return `true` to skip it entirely. */\n skip?: (seeder: SeederCtor) => boolean | Promise<boolean>;\n}\n\n/**\n * Topologically sorts the given seeders and all their transitive dependencies.\n * BFS walks from the roots to collect all nodes, then dependency edges are wired and\n * the graph is sorted so that every dependency precedes the seeders that depend on it.\n * Throws a descriptive error if a circular dependency is detected.\n */\nfunction topoSort(roots: SeederCtor[]): SeederCtor[] {\n const graph = new DepGraph<SeederCtor>();\n const byName = new Map<string, SeederCtor>();\n\n // Collect all nodes transitively via BFS and register them in the graph.\n const visited = new Set<SeederCtor>();\n const queue: SeederCtor[] = [...roots];\n\n while (queue.length > 0) {\n const node = queue.shift()!;\n\n if (visited.has(node)) {\n continue;\n }\n\n visited.add(node);\n graph.addNode(node.name, node);\n byName.set(node.name, node);\n\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n queue.push(dep);\n }\n }\n\n // Wire up the dependency edges.\n for (const node of visited) {\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n graph.addDependency(node.name, dep.name);\n }\n }\n\n try {\n return graph.overallOrder().map((name) => byName.get(name)!);\n } catch (err) {\n if (err && typeof err === 'object' && 'cyclePath' in err) {\n const path = (err as { cyclePath: string[] }).cyclePath.join(' → ');\n throw new Error(`Circular dependency detected among seeders: ${path}`);\n }\n\n throw err;\n }\n}\n\n/**\n * Runs the given seeders (and all their transitive dependencies) in dependency order.\n *\n * Each seeder is instantiated, its `run` method is called with the context derived\n * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called\n * around it. Errors are re-thrown after `onError` returns.\n *\n * @example\n * await runSeeders([PostSeeder], { dataSource })\n *\n * @example\n * // With lifecycle hooks and no console output\n * await runSeeders([PostSeeder], {\n * dataSource,\n * logging: false,\n * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),\n * })\n */\nexport async function runSeeders(\n seeders: SeederCtor[],\n options: RunSeedersOptions = {},\n): Promise<void> {\n const { logging = true, onBefore, onAfter, onError, skip, ...context } = options;\n\n for (const SeederClass of topoSort(seeders)) {\n if (await skip?.(SeederClass)) {\n continue;\n }\n\n if (logging) {\n console.log(`[${SeederClass.name}] Starting...`);\n }\n\n await onBefore?.(SeederClass);\n\n const start = Date.now();\n\n try {\n await new SeederClass().run(context);\n } catch (err) {\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.error(`[${SeederClass.name}] Failed after ${durationMs}ms`);\n }\n\n await onError?.(SeederClass, err);\n throw err;\n }\n\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.log(`[${SeederClass.name}] Done in ${durationMs}ms`);\n }\n\n await onAfter?.(SeederClass, durationMs);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["registry","DepGraph"],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/creator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seeder/registry.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"sourcesContent":["import type { DataSource } from 'typeorm';\n\n/** An entity instance — any class-based object managed by TypeORM. */\nexport type EntityInstance = object;\n\n/** A constructor that produces an entity instance. */\nexport type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;\n\n/** Context passed through a seed operation. Available inside factory callbacks and `SeederInterface.run`. */\nexport interface SeedContext {\n /**\n * The TypeORM DataSource. Automatically set by `save`/`saveMany` calls.\n * Also available in factory callbacks — useful for looking up existing\n * entities instead of creating new ones:\n *\n * @example\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\n dataSource?: DataSource;\n /**\n * Set to `false` to skip automatic relation seeding. Scalar and embedded\n * properties are still seeded; only relation properties decorated with a\n * bare `@Seed()` are skipped. Useful when you want to create flat entities\n * and wire relations yourself.\n *\n * @default true\n */\n relations?: boolean;\n}\n\n/**\n * Factory callback passed to `@Seed`. Receives the seed context and the partially built entity.\n *\n * Properties are seeded sequentially in declaration order, so any property declared above the\n * current one is already set on `self` and can be read to derive the current value.\n *\n * Annotate `self` with the entity class to get full type inference — TypeScript infers\n * `TEntity` from the annotation, so no cast is needed:\n *\n * @example\n * @Seed(() => faker.date.past())\n * beginDate!: Date\n *\n * @Seed((_, self: MyEntity) => faker.date.future({ refDate: self.beginDate }))\n * endDate!: Date\n */\nexport type SeedFactory<T = unknown, TEntity = any> = (\n context: SeedContext,\n self: TEntity,\n) => T | Promise<T>;\n\n/** Options for the `@Seed` decorator. */\nexport interface SeedOptions {\n /**\n * Number of related entities to create. Only meaningful on one-to-many and\n * many-to-many relation properties. Ignored on scalar and single-entity relations.\n */\n count?: number;\n}\n\nexport interface SeedEntry {\n propertyKey: string | symbol;\n /** Undefined when @Seed is used without a factory (i.e. bare relation seed). */\n factory: SeedFactory | undefined;\n options: SeedOptions;\n}\n\nexport type MapToInstances<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I : never;\n};\n\nexport type MapToInstanceArrays<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never;\n};\n\n// Keyed by the entity class constructor.\nconst registry = new Map<Function, SeedEntry[]>();\n\n/** Registers a seed entry for the given class constructor. Called internally by the `@Seed` decorator. */\nexport function registerSeed(target: Function, entry: SeedEntry): void {\n const entries = registry.get(target) ?? [];\n\n entries.push(entry);\n registry.set(target, entries);\n}\n\n/**\n * Returns all seed entries for the given class, including those inherited from\n * parent classes. Parent entries come first, preserving declaration order.\n */\nexport function getSeeds(target: Function): SeedEntry[] {\n const entries: SeedEntry[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n const own = registry.get(current);\n\n if (own) {\n entries.unshift(...own);\n }\n\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return entries;\n}\n","import { registerSeed } from './registry.js';\nimport type { SeedFactory, SeedOptions } from './registry.js';\n\n/**\n * Marks a relation property for auto-seeding.\n *\n * The related entity class is inferred from TypeORM metadata. One instance is created\n * and recursively seeded (including its own `@Seed` properties).\n *\n * Circular back-references are broken automatically: if the related class is already\n * being seeded higher up in the same call chain, the property is left `undefined`.\n * TypeORM treats `undefined` as \"don't touch this column\" rather than setting it to null.\n */\nexport function Seed(): PropertyDecorator;\n/**\n * Marks a relation property for auto-seeding with options.\n *\n * Use `count` on one-to-many and many-to-many properties to control how many\n * related entities are created. Ignored for one-to-one and many-to-one.\n *\n * @example\n * @Seed({ count: 3 })\n * @OneToMany(() => Book, (b) => b.author)\n * books!: Book[]\n */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/**\n * Marks a property with a factory callback.\n *\n * The factory receives the current {@link SeedContext} and can return any value,\n * including a `Promise`. Use this for scalar properties or when you need full\n * control over how a related entity is resolved.\n *\n * @example\n * @Seed(() => faker.internet.email())\n * email!: string\n *\n * @example\n * // Look up an existing entity instead of creating a new one\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\nexport function Seed<TEntity = any>(factory: SeedFactory<unknown, TEntity>): PropertyDecorator;\n/** Marks a property with a factory callback and additional options. */\nexport function Seed<TEntity = any>(\n factory: SeedFactory<unknown, TEntity>,\n options: SeedOptions,\n): PropertyDecorator;\nexport function Seed(\n factoryOrOptions?: SeedFactory | SeedOptions,\n options?: SeedOptions,\n): PropertyDecorator {\n const factory = typeof factoryOrOptions === 'function' ? factoryOrOptions : undefined;\n const opts: SeedOptions =\n (typeof factoryOrOptions === 'object' ? factoryOrOptions : options) ?? {};\n\n return (target, propertyKey) => {\n registerSeed(target.constructor as Function, { propertyKey, factory, options: opts });\n };\n}\n","import { getMetadataArgsStorage } from 'typeorm';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n SeedFactory,\n} from './registry.js';\nimport { getSeeds } from './registry.js';\n\n/**\n * A map of property overrides for seeded entities.\n * Each property can be either a static value or a {@link SeedFactory} that is called\n * once per entity — enabling unique random values across each created instance.\n *\n * @example\n * // All 10 bookings get a unique random price\n * await seed(Booking).saveMany(10, {\n * dataSource,\n * values: { price: () => faker.number.float({ min: 10, max: 500 }) },\n * })\n */\nexport type SeedValues<T extends EntityInstance> = {\n [K in keyof T]?: T[K] | SeedFactory<T[K], T>;\n};\n\n/**\n * Options for {@link create} and {@link createMany} on the single-class form.\n * Extends {@link SeedContext} with a typed `values` override map.\n */\nexport interface CreateOptions<T extends EntityInstance> extends SeedContext {\n /**\n * Property values to apply after all `@Seed` factories have run.\n * Wins unconditionally — factories still execute but their output is overwritten.\n * Also works for properties that have no `@Seed` decorator.\n *\n * @example\n * const user = await dataSource.getRepository(User).findOneByOrFail({ name: 'Alice' })\n * const post = await seed(Post).create({ values: { author: user } })\n */\n values?: SeedValues<T>;\n}\n\n/** Options for {@link createMany}. Extends {@link SeedContext} with a required instance count. */\nexport interface CreateManyOptions<T extends EntityInstance = EntityInstance> extends SeedContext {\n count: number;\n values?: SeedValues<T>;\n}\n\n// Internal extension of SeedContext — never exposed in the public API.\ninterface InternalContext extends SeedContext {\n _ancestors: Set<Function>;\n}\n\n/** Extracts the ancestor set from an internal context, returning an empty set for external callers. */\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\n/**\n * Applies a {@link SeedValues} map to an instance.\n * Factory entries are called once per instance so each entity can get unique values.\n */\nasync function applyValues<T extends EntityInstance>(\n instance: T,\n values: SeedValues<T>,\n context: SeedContext,\n): Promise<void> {\n const record = instance as Record<string | symbol, unknown>;\n\n for (const key of Object.keys(values) as (keyof T & string)[]) {\n const value = values[key];\n\n if (typeof value === 'function') {\n record[key] = await (value as SeedFactory)(context, instance);\n } else {\n record[key] = value;\n }\n }\n}\n\n/** Returns a new context with `cls` added to the ancestor set, used to detect circular relation chains. */\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\n/** Walks the prototype chain and returns all classes from `target` up to (but not including) `Function.prototype`. */\nfunction getClassHierarchy(target: Function): Function[] {\n const hierarchy: Function[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n hierarchy.push(current);\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return hierarchy;\n}\n\n/**\n * Creates one fully populated instance of `EntityClass` in memory.\n *\n * Runs in three steps:\n * 1. Factory-decorated properties (`@Seed(factory)`) — run first, in declaration order.\n * 2. Embedded types (`@Embedded`) — auto-seeded if the embedded class has any `@Seed` entries.\n * 3. Bare relation decorators (`@Seed()` without a factory) — skipped when `relations` is `false`,\n * and also skipped for any related class already present in the ancestor chain (circular guard).\n */\nasync function createOne<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context: SeedContext,\n): Promise<T> {\n const instance = new EntityClass();\n const ancestors = getAncestors(context);\n const childContext = withAncestor(context, EntityClass);\n const storage = getMetadataArgsStorage();\n const relations = storage.filterRelations(getClassHierarchy(EntityClass));\n const seededProperties = new Set<string | symbol>();\n const record = instance as Record<string | symbol, unknown>;\n\n // Step 1: Run @Seed entries that have an explicit factory.\n for (const { propertyKey, factory } of getSeeds(EntityClass)) {\n if (!factory) {\n continue;\n }\n\n record[propertyKey] = await factory(context, instance);\n seededProperties.add(propertyKey);\n }\n\n // Step 2: Auto-seed TypeORM embedded properties not already covered by Step 1.\n for (const embedded of storage.filterEmbeddeds(EntityClass)) {\n if (seededProperties.has(embedded.propertyName)) {\n continue;\n }\n\n const EmbeddedClass = embedded.type() as EntityConstructor;\n\n if (getSeeds(EmbeddedClass).length > 0) {\n record[embedded.propertyName] = await createOne(EmbeddedClass, context);\n seededProperties.add(embedded.propertyName);\n }\n }\n\n // Step 3: Auto-seed @Seed entries without a factory (relation seeds).\n // Uses the ancestor guard to cut circular chains: if the related class is\n // already being seeded higher up in this call chain, the property is left\n // undefined rather than triggering infinite recursion.\n // Skipped entirely when context.relations === false.\n if (context.relations === false) {\n return instance;\n }\n\n for (const { propertyKey, factory, options } of getSeeds(EntityClass)) {\n if (factory || seededProperties.has(propertyKey)) {\n continue;\n }\n\n const relation = relations.find((r) => r.propertyName === String(propertyKey));\n\n if (!relation || typeof relation.type !== 'function') {\n continue;\n }\n\n const RelatedClass = (relation.type as () => Function)() as EntityConstructor;\n\n if (ancestors.has(RelatedClass)) {\n continue;\n }\n\n const isArray =\n relation.relationType === 'one-to-many' || relation.relationType === 'many-to-many';\n\n if (isArray) {\n record[propertyKey] = await createMany(RelatedClass, {\n count: options.count ?? 1,\n ...childContext,\n });\n } else {\n record[propertyKey] = await createOne(RelatedClass, childContext);\n }\n\n seededProperties.add(propertyKey);\n }\n\n return instance;\n}\n\n/**\n * Creates one entity instance in memory without persisting it.\n *\n * When passed an array of classes, relation seeding is disabled by default\n * (pass `relations: true` in the context to override). Returns a tuple of\n * instances in the same order as the input array.\n */\nexport async function create<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options?: CreateOptions<T>,\n): Promise<T>;\nexport async function create<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n context?: SeedContext,\n): Promise<MapToInstances<T>>;\nexport async function create<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: CreateOptions<T> = {},\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...options };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => createOne(cls, effectiveContext)),\n )) as EntityInstance[];\n }\n\n const { values, ...context } = options as CreateOptions<T>;\n const instance = await createOne(classOrClasses as EntityConstructor<T>, context);\n\n if (values) {\n await applyValues(instance, values, context);\n }\n\n return instance;\n}\n\n/**\n * Creates multiple entity instances in memory without persisting them.\n *\n * When passed an array of classes, returns a tuple of arrays — one per class — each\n * containing `count` instances. Relation seeding is disabled by default for the\n * array variant; pass `relations: true` in the options to override.\n */\nexport async function createMany<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: CreateManyOptions<T>,\n): Promise<T[]>;\nexport async function createMany<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: CreateManyOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function createMany<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n { count, values, ...context }: CreateManyOptions<T>,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n Promise.all(Array.from({ length: count }, () => createOne(cls, effectiveContext))),\n ),\n )) as EntityInstance[][];\n }\n\n const instances = await Promise.all(\n Array.from({ length: count }, () => createOne(classOrClasses as EntityConstructor<T>, context)),\n );\n\n if (values) {\n await Promise.all(instances.map((instance) => applyValues(instance, values, context)));\n }\n\n return instances;\n}\n","import { type DataSource } from 'typeorm';\nimport { createMany } from './creator.js';\nimport type { SeedValues } from './creator.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link save}. Extends {@link SeedContext} with a required DataSource. */\nexport interface SaveOptions<T extends EntityInstance = EntityInstance> extends SeedContext {\n dataSource: DataSource;\n /**\n * Property values to apply to each entity after seeding and before persisting.\n * Wins unconditionally over `@Seed` factory output — the factory still runs,\n * but its result is overwritten. Also works for properties that have no `@Seed`\n * decorator at all.\n *\n * @example\n * const users = await dataSource.getRepository(User).find()\n * const user = faker.helpers.arrayElement(users)\n * await seed(Booking).saveMany(10, { dataSource, values: { user } })\n */\n values?: SeedValues<T>;\n}\n\n/** Options for {@link saveMany}. Extends {@link SaveOptions} with a required instance count. */\nexport interface SaveManyOptions<T extends EntityInstance = EntityInstance> extends SaveOptions<T> {\n count: number;\n}\n\ntype RelationMetadata = DataSource extends { getMetadata(...args: never[]): infer M }\n ? M extends { relations: Array<infer R> }\n ? R\n : never\n : never;\n\ninterface CascadeState {\n relation: RelationMetadata;\n original: boolean;\n}\n\n/**\n * Walks an entity object graph and collects every unique entity class encountered.\n * Used to discover all entity classes that need cascade-insert temporarily enabled\n * before saving so that the full in-memory graph is persisted in one shot.\n */\nfunction collectEntityClasses(entity: EntityInstance, visited = new Set<Function>()): Function[] {\n const EntityClass = entity.constructor as Function;\n\n if (visited.has(EntityClass)) {\n return [];\n }\n\n visited.add(EntityClass);\n\n const classes: Function[] = [EntityClass];\n\n for (const value of Object.values(entity)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object' && item.constructor !== Object) {\n classes.push(...collectEntityClasses(item, visited));\n }\n }\n } else if (value && typeof value === 'object' && value.constructor !== Object) {\n classes.push(...collectEntityClasses(value as EntityInstance, visited));\n }\n }\n\n return classes;\n}\n\n/**\n * Temporarily enables `isCascadeInsert` on every TypeORM relation for the given class.\n * Returns the previous flag values so they can be restored after saving.\n *\n * This is necessary because the seeder builds the full object graph in memory before\n * calling `save()`. Without cascade inserts, TypeORM would only persist the root entity\n * and ignore any nested relations that weren't already configured with `cascade: true`.\n *\n * Classes not registered as TypeORM entities (e.g. embedded value objects) are silently skipped.\n */\nfunction enableCascadeInsert(EntityClass: Function, dataSource: DataSource): CascadeState[] {\n const states: CascadeState[] = [];\n\n try {\n const relations = dataSource.getMetadata(EntityClass).relations;\n\n for (const relation of relations) {\n states.push({ relation, original: relation.isCascadeInsert });\n relation.isCascadeInsert = true;\n }\n } catch {\n // Class is not registered as an entity with this DataSource (e.g. embedded class).\n }\n\n return states;\n}\n\n/**\n * Restores `isCascadeInsert` flags to their original values.\n * Always called in a `finally` block to guarantee cleanup even when saving throws.\n */\nfunction restoreCascade(states: CascadeState[]): void {\n for (const { relation, original } of states) {\n relation.isCascadeInsert = original;\n }\n}\n\n/**\n * Creates and persists a seed entity and all its seeded relations.\n */\nexport async function save<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveOptions<T>,\n): Promise<T>;\n/**\n * Creates and persists one instance of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function save<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveOptions,\n): Promise<MapToInstances<T>>;\nexport async function save<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveOptions<T>,\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options, count: 1 };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n saveBatch(cls, effectiveOptions).then(([entity]) => entity!),\n ),\n )) as EntityInstance[];\n }\n\n const [entity] = await saveBatch(classOrClasses as EntityConstructor<T>, {\n ...options,\n count: 1,\n });\n\n return entity!;\n}\n\n/**\n * Creates and persists multiple seed entities of the same class.\n * Applies the same logic as {@link save} for each entity.\n */\nexport async function saveMany<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManyOptions<T>,\n): Promise<T[]>;\n/**\n * Creates and persists multiple instances of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveMany<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveManyOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function saveMany<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveManyOptions<T>,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => saveBatch(cls, effectiveOptions)),\n )) as EntityInstance[][];\n }\n\n return await saveBatch(classOrClasses as EntityConstructor<T>, options);\n}\n\n/**\n * Creates and persists `count` instances of a single entity class in one batched\n * `repository.save()` call. Batching is intentional — it is more efficient than\n * saving each instance individually, as TypeORM can consolidate the inserts.\n *\n * Enables cascade inserts on every entity class in the object graph before saving,\n * then restores the original flags — regardless of whether the save succeeds or fails.\n */\nasync function saveBatch<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManyOptions<T>,\n): Promise<T[]> {\n const { count, dataSource } = options;\n\n if (count === 0) {\n return [];\n }\n\n const entities = await createMany(EntityClass, options);\n\n const visited = new Set<Function>();\n const states = entities\n .flatMap((entity) => collectEntityClasses(entity, visited))\n .flatMap((cls) => enableCascadeInsert(cls, dataSource));\n\n try {\n return (await dataSource.getRepository(EntityClass).save(entities)) as T[];\n } finally {\n restoreCascade(states);\n }\n}\n","import type { CreateOptions } from './creator.js';\nimport { create, createMany } from './creator.js';\nimport type { SaveManyOptions, SaveOptions } from './persist.js';\nimport { save, saveMany } from './persist.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\nexport type { CreateOptions } from './creator.js';\n\n/** Seed builder for a single entity class. Returned by {@link seed} when passed one class. */\ninterface SingleSeed<T extends EntityInstance> {\n /** Creates a single instance in memory without persisting. */\n create(context?: CreateOptions<T>): Promise<T>;\n /** Creates and persists a single instance. */\n save(options: SaveOptions<T>): Promise<T>;\n /** Creates multiple instances in memory without persisting. */\n createMany(count: number, context?: CreateOptions<T>): Promise<T[]>;\n /** Creates and persists multiple instances. */\n saveMany(count: number, options: SaveOptions<T>): Promise<T[]>;\n}\n\n/**\n * Seed builder for multiple entity classes. Returned by {@link seed} when passed an array.\n * Each method returns a tuple of instances in the same order as the input array.\n * Relation seeding is disabled by default; pass `relations: true` in the context to enable it.\n */\ninterface MultiSeed<T extends readonly EntityConstructor[]> {\n /** Creates one instance of each class in memory without persisting. */\n create(context?: SeedContext): Promise<MapToInstances<T>>;\n /** Creates and persists one instance of each class. */\n save(options: SaveOptions): Promise<MapToInstances<T>>;\n /** Creates `count` instances of each class in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<MapToInstanceArrays<T>>;\n /** Creates and persists `count` instances of each class. */\n saveMany(count: number, options: SaveOptions): Promise<MapToInstanceArrays<T>>;\n}\n\n/**\n * Entry point for creating and persisting seed data.\n *\n * Pass a single entity class to get a {@link SingleSeed} builder, or an array of classes\n * to get a {@link MultiSeed} builder that operates on all of them at once.\n *\n * @example\n * // Create one Author in memory (no DB)\n * const author = await seed(Author).create()\n *\n * @example\n * // Persist one Author with all its seeded relations\n * const author = await seed(Author).save({ dataSource })\n *\n * @example\n * // Persist 10 Authors\n * const authors = await seed(Author).saveMany(10, { dataSource })\n *\n * @example\n * // Create multiple entity classes at once (relations disabled by default)\n * const [user, post] = await seed([User, Post]).create()\n */\nexport function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;\nexport function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;\nexport function seed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n): SingleSeed<T> | MultiSeed<readonly EntityConstructor[]> {\n if (Array.isArray(classOrClasses)) {\n const classes = classOrClasses as readonly EntityConstructor[];\n\n return {\n create: (context?: SeedContext) =>\n create(classes as [...typeof classes], context) as Promise<MapToInstances<typeof classes>>,\n save: (options: SaveOptions) =>\n save(classes as [...typeof classes], options) as Promise<MapToInstances<typeof classes>>,\n createMany: (count: number, context?: SeedContext) =>\n createMany(classes as [...typeof classes], { count, ...context }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n saveMany: (count: number, options: SaveOptions) =>\n saveMany(\n classes as [...typeof classes],\n { count, ...options } as SaveManyOptions,\n ) as Promise<MapToInstanceArrays<typeof classes>>,\n };\n }\n\n const EntityClass = classOrClasses as EntityConstructor<T>;\n\n return {\n create: (options?: CreateOptions<T>) => create(EntityClass, options),\n save: (options: SaveOptions<T>) => save(EntityClass, options),\n createMany: (count: number, options?: CreateOptions<T>) =>\n createMany(EntityClass, { count, ...options }),\n saveMany: (count: number, options: SaveOptions<T>) =>\n saveMany(EntityClass, { count, ...options }),\n };\n}\n","interface SeederMeta {\n dependencies: Function[];\n}\n\nconst registry = new WeakMap<Function, SeederMeta>();\n\n/** Registers seeder metadata for the given class constructor. Called internally by the `@Seeder` decorator. */\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\n/** Returns the metadata registered for the given seeder class, or `undefined` if not registered. */\nexport function getSeederMeta(target: Function): SeederMeta | undefined {\n return registry.get(target);\n}\n","import { registerSeeder } from './registry.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/**\n * Interface that seeder classes must implement.\n *\n * The `run` method receives the seed context (which includes the DataSource when\n * called via `runSeeders`) and performs the seeding logic — typically by calling\n * `seed().save()` or other seeding utilities.\n */\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\n/** Configuration options for the {@link Seeder} decorator. */\nexport interface SeederOptions {\n /**\n * Seeder classes that must complete before this one runs.\n * Resolved transitively — dependencies of dependencies are included automatically.\n * {@link runSeeders} topologically sorts the full set and detects circular dependencies.\n */\n dependencies?: (new () => SeederInterface)[];\n}\n\n/**\n * Marks a class as a seeder and registers its dependency metadata.\n *\n * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves\n * all transitive dependencies, sorts them topologically, and executes them in order.\n *\n * @example\n * @Seeder({ dependencies: [UserSeeder] })\n * class PostSeeder implements SeederInterface {\n * async run(ctx: SeedContext) {\n * await seed(Post).saveMany(50, ctx)\n * }\n * }\n */\nexport function Seeder(options: SeederOptions = {}): ClassDecorator {\n return (target) => {\n registerSeeder(target, { dependencies: options.dependencies ?? [] });\n };\n}\n","import { DepGraph } from 'dependency-graph';\nimport { getSeederMeta } from './registry.js';\nimport type { SeederInterface } from './decorator.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/** Constructor type for a class decorated with `@Seeder`. */\nexport type SeederCtor = new () => SeederInterface;\n\n/** Options for {@link runSeeders}. Extends {@link SeedContext} with lifecycle hooks and logging control. */\nexport interface RunSeedersOptions extends SeedContext {\n /**\n * Enable console logging for each seeder. Set to `false` to silence output,\n * e.g. when using callbacks to handle logging yourself.\n *\n * @default true\n */\n logging?: boolean;\n /** Called before each seeder runs, in execution order. */\n onBefore?: (seeder: SeederCtor) => void | Promise<void>;\n /** Called after each seeder completes successfully, with the time it took in milliseconds. */\n onAfter?: (seeder: SeederCtor, durationMs: number) => void | Promise<void>;\n /** Called when a seeder throws. The error is re-thrown after this callback returns. */\n onError?: (seeder: SeederCtor, error: unknown) => void | Promise<void>;\n /** Called for each seeder before it runs. Return `true` to skip it entirely. */\n skip?: (seeder: SeederCtor) => boolean | Promise<boolean>;\n}\n\n/**\n * Topologically sorts the given seeders and all their transitive dependencies.\n * BFS walks from the roots to collect all nodes, then dependency edges are wired and\n * the graph is sorted so that every dependency precedes the seeders that depend on it.\n * Throws a descriptive error if a circular dependency is detected.\n */\nfunction topoSort(roots: SeederCtor[]): SeederCtor[] {\n const graph = new DepGraph<SeederCtor>();\n const byName = new Map<string, SeederCtor>();\n\n // Collect all nodes transitively via BFS and register them in the graph.\n const visited = new Set<SeederCtor>();\n const queue: SeederCtor[] = [...roots];\n\n while (queue.length > 0) {\n const node = queue.shift()!;\n\n if (visited.has(node)) {\n continue;\n }\n\n visited.add(node);\n graph.addNode(node.name, node);\n byName.set(node.name, node);\n\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n queue.push(dep);\n }\n }\n\n // Wire up the dependency edges.\n for (const node of visited) {\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n graph.addDependency(node.name, dep.name);\n }\n }\n\n try {\n return graph.overallOrder().map((name) => byName.get(name)!);\n } catch (err) {\n if (err && typeof err === 'object' && 'cyclePath' in err) {\n const path = (err as { cyclePath: string[] }).cyclePath.join(' → ');\n throw new Error(`Circular dependency detected among seeders: ${path}`);\n }\n\n throw err;\n }\n}\n\n/**\n * Runs the given seeders (and all their transitive dependencies) in dependency order.\n *\n * Each seeder is instantiated, its `run` method is called with the context derived\n * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called\n * around it. Errors are re-thrown after `onError` returns.\n *\n * @example\n * await runSeeders([PostSeeder], { dataSource })\n *\n * @example\n * // With lifecycle hooks and no console output\n * await runSeeders([PostSeeder], {\n * dataSource,\n * logging: false,\n * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),\n * })\n */\nexport async function runSeeders(\n seeders: SeederCtor[],\n options: RunSeedersOptions = {},\n): Promise<void> {\n const { logging = true, onBefore, onAfter, onError, skip, ...context } = options;\n\n for (const SeederClass of topoSort(seeders)) {\n if (await skip?.(SeederClass)) {\n continue;\n }\n\n if (logging) {\n console.log(`[${SeederClass.name}] Starting...`);\n }\n\n await onBefore?.(SeederClass);\n\n const start = Date.now();\n\n try {\n await new SeederClass().run(context);\n } catch (err) {\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.error(`[${SeederClass.name}] Failed after ${durationMs}ms`);\n }\n\n await onError?.(SeederClass, err);\n throw err;\n }\n\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.log(`[${SeederClass.name}] Done in ${durationMs}ms`);\n }\n\n await onAfter?.(SeederClass, durationMs);\n }\n}\n"],"mappings":";;;;AA6EA,MAAMA,6BAAW,IAAI,KAA4B;;AAGjD,SAAgB,aAAa,QAAkB,OAAwB;CACrE,MAAM,UAAUA,WAAS,IAAI,OAAO,IAAI,EAAE;AAE1C,SAAQ,KAAK,MAAM;AACnB,YAAS,IAAI,QAAQ,QAAQ;;;;;;AAO/B,SAAgB,SAAS,QAA+B;CACtD,MAAM,UAAuB,EAAE;CAC/B,IAAI,UAAoB;AAExB,QAAO,WAAW,YAAY,SAAS,WAAW;EAChD,MAAM,MAAMA,WAAS,IAAI,QAAQ;AAEjC,MAAI,IACF,SAAQ,QAAQ,GAAG,IAAI;AAGzB,YAAU,OAAO,eAAe,QAAQ;;AAG1C,QAAO;;;;ACzDT,SAAgB,KACd,kBACA,SACmB;CACnB,MAAM,UAAU,OAAO,qBAAqB,aAAa,mBAAmB,KAAA;CAC5E,MAAM,QACH,OAAO,qBAAqB,WAAW,mBAAmB,YAAY,EAAE;AAE3E,SAAQ,QAAQ,gBAAgB;AAC9B,eAAa,OAAO,aAAyB;GAAE;GAAa;GAAS,SAAS;GAAM,CAAC;;;;;;ACDzF,SAAS,aAAa,SAAqC;AACzD,QAAQ,QAA4B,8BAAc,IAAI,KAAK;;;;;;AAO7D,eAAe,YACb,UACA,QACA,SACe;CACf,MAAM,SAAS;AAEf,MAAK,MAAM,OAAO,OAAO,KAAK,OAAO,EAA0B;EAC7D,MAAM,QAAQ,OAAO;AAErB,MAAI,OAAO,UAAU,WACnB,QAAO,OAAO,MAAO,MAAsB,SAAS,SAAS;MAE7D,QAAO,OAAO;;;;AAMpB,SAAS,aAAa,SAAsB,KAAgC;CAC1E,MAAM,YAAY,aAAa,QAAQ;AAEvC,QAAO;EAAE,GAAG;EAAS,YAAY,IAAI,IAAI,CAAC,GAAG,WAAW,IAAI,CAAC;EAAE;;;AAIjE,SAAS,kBAAkB,QAA8B;CACvD,MAAM,YAAwB,EAAE;CAChC,IAAI,UAAoB;AAExB,QAAO,WAAW,YAAY,SAAS,WAAW;AAChD,YAAU,KAAK,QAAQ;AACvB,YAAU,OAAO,eAAe,QAAQ;;AAG1C,QAAO;;;;;;;;;;;AAYT,eAAe,UACb,aACA,SACY;CACZ,MAAM,WAAW,IAAI,aAAa;CAClC,MAAM,YAAY,aAAa,QAAQ;CACvC,MAAM,eAAe,aAAa,SAAS,YAAY;CACvD,MAAM,WAAA,GAAA,QAAA,yBAAkC;CACxC,MAAM,YAAY,QAAQ,gBAAgB,kBAAkB,YAAY,CAAC;CACzE,MAAM,mCAAmB,IAAI,KAAsB;CACnD,MAAM,SAAS;AAGf,MAAK,MAAM,EAAE,aAAa,aAAa,SAAS,YAAY,EAAE;AAC5D,MAAI,CAAC,QACH;AAGF,SAAO,eAAe,MAAM,QAAQ,SAAS,SAAS;AACtD,mBAAiB,IAAI,YAAY;;AAInC,MAAK,MAAM,YAAY,QAAQ,gBAAgB,YAAY,EAAE;AAC3D,MAAI,iBAAiB,IAAI,SAAS,aAAa,CAC7C;EAGF,MAAM,gBAAgB,SAAS,MAAM;AAErC,MAAI,SAAS,cAAc,CAAC,SAAS,GAAG;AACtC,UAAO,SAAS,gBAAgB,MAAM,UAAU,eAAe,QAAQ;AACvE,oBAAiB,IAAI,SAAS,aAAa;;;AAS/C,KAAI,QAAQ,cAAc,MACxB,QAAO;AAGT,MAAK,MAAM,EAAE,aAAa,SAAS,aAAa,SAAS,YAAY,EAAE;AACrE,MAAI,WAAW,iBAAiB,IAAI,YAAY,CAC9C;EAGF,MAAM,WAAW,UAAU,MAAM,MAAM,EAAE,iBAAiB,OAAO,YAAY,CAAC;AAE9E,MAAI,CAAC,YAAY,OAAO,SAAS,SAAS,WACxC;EAGF,MAAM,eAAgB,SAAS,MAAyB;AAExD,MAAI,UAAU,IAAI,aAAa,CAC7B;AAMF,MAFE,SAAS,iBAAiB,iBAAiB,SAAS,iBAAiB,eAGrE,QAAO,eAAe,MAAM,WAAW,cAAc;GACnD,OAAO,QAAQ,SAAS;GACxB,GAAG;GACJ,CAAC;MAEF,QAAO,eAAe,MAAM,UAAU,cAAc,aAAa;AAGnE,mBAAiB,IAAI,YAAY;;AAGnC,QAAO;;AAkBT,eAAsB,OACpB,gBACA,UAA4B,EAAE,EACC;AAC/B,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAgC;GAAE,WAAW;GAAO,GAAG;GAAS;AAEtE,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAAQ,UAAU,KAAK,iBAAiB,CAAC,CACvF;;CAGH,MAAM,EAAE,QAAQ,GAAG,YAAY;CAC/B,MAAM,WAAW,MAAM,UAAU,gBAAwC,QAAQ;AAEjF,KAAI,OACF,OAAM,YAAY,UAAU,QAAQ,QAAQ;AAG9C,QAAO;;AAkBT,eAAsB,WACpB,gBACA,EAAE,OAAO,QAAQ,GAAG,WACe;AACnC,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAgC;GAAE,WAAW;GAAO,GAAG;GAAS;AAEtE,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAC3C,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,OAAO,QAAQ,UAAU,KAAK,iBAAiB,CAAC,CAAC,CACnF,CACF;;CAGH,MAAM,YAAY,MAAM,QAAQ,IAC9B,MAAM,KAAK,EAAE,QAAQ,OAAO,QAAQ,UAAU,gBAAwC,QAAQ,CAAC,CAChG;AAED,KAAI,OACF,OAAM,QAAQ,IAAI,UAAU,KAAK,aAAa,YAAY,UAAU,QAAQ,QAAQ,CAAC,CAAC;AAGxF,QAAO;;;;;;;;;ACxNT,SAAS,qBAAqB,QAAwB,0BAAU,IAAI,KAAe,EAAc;CAC/F,MAAM,cAAc,OAAO;AAE3B,KAAI,QAAQ,IAAI,YAAY,CAC1B,QAAO,EAAE;AAGX,SAAQ,IAAI,YAAY;CAExB,MAAM,UAAsB,CAAC,YAAY;AAEzC,MAAK,MAAM,SAAS,OAAO,OAAO,OAAO,CACvC,KAAI,MAAM,QAAQ,MAAM;OACjB,MAAM,QAAQ,MACjB,KAAI,QAAQ,OAAO,SAAS,YAAY,KAAK,gBAAgB,OAC3D,SAAQ,KAAK,GAAG,qBAAqB,MAAM,QAAQ,CAAC;YAG/C,SAAS,OAAO,UAAU,YAAY,MAAM,gBAAgB,OACrE,SAAQ,KAAK,GAAG,qBAAqB,OAAyB,QAAQ,CAAC;AAI3E,QAAO;;;;;;;;;;;;AAaT,SAAS,oBAAoB,aAAuB,YAAwC;CAC1F,MAAM,SAAyB,EAAE;AAEjC,KAAI;EACF,MAAM,YAAY,WAAW,YAAY,YAAY,CAAC;AAEtD,OAAK,MAAM,YAAY,WAAW;AAChC,UAAO,KAAK;IAAE;IAAU,UAAU,SAAS;IAAiB,CAAC;AAC7D,YAAS,kBAAkB;;SAEvB;AAIR,QAAO;;;;;;AAOT,SAAS,eAAe,QAA8B;AACpD,MAAK,MAAM,EAAE,UAAU,cAAc,OACnC,UAAS,kBAAkB;;AAmB/B,eAAsB,KACpB,gBACA,SAC+B;AAC/B,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAmB;GAAE,WAAW;GAAO,GAAG;GAAS,OAAO;GAAG;AAEnE,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAC3C,UAAU,KAAK,iBAAiB,CAAC,MAAM,CAAC,YAAY,OAAQ,CAC7D,CACF;;CAGH,MAAM,CAAC,UAAU,MAAM,UAAU,gBAAwC;EACvE,GAAG;EACH,OAAO;EACR,CAAC;AAEF,QAAO;;AAmBT,eAAsB,SACpB,gBACA,SACmC;AACnC,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAmB;GAAE,WAAW;GAAO,GAAG;GAAS;AAEzD,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAAQ,UAAU,KAAK,iBAAiB,CAAC,CACvF;;AAGH,QAAO,MAAM,UAAU,gBAAwC,QAAQ;;;;;;;;;;AAWzE,eAAe,UACb,aACA,SACc;CACd,MAAM,EAAE,OAAO,eAAe;AAE9B,KAAI,UAAU,EACZ,QAAO,EAAE;CAGX,MAAM,WAAW,MAAM,WAAW,aAAa,QAAQ;CAEvD,MAAM,0BAAU,IAAI,KAAe;CACnC,MAAM,SAAS,SACZ,SAAS,WAAW,qBAAqB,QAAQ,QAAQ,CAAC,CAC1D,SAAS,QAAQ,oBAAoB,KAAK,WAAW,CAAC;AAEzD,KAAI;AACF,SAAQ,MAAM,WAAW,cAAc,YAAY,CAAC,KAAK,SAAS;WAC1D;AACR,iBAAe,OAAO;;;;;AC9I1B,SAAgB,KACd,gBACyD;AACzD,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,UAAU;AAEhB,SAAO;GACL,SAAS,YACP,OAAO,SAAgC,QAAQ;GACjD,OAAO,YACL,KAAK,SAAgC,QAAQ;GAC/C,aAAa,OAAe,YAC1B,WAAW,SAAgC;IAAE;IAAO,GAAG;IAAS,CAAC;GAGnE,WAAW,OAAe,YACxB,SACE,SACA;IAAE;IAAO,GAAG;IAAS,CACtB;GACJ;;CAGH,MAAM,cAAc;AAEpB,QAAO;EACL,SAAS,YAA+B,OAAO,aAAa,QAAQ;EACpE,OAAO,YAA4B,KAAK,aAAa,QAAQ;EAC7D,aAAa,OAAe,YAC1B,WAAW,aAAa;GAAE;GAAO,GAAG;GAAS,CAAC;EAChD,WAAW,OAAe,YACxB,SAAS,aAAa;GAAE;GAAO,GAAG;GAAS,CAAC;EAC/C;;;;AC9FH,MAAM,2BAAW,IAAI,SAA+B;;AAGpD,SAAgB,eAAe,QAAkB,MAAwB;AACvE,UAAS,IAAI,QAAQ,KAAK;;;AAI5B,SAAgB,cAAc,QAA0C;AACtE,QAAO,SAAS,IAAI,OAAO;;;;;;;;;;;;;;;;;;ACyB7B,SAAgB,OAAO,UAAyB,EAAE,EAAkB;AAClE,SAAQ,WAAW;AACjB,iBAAe,QAAQ,EAAE,cAAc,QAAQ,gBAAgB,EAAE,EAAE,CAAC;;;;;;;;;;;ACPxE,SAAS,SAAS,OAAmC;CACnD,MAAM,QAAQ,IAAIC,iBAAAA,UAAsB;CACxC,MAAM,yBAAS,IAAI,KAAyB;CAG5C,MAAM,0BAAU,IAAI,KAAiB;CACrC,MAAM,QAAsB,CAAC,GAAG,MAAM;AAEtC,QAAO,MAAM,SAAS,GAAG;EACvB,MAAM,OAAO,MAAM,OAAO;AAE1B,MAAI,QAAQ,IAAI,KAAK,CACnB;AAGF,UAAQ,IAAI,KAAK;AACjB,QAAM,QAAQ,KAAK,MAAM,KAAK;AAC9B,SAAO,IAAI,KAAK,MAAM,KAAK;AAE3B,OAAK,MAAM,OAAQ,cAAc,KAAK,EAAE,gBAAgB,EAAE,CACxD,OAAM,KAAK,IAAI;;AAKnB,MAAK,MAAM,QAAQ,QACjB,MAAK,MAAM,OAAQ,cAAc,KAAK,EAAE,gBAAgB,EAAE,CACxD,OAAM,cAAc,KAAK,MAAM,IAAI,KAAK;AAI5C,KAAI;AACF,SAAO,MAAM,cAAc,CAAC,KAAK,SAAS,OAAO,IAAI,KAAK,CAAE;UACrD,KAAK;AACZ,MAAI,OAAO,OAAO,QAAQ,YAAY,eAAe,KAAK;GACxD,MAAM,OAAQ,IAAgC,UAAU,KAAK,MAAM;AACnE,SAAM,IAAI,MAAM,+CAA+C,OAAO;;AAGxE,QAAM;;;;;;;;;;;;;;;;;;;;;AAsBV,eAAsB,WACpB,SACA,UAA6B,EAAE,EAChB;CACf,MAAM,EAAE,UAAU,MAAM,UAAU,SAAS,SAAS,MAAM,GAAG,YAAY;AAEzE,MAAK,MAAM,eAAe,SAAS,QAAQ,EAAE;AAC3C,MAAI,MAAM,OAAO,YAAY,CAC3B;AAGF,MAAI,QACF,SAAQ,IAAI,IAAI,YAAY,KAAK,eAAe;AAGlD,QAAM,WAAW,YAAY;EAE7B,MAAM,QAAQ,KAAK,KAAK;AAExB,MAAI;AACF,SAAM,IAAI,aAAa,CAAC,IAAI,QAAQ;WAC7B,KAAK;GACZ,MAAM,aAAa,KAAK,KAAK,GAAG;AAEhC,OAAI,QACF,SAAQ,MAAM,IAAI,YAAY,KAAK,iBAAiB,WAAW,IAAI;AAGrE,SAAM,UAAU,aAAa,IAAI;AACjC,SAAM;;EAGR,MAAM,aAAa,KAAK,KAAK,GAAG;AAEhC,MAAI,QACF,SAAQ,IAAI,IAAI,YAAY,KAAK,YAAY,WAAW,IAAI;AAG9D,QAAM,UAAU,aAAa,WAAW"}
|