@joakimbugge/typeorm-seeder 0.4.0 → 0.4.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 CHANGED
@@ -2,6 +2,21 @@
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
+ Coded by AI. Reviewed by humans.
6
+
7
+ ---
8
+
9
+ - [Installation](#installation)
10
+ - [Decorating entities](#decorating-entities)
11
+ - [Seeding entities](#seeding-entities)
12
+ - [Seeder suites](#seeder-suites)
13
+ - [Seeding without `@Seed()`](#seeding-without-seed)
14
+ - [Logging](#logging)
15
+ - [Hooks](#hooks)
16
+ - [Skipping seeders](#skipping-seeders)
17
+ - [Running seed scripts](#running-seed-scripts)
18
+ - [API reference](#api-reference)
19
+
5
20
  ---
6
21
 
7
22
  ## Installation
@@ -193,6 +208,84 @@ Circular dependencies between seeders are detected at runtime and throw an error
193
208
 
194
209
  ---
195
210
 
211
+ ## Seeding without `@Seed()`
212
+
213
+ `@Seed()` is a convenience — it is not required. If you want to seed with explicit, fixed values rather than generated ones, use TypeORM's `Repository` or `EntityManager` directly inside `run()`. Both are available through the `dataSource` from `SeedContext`:
214
+
215
+ ```ts
216
+ @Seeder()
217
+ class UserSeeder implements SeederInterface {
218
+ async run({ dataSource }: SeedContext): Promise<void> {
219
+ await dataSource!.getRepository(User).save([
220
+ { name: 'Alice', role: 'admin' },
221
+ { name: 'Bob', role: 'user' },
222
+ ])
223
+ }
224
+ }
225
+ ```
226
+
227
+ You can mix both approaches freely — use `@Seed()` for entities where generated data is fine, and explicit values where the content matters.
228
+
229
+ ---
230
+
231
+ ## Logging
232
+
233
+ By default `runSeeders` logs each seeder's progress to the console:
234
+
235
+ ```
236
+ [UserSeeder] Starting...
237
+ [UserSeeder] Done in 42ms
238
+ ```
239
+
240
+ When a seeder throws, the failure is logged to `console.error` before the error is re-thrown:
241
+
242
+ ```
243
+ [UserSeeder] Failed after 3ms
244
+ ```
245
+
246
+ Pass `logging: false` to silence all built-in output.
247
+
248
+ ---
249
+
250
+ ## Hooks
251
+
252
+ `runSeeders` accepts lifecycle callbacks that fire around each seeder:
253
+
254
+ ```ts
255
+ await runSeeders([UserSeeder, PostSeeder], {
256
+ dataSource,
257
+ onBefore: (seeder) => console.log(`Starting ${seeder.name}...`),
258
+ onAfter: (seeder, durationMs) => console.log(`${seeder.name} done in ${durationMs}ms`),
259
+ onError: (seeder, error) => console.error(`${seeder.name} failed`, error),
260
+ })
261
+ ```
262
+
263
+ | Callback | When it fires |
264
+ |---|---|
265
+ | `onBefore(seeder)` | Before each seeder runs |
266
+ | `onAfter(seeder, durationMs)` | After each seeder completes successfully |
267
+ | `onError(seeder, error)` | When a seeder throws — the error is still re-thrown after this returns |
268
+
269
+ ---
270
+
271
+ ## Skipping seeders
272
+
273
+ Pass a `skip` callback to conditionally bypass individual seeders. Return `true` to skip, `false` (or nothing) to run:
274
+
275
+ ```ts
276
+ const alreadyRun = new Set(['UserSeeder'])
277
+
278
+ await runSeeders([UserSeeder, PostSeeder], {
279
+ dataSource,
280
+ skip: (seeder) => alreadyRun.has(seeder.name),
281
+ })
282
+ // UserSeeder is skipped, PostSeeder runs normally
283
+ ```
284
+
285
+ Skipped seeders do not trigger `onBefore`, `onAfter`, or `onError`.
286
+
287
+ ---
288
+
196
289
  ## Running seed scripts
197
290
 
198
291
  When running a seed script directly with Node.js, `reflect-metadata` must be the very first import — before any entity is loaded. TypeORM's decorators depend on it being in place when the class is evaluated.
@@ -280,7 +373,7 @@ Class decorator. Registers a class as a seeder and declares its dependencies.
280
373
 
281
374
  ---
282
375
 
283
- ### `runSeeders(seeders, context?)`
376
+ ### `runSeeders(seeders, options?)`
284
377
 
285
378
  Topologically sorts and runs the given seeders plus all their transitive dependencies.
286
379
 
@@ -290,6 +383,18 @@ runSeeders([PostSeeder], { dataSource }): Promise<void>
290
383
 
291
384
  Throws if a circular dependency is detected.
292
385
 
386
+ **`RunSeedersOptions`** extends `SeedContext`
387
+
388
+ | Property | Type | Default | Description |
389
+ |---|---|---|---|
390
+ | `dataSource` | `DataSource?` | — | Passed through to each seeder's `run()` and to factory functions. |
391
+ | `relations` | `boolean?` | `true` | Passed through to each seeder's `run()`. |
392
+ | `logging` | `boolean?` | `true` | Log seeder progress to the console. Set to `false` when handling output via hooks. |
393
+ | `onBefore` | `(seeder) => void \| Promise<void>` | — | Called before each seeder runs. |
394
+ | `onAfter` | `(seeder, durationMs) => void \| Promise<void>` | — | Called after each seeder completes successfully. |
395
+ | `onError` | `(seeder, error) => void \| Promise<void>` | — | Called when a seeder throws. The error is re-thrown after this returns. |
396
+ | `skip` | `(seeder) => boolean \| Promise<boolean>` | — | Return `true` to skip a seeder. Skipped seeders bypass all hooks. |
397
+
293
398
  ---
294
399
 
295
400
  ### `SeedContext`
package/dist/index.cjs CHANGED
@@ -3,6 +3,7 @@ let typeorm = require("typeorm");
3
3
  let dependency_graph = require("dependency-graph");
4
4
  //#region src/seed/registry.ts
5
5
  const registry$1 = /* @__PURE__ */ new Map();
6
+ /** Registers a seed entry for the given class constructor. Called internally by the `@Seed` decorator. */
6
7
  function registerSeed(target, entry) {
7
8
  const entries = registry$1.get(target) ?? [];
8
9
  entries.push(entry);
@@ -37,9 +38,11 @@ function Seed(factoryOrOptions, options) {
37
38
  }
38
39
  //#endregion
39
40
  //#region src/seed/creator.ts
41
+ /** Extracts the ancestor set from an internal context, returning an empty set for external callers. */
40
42
  function getAncestors(context) {
41
43
  return context._ancestors ?? /* @__PURE__ */ new Set();
42
44
  }
45
+ /** Returns a new context with `cls` added to the ancestor set, used to detect circular relation chains. */
43
46
  function withAncestor(context, cls) {
44
47
  const ancestors = getAncestors(context);
45
48
  return {
@@ -47,6 +50,7 @@ function withAncestor(context, cls) {
47
50
  _ancestors: new Set([...ancestors, cls])
48
51
  };
49
52
  }
53
+ /** Walks the prototype chain and returns all classes from `target` up to (but not including) `Function.prototype`. */
50
54
  function getClassHierarchy(target) {
51
55
  const hierarchy = [];
52
56
  let current = target;
@@ -56,6 +60,15 @@ function getClassHierarchy(target) {
56
60
  }
57
61
  return hierarchy;
58
62
  }
63
+ /**
64
+ * Creates one fully populated instance of `EntityClass` in memory.
65
+ *
66
+ * Runs in three steps:
67
+ * 1. Factory-decorated properties (`@Seed(factory)`) — run first, in declaration order.
68
+ * 2. Embedded types (`@Embedded`) — auto-seeded if the embedded class has any `@Seed` entries.
69
+ * 3. Bare relation decorators (`@Seed()` without a factory) — skipped when `relations` is `false`,
70
+ * and also skipped for any related class already present in the ancestor chain (circular guard).
71
+ */
59
72
  async function createOneSeed(EntityClass, context) {
60
73
  const instance = new EntityClass();
61
74
  const ancestors = getAncestors(context);
@@ -119,6 +132,11 @@ async function createManySeed(classOrClasses, { count, ...context }) {
119
132
  }
120
133
  //#endregion
121
134
  //#region src/seed/persist.ts
135
+ /**
136
+ * Walks an entity object graph and collects every unique entity class encountered.
137
+ * Used to discover all entity classes that need cascade-insert temporarily enabled
138
+ * before saving so that the full in-memory graph is persisted in one shot.
139
+ */
122
140
  function collectEntityClasses(entity, visited = /* @__PURE__ */ new Set()) {
123
141
  const EntityClass = entity.constructor;
124
142
  if (visited.has(EntityClass)) return [];
@@ -129,6 +147,16 @@ function collectEntityClasses(entity, visited = /* @__PURE__ */ new Set()) {
129
147
  } else if (value && typeof value === "object" && value.constructor !== Object) classes.push(...collectEntityClasses(value, visited));
130
148
  return classes;
131
149
  }
150
+ /**
151
+ * Temporarily enables `isCascadeInsert` on every TypeORM relation for the given class.
152
+ * Returns the previous flag values so they can be restored after saving.
153
+ *
154
+ * This is necessary because the seeder builds the full object graph in memory before
155
+ * calling `save()`. Without cascade inserts, TypeORM would only persist the root entity
156
+ * and ignore any nested relations that weren't already configured with `cascade: true`.
157
+ *
158
+ * Classes not registered as TypeORM entities (e.g. embedded value objects) are silently skipped.
159
+ */
132
160
  function enableCascadeInsert(EntityClass, dataSource) {
133
161
  const states = [];
134
162
  try {
@@ -143,6 +171,10 @@ function enableCascadeInsert(EntityClass, dataSource) {
143
171
  } catch {}
144
172
  return states;
145
173
  }
174
+ /**
175
+ * Restores `isCascadeInsert` flags to their original values.
176
+ * Always called in a `finally` block to guarantee cleanup even when saving throws.
177
+ */
146
178
  function restoreCascade(states) {
147
179
  for (const { relation, original } of states) relation.isCascadeInsert = original;
148
180
  }
@@ -171,6 +203,11 @@ async function saveManySeed(classOrClasses, options) {
171
203
  }
172
204
  return await saveManySeedOne(classOrClasses, options);
173
205
  }
206
+ /**
207
+ * Creates and persists `count` instances of a single entity class.
208
+ * Enables cascade inserts on every entity class in the object graph before saving,
209
+ * then restores the original flags — regardless of whether the save succeeds or fails.
210
+ */
174
211
  async function saveManySeedOne(EntityClass, options) {
175
212
  const { count, dataSource } = options;
176
213
  if (count === 0) return [];
@@ -218,14 +255,30 @@ function seed(classOrClasses) {
218
255
  //#endregion
219
256
  //#region src/seeder/registry.ts
220
257
  const registry = /* @__PURE__ */ new WeakMap();
258
+ /** Registers seeder metadata for the given class constructor. Called internally by the `@Seeder` decorator. */
221
259
  function registerSeeder(target, meta) {
222
260
  registry.set(target, meta);
223
261
  }
262
+ /** Returns the metadata registered for the given seeder class, or `undefined` if not registered. */
224
263
  function getSeederMeta(target) {
225
264
  return registry.get(target);
226
265
  }
227
266
  //#endregion
228
267
  //#region src/seeder/decorator.ts
268
+ /**
269
+ * Marks a class as a seeder and registers its dependency metadata.
270
+ *
271
+ * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves
272
+ * all transitive dependencies, sorts them topologically, and executes them in order.
273
+ *
274
+ * @example
275
+ * @Seeder({ dependencies: [UserSeeder] })
276
+ * class PostSeeder implements SeederInterface {
277
+ * async run(ctx: SeedContext) {
278
+ * await seed(Post).saveMany(50, ctx)
279
+ * }
280
+ * }
281
+ */
229
282
  function Seeder(options = {}) {
230
283
  return (target) => {
231
284
  registerSeeder(target, { dependencies: options.dependencies ?? [] });
@@ -233,6 +286,12 @@ function Seeder(options = {}) {
233
286
  }
234
287
  //#endregion
235
288
  //#region src/seeder/runner.ts
289
+ /**
290
+ * Topologically sorts the given seeders and all their transitive dependencies.
291
+ * BFS walks from the roots to collect all nodes, then dependency edges are wired and
292
+ * the graph is sorted so that every dependency precedes the seeders that depend on it.
293
+ * Throws a descriptive error if a circular dependency is detected.
294
+ */
236
295
  function topoSort(roots) {
237
296
  const graph = new dependency_graph.DepGraph();
238
297
  const byName = /* @__PURE__ */ new Map();
@@ -257,6 +316,24 @@ function topoSort(roots) {
257
316
  throw err;
258
317
  }
259
318
  }
319
+ /**
320
+ * Runs the given seeders (and all their transitive dependencies) in dependency order.
321
+ *
322
+ * Each seeder is instantiated, its `run` method is called with the context derived
323
+ * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called
324
+ * around it. Errors are re-thrown after `onError` returns.
325
+ *
326
+ * @example
327
+ * await runSeeders([PostSeeder], { dataSource })
328
+ *
329
+ * @example
330
+ * // With lifecycle hooks and no console output
331
+ * await runSeeders([PostSeeder], {
332
+ * dataSource,
333
+ * logging: false,
334
+ * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),
335
+ * })
336
+ */
260
337
  async function runSeeders(seeders, options = {}) {
261
338
  const { logging = true, onBefore, onAfter, onError, skip, ...context } = options;
262
339
  for (const SeederClass of topoSort(seeders)) {
@@ -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\nexport interface SeedContext {\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/** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */\nexport type SeedFactory<T = unknown> = (context: SeedContext) => T | Promise<T>;\n\n/** Options passed to @Seed. */\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\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/** Mark a relation property for auto-seeding (creates one related entity). */\nexport function Seed(): PropertyDecorator;\n/** Mark a relation property for auto-seeding with options (e.g. count for one-to-many). */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/** Mark a scalar property with a factory callback. */\nexport function Seed(factory: SeedFactory): PropertyDecorator;\n/** Mark a scalar property with a factory callback and 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\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\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\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\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);\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\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\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\nexport interface SaveSeedOptions extends SeedContext {\n dataSource: DataSource;\n}\n\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\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\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\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\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\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\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\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\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\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\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\nexport interface SeederOptions {\n dependencies?: (new () => SeederInterface)[];\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\nexport type SeederCtor = new () => SeederInterface;\n\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\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\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":";;;;AAiDA,MAAMA,6BAAW,IAAI,KAA4B;AAEjD,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;;;;ACjET,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;;AAG7D,SAAS,aAAa,SAAsB,KAAgC;CAC1E,MAAM,YAAY,aAAa,QAAQ;AAEvC,QAAO;EAAE,GAAG;EAAS,YAAY,IAAI,IAAI,CAAC,GAAG,WAAW,IAAI,CAAC;EAAE;;AAGjE,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;;AAGT,eAAe,cACb,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,QAAQ;AAC5C,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,cAAc,eAAe,QAAQ;AAC3E,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,eAAe,cAAc;GACvD,OAAO,QAAQ,SAAS;GACxB,GAAG;GACJ,CAAC;MAEF,QAAO,eAAe,MAAM,cAAc,cAAc,aAAa;AAGvE,mBAAiB,IAAI,YAAY;;AAGnC,QAAO;;AAWT,eAAsB,WACpB,gBACA,UAAuB,EAAE,EACM;AAC/B,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAgC;GAAE,WAAW;GAAO,GAAG;GAAS;AAEtE,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAAQ,cAAc,KAAK,iBAAiB,CAAC,CAC3F;;CAGH,MAAM,CAAC,UAAU,MAAM,eAAe,gBAAwC;EAC5E,OAAO;EACP,GAAG;EACJ,CAAC;AAEF,QAAO;;AAWT,eAAsB,eACpB,gBACA,EAAE,OAAO,GAAG,WACuB;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,cAAc,KAAK,iBAAiB,CAAC,CAAC,CACvF,CACF;;AAGH,QAAO,MAAM,QAAQ,IACnB,MAAM,KAAK,EAAE,QAAQ,OAAO,QAC1B,cAAc,gBAAwC,QAAQ,CAC/D,CACF;;;;ACjJH,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;;AAGT,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;;AAGT,SAAS,eAAe,QAA8B;AACpD,MAAK,MAAM,EAAE,UAAU,cAAc,OACnC,UAAS,kBAAkB;;AAoB/B,eAAsB,SACpB,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,aAAa,KAAK,iBAAiB,CAAC,MAAM,CAAC,YAAY,OAAQ,CAChE,CACF;;CAGH,MAAM,CAAC,UAAU,MAAM,aAAa,gBAAwC;EAC1E,GAAG;EACH,OAAO;EACR,CAAC;AAEF,QAAO;;AAmBT,eAAsB,aACpB,gBACA,SACmC;AACnC,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAmB;GAAE,WAAW;GAAO,GAAG;GAAS;AAEzD,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAAQ,gBAAgB,KAAK,iBAAiB,CAAC,CAC7F;;AAGH,QAAO,MAAM,gBAAgB,gBAAwC,QAAQ;;AAG/E,eAAe,gBACb,aACA,SACc;CACd,MAAM,EAAE,OAAO,eAAe;AAE9B,KAAI,UAAU,EACZ,QAAO,EAAE;CAGX,MAAM,WAAW,MAAM,eAAe,aAAa,QAAQ;CAE3D,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;;;;;ACrI1B,SAAgB,KACd,gBACyD;AACzD,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,UAAU;AAEhB,SAAO;GACL,SAAS,YACP,WAAW,SAAgC,QAAQ;GAGrD,OAAO,YACL,SAAS,SAAgC,QAAQ;GAGnD,aAAa,OAAe,YAC1B,eAAe,SAAgC;IAAE;IAAO,GAAG;IAAS,CAAC;GAGvE,WAAW,OAAe,YACxB,aAAa,SAAgC;IAAE;IAAO,GAAG;IAAS,CAAC;GAGtE;;CAGH,MAAM,cAAc;AAEpB,QAAO;EACL,SAAS,YAA0B,WAAW,aAAa,QAAQ;EACnE,OAAO,YAA6B,SAAS,aAAa,QAAQ;EAClE,aAAa,OAAe,YAC1B,eAAe,aAAa;GAAE;GAAO,GAAG;GAAS,CAAC;EACpD,WAAW,OAAe,YACxB,aAAa,aAAa;GAAE;GAAO,GAAG;GAAS,CAAC;EACnD;;;;AClEH,MAAM,2BAAW,IAAI,SAA+B;AAEpD,SAAgB,eAAe,QAAkB,MAAwB;AACvE,UAAS,IAAI,QAAQ,KAAK;;AAG5B,SAAgB,cAAc,QAA0C;AACtE,QAAO,SAAS,IAAI,OAAO;;;;ACA7B,SAAgB,OAAO,UAAyB,EAAE,EAAkB;AAClE,SAAQ,WAAW;AACjB,iBAAe,QAAQ,EAAE,cAAc,QAAQ,gBAAgB,EAAE,EAAE,CAAC;;;;;ACYxE,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;;;AAIV,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"}
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/** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */\nexport type SeedFactory<T = unknown> = (context: SeedContext) => 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);\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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"}
package/dist/index.d.cts CHANGED
@@ -5,7 +5,17 @@ import { DataSource } from "typeorm";
5
5
  type EntityInstance = object;
6
6
  /** A constructor that produces an entity instance. */
7
7
  type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;
8
+ /** Context passed through a seed operation. Available inside factory callbacks and `SeederInterface.run`. */
8
9
  interface SeedContext {
10
+ /**
11
+ * The TypeORM DataSource. Automatically set by `save`/`saveMany` calls.
12
+ * Also available in factory callbacks — useful for looking up existing
13
+ * entities instead of creating new ones:
14
+ *
15
+ * @example
16
+ * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))
17
+ * role!: Role
18
+ */
9
19
  dataSource?: DataSource;
10
20
  /**
11
21
  * Set to `false` to skip automatic relation seeding. Scalar and embedded
@@ -19,7 +29,7 @@ interface SeedContext {
19
29
  }
20
30
  /** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */
21
31
  type SeedFactory<T = unknown> = (context: SeedContext) => T | Promise<T>;
22
- /** Options passed to @Seed. */
32
+ /** Options for the `@Seed` decorator. */
23
33
  interface SeedOptions {
24
34
  /**
25
35
  * Number of related entities to create. Only meaningful on one-to-many and
@@ -37,19 +47,55 @@ type MapToInstances<T extends readonly EntityConstructor[]> = { [K in keyof T]:
37
47
  type MapToInstanceArrays<T extends readonly EntityConstructor[]> = { [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never };
38
48
  //#endregion
39
49
  //#region src/seed/decorator.d.ts
40
- /** Mark a relation property for auto-seeding (creates one related entity). */
50
+ /**
51
+ * Marks a relation property for auto-seeding.
52
+ *
53
+ * The related entity class is inferred from TypeORM metadata. One instance is created
54
+ * and recursively seeded (including its own `@Seed` properties).
55
+ *
56
+ * Circular back-references are broken automatically: if the related class is already
57
+ * being seeded higher up in the same call chain, the property is left `undefined`.
58
+ * TypeORM treats `undefined` as "don't touch this column" rather than setting it to null.
59
+ */
41
60
  declare function Seed(): PropertyDecorator;
42
- /** Mark a relation property for auto-seeding with options (e.g. count for one-to-many). */
61
+ /**
62
+ * Marks a relation property for auto-seeding with options.
63
+ *
64
+ * Use `count` on one-to-many and many-to-many properties to control how many
65
+ * related entities are created. Ignored for one-to-one and many-to-one.
66
+ *
67
+ * @example
68
+ * @Seed({ count: 3 })
69
+ * @OneToMany(() => Book, (b) => b.author)
70
+ * books!: Book[]
71
+ */
43
72
  declare function Seed(options: SeedOptions): PropertyDecorator;
44
- /** Mark a scalar property with a factory callback. */
73
+ /**
74
+ * Marks a property with a factory callback.
75
+ *
76
+ * The factory receives the current {@link SeedContext} and can return any value,
77
+ * including a `Promise`. Use this for scalar properties or when you need full
78
+ * control over how a related entity is resolved.
79
+ *
80
+ * @example
81
+ * @Seed(() => faker.internet.email())
82
+ * email!: string
83
+ *
84
+ * @example
85
+ * // Look up an existing entity instead of creating a new one
86
+ * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))
87
+ * role!: Role
88
+ */
45
89
  declare function Seed(factory: SeedFactory): PropertyDecorator;
46
- /** Mark a scalar property with a factory callback and options. */
90
+ /** Marks a property with a factory callback and additional options. */
47
91
  declare function Seed(factory: SeedFactory, options: SeedOptions): PropertyDecorator;
48
92
  //#endregion
49
93
  //#region src/seed/persist.d.ts
94
+ /** Options for {@link saveSeed}. Extends {@link SeedContext} with a required DataSource. */
50
95
  interface SaveSeedOptions extends SeedContext {
51
96
  dataSource: DataSource;
52
97
  }
98
+ /** Options for {@link saveManySeed}. Extends {@link SaveSeedOptions} with a required instance count. */
53
99
  interface SaveManySeedOptions extends SaveSeedOptions {
54
100
  count: number;
55
101
  }
@@ -75,6 +121,7 @@ declare function saveManySeed<T extends EntityInstance>(EntityClass: EntityConst
75
121
  declare function saveManySeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: SaveManySeedOptions): Promise<MapToInstanceArrays<T>>;
76
122
  //#endregion
77
123
  //#region src/seed/builder.d.ts
124
+ /** Seed builder for a single entity class. Returned by {@link seed} when passed one class. */
78
125
  interface SingleSeed<T extends EntityInstance> {
79
126
  /** Creates a single instance in memory without persisting. */
80
127
  create(context?: SeedContext): Promise<T>;
@@ -85,6 +132,11 @@ interface SingleSeed<T extends EntityInstance> {
85
132
  /** Creates and persists multiple instances. */
86
133
  saveMany(count: number, options: SaveSeedOptions): Promise<T[]>;
87
134
  }
135
+ /**
136
+ * Seed builder for multiple entity classes. Returned by {@link seed} when passed an array.
137
+ * Each method returns a tuple of instances in the same order as the input array.
138
+ * Relation seeding is disabled by default; pass `relations: true` in the context to enable it.
139
+ */
88
140
  interface MultiSeed<T extends readonly EntityConstructor[]> {
89
141
  /** Creates one instance of each class in memory without persisting. */
90
142
  create(context?: SeedContext): Promise<MapToInstances<T>>;
@@ -95,29 +147,95 @@ interface MultiSeed<T extends readonly EntityConstructor[]> {
95
147
  /** Creates and persists `count` instances of each class. */
96
148
  saveMany(count: number, options: SaveSeedOptions): Promise<MapToInstanceArrays<T>>;
97
149
  }
150
+ /**
151
+ * Entry point for creating and persisting seed data.
152
+ *
153
+ * Pass a single entity class to get a {@link SingleSeed} builder, or an array of classes
154
+ * to get a {@link MultiSeed} builder that operates on all of them at once.
155
+ *
156
+ * @example
157
+ * // Create one Author in memory (no DB)
158
+ * const author = await seed(Author).create()
159
+ *
160
+ * @example
161
+ * // Persist one Author with all its seeded relations
162
+ * const author = await seed(Author).save({ dataSource })
163
+ *
164
+ * @example
165
+ * // Persist 10 Authors
166
+ * const authors = await seed(Author).saveMany(10, { dataSource })
167
+ *
168
+ * @example
169
+ * // Create multiple entity classes at once (relations disabled by default)
170
+ * const [user, post] = await seed([User, Post]).create()
171
+ */
98
172
  declare function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;
99
173
  declare function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;
100
174
  //#endregion
101
175
  //#region src/seed/creator.d.ts
176
+ /** Options for {@link createManySeed}. Extends {@link SeedContext} with a required instance count. */
102
177
  interface CreateManySeedOptions extends SeedContext {
103
178
  count: number;
104
179
  }
180
+ /**
181
+ * Creates one entity instance in memory without persisting it.
182
+ *
183
+ * When passed an array of classes, relation seeding is disabled by default
184
+ * (pass `relations: true` in the context to override). Returns a tuple of
185
+ * instances in the same order as the input array.
186
+ */
105
187
  declare function createSeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, context?: SeedContext): Promise<T>;
106
188
  declare function createSeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], context?: SeedContext): Promise<MapToInstances<T>>;
189
+ /**
190
+ * Creates multiple entity instances in memory without persisting them.
191
+ *
192
+ * When passed an array of classes, returns a tuple of arrays — one per class — each
193
+ * containing `count` instances. Relation seeding is disabled by default for the
194
+ * array variant; pass `relations: true` in the options to override.
195
+ */
107
196
  declare function createManySeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, options: CreateManySeedOptions): Promise<T[]>;
108
197
  declare function createManySeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: CreateManySeedOptions): Promise<MapToInstanceArrays<T>>;
109
198
  //#endregion
110
199
  //#region src/seeder/decorator.d.ts
200
+ /**
201
+ * Interface that seeder classes must implement.
202
+ *
203
+ * The `run` method receives the seed context (which includes the DataSource when
204
+ * called via `runSeeders`) and performs the seeding logic — typically by calling
205
+ * `seed().save()` or other seeding utilities.
206
+ */
111
207
  interface SeederInterface {
112
208
  run(context: SeedContext): Promise<void>;
113
209
  }
210
+ /** Configuration options for the {@link Seeder} decorator. */
114
211
  interface SeederOptions {
212
+ /**
213
+ * Seeder classes that must complete before this one runs.
214
+ * Resolved transitively — dependencies of dependencies are included automatically.
215
+ * {@link runSeeders} topologically sorts the full set and detects circular dependencies.
216
+ */
115
217
  dependencies?: (new () => SeederInterface)[];
116
218
  }
219
+ /**
220
+ * Marks a class as a seeder and registers its dependency metadata.
221
+ *
222
+ * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves
223
+ * all transitive dependencies, sorts them topologically, and executes them in order.
224
+ *
225
+ * @example
226
+ * @Seeder({ dependencies: [UserSeeder] })
227
+ * class PostSeeder implements SeederInterface {
228
+ * async run(ctx: SeedContext) {
229
+ * await seed(Post).saveMany(50, ctx)
230
+ * }
231
+ * }
232
+ */
117
233
  declare function Seeder(options?: SeederOptions): ClassDecorator;
118
234
  //#endregion
119
235
  //#region src/seeder/runner.d.ts
236
+ /** Constructor type for a class decorated with `@Seeder`. */
120
237
  type SeederCtor = new () => SeederInterface;
238
+ /** Options for {@link runSeeders}. Extends {@link SeedContext} with lifecycle hooks and logging control. */
121
239
  interface RunSeedersOptions extends SeedContext {
122
240
  /**
123
241
  * Enable console logging for each seeder. Set to `false` to silence output,
@@ -135,6 +253,24 @@ interface RunSeedersOptions extends SeedContext {
135
253
  /** Called for each seeder before it runs. Return `true` to skip it entirely. */
136
254
  skip?: (seeder: SeederCtor) => boolean | Promise<boolean>;
137
255
  }
256
+ /**
257
+ * Runs the given seeders (and all their transitive dependencies) in dependency order.
258
+ *
259
+ * Each seeder is instantiated, its `run` method is called with the context derived
260
+ * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called
261
+ * around it. Errors are re-thrown after `onError` returns.
262
+ *
263
+ * @example
264
+ * await runSeeders([PostSeeder], { dataSource })
265
+ *
266
+ * @example
267
+ * // With lifecycle hooks and no console output
268
+ * await runSeeders([PostSeeder], {
269
+ * dataSource,
270
+ * logging: false,
271
+ * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),
272
+ * })
273
+ */
138
274
  declare function runSeeders(seeders: SeederCtor[], options?: RunSeedersOptions): Promise<void>;
139
275
  //#endregion
140
276
  export { type CreateManySeedOptions, type EntityConstructor, type EntityInstance, type RunSeedersOptions, type SaveManySeedOptions, type SaveSeedOptions, Seed, type SeedContext, type SeedEntry, type SeedFactory, type SeedOptions, Seeder, type SeederCtor, type SeederInterface, type SeederOptions, createManySeed, createSeed, runSeeders, saveManySeed, saveSeed, seed };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seed/creator.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"mappings":";;;;KAGY,cAAA;AAAZ;AAAA,KAGY,iBAAA,WAA4B,cAAA,GAAiB,cAAA,cAA4B,CAAA;AAAA,UAEpE,WAAA;EACf,UAAA,GAAa,UAAA;EANW;AAG1B;;;;;;;EAYE,SAAA;AAAA;;KAIU,WAAA,iBAA4B,OAAA,EAAS,WAAA,KAAgB,CAAA,GAAI,OAAA,CAAQ,CAAA;;UAG5D,WAAA;EAnBqE;AAEtF;;;EAsBE,KAAA;AAAA;AAAA,UAGe,SAAA;EACf,WAAA;EAhBS;EAkBT,OAAA,EAAS,WAAA;EACT,OAAA,EAAS,WAAA;AAAA;AAAA,KAGC,cAAA,oBAAkC,iBAAA,oBAChC,CAAA,GAAI,CAAA,CAAE,CAAA,UAAW,iBAAA,YAA6B,CAAA;AAAA,KAGhD,mBAAA,oBAAuC,iBAAA,oBACrC,CAAA,GAAI,CAAA,CAAE,CAAA,UAAW,iBAAA,YAA6B,CAAA;;;;iBCzC5C,IAAA,CAAA,GAAQ,iBAAA;ADDxB;AAAA,iBCGgB,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,iBAAA;;iBAE5B,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,iBAAA;;iBAE5B,IAAA,CAAK,OAAA,EAAS,WAAA,EAAa,OAAA,EAAS,WAAA,GAAc,iBAAA;;;UCCjD,eAAA,SAAwB,WAAA;EACvC,UAAA,EAAY,UAAA;AAAA;AAAA,UAGG,mBAAA,SAA4B,eAAA;EAC3C,KAAA;AAAA;AFVF;;;;AAAA,iBE6EsB,QAAA,WAAmB,cAAA,CAAA,CACvC,WAAA,EAAa,iBAAA,CAAkB,CAAA,GAC/B,OAAA,EAAS,eAAA,GACR,OAAA,CAAQ,CAAA;;;;;iBAKW,QAAA,oBAA4B,iBAAA,GAAA,CAChD,aAAA,MAAmB,CAAA,GACnB,OAAA,EAAS,eAAA,GACR,OAAA,CAAQ,cAAA,CAAe,CAAA;;;;;iBA2BJ,YAAA,WAAuB,cAAA,CAAA,CAC3C,WAAA,EAAa,iBAAA,CAAkB,CAAA,GAC/B,OAAA,EAAS,mBAAA,GACR,OAAA,CAAQ,CAAA;;;;;iBAKW,YAAA,oBAAgC,iBAAA,GAAA,CACpD,aAAA,MAAmB,CAAA,GACnB,OAAA,EAAS,mBAAA,GACR,OAAA,CAAQ,mBAAA,CAAoB,CAAA;;;UCzHrB,UAAA,WAAqB,cAAA;EHRnB;EGUV,MAAA,CAAO,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,CAAA;;EAEvC,IAAA,CAAK,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,CAAA;EHZhB;EGcxB,UAAA,CAAW,KAAA,UAAe,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,CAAA;EHX/B;EGa3B,QAAA,CAAS,KAAA,UAAe,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,CAAA;AAAA;AAAA,UAGnD,SAAA,oBAA6B,iBAAA;EHhB8C;EGkBnF,MAAA,CAAO,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,cAAA,CAAe,CAAA;EHlB8B;EGoBpF,IAAA,CAAK,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,cAAA,CAAe,CAAA;EHpBjB;EGsBtC,UAAA,CAAW,KAAA,UAAe,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,mBAAA,CAAoB,CAAA;EHtBK;EGwBnF,QAAA,CAAS,KAAA,UAAe,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,mBAAA,CAAoB,CAAA;AAAA;AAAA,iBAGjE,IAAA,WAAe,cAAA,CAAA,CAAgB,WAAA,EAAa,iBAAA,CAAkB,CAAA,IAAK,UAAA,CAAW,CAAA;AAAA,iBAC9E,IAAA,oBAAwB,iBAAA,GAAA,CAAqB,aAAA,MAAmB,CAAA,IAAK,SAAA,CAAU,CAAA;;;UCxB9E,qBAAA,SAA8B,WAAA;EAC7C,KAAA;AAAA;AAAA,iBA8GoB,UAAA,WAAqB,cAAA,CAAA,CACzC,WAAA,EAAa,iBAAA,CAAkB,CAAA,GAC/B,OAAA,GAAU,WAAA,GACT,OAAA,CAAQ,CAAA;AAAA,iBACW,UAAA,oBAA8B,iBAAA,GAAA,CAClD,aAAA,MAAmB,CAAA,GACnB,OAAA,GAAU,WAAA,GACT,OAAA,CAAQ,cAAA,CAAe,CAAA;AAAA,iBAqBJ,cAAA,WAAyB,cAAA,CAAA,CAC7C,WAAA,EAAa,iBAAA,CAAkB,CAAA,GAC/B,OAAA,EAAS,qBAAA,GACR,OAAA,CAAQ,CAAA;AAAA,iBACW,cAAA,oBAAkC,iBAAA,GAAA,CACtD,aAAA,MAAmB,CAAA,GACnB,OAAA,EAAS,qBAAA,GACR,OAAA,CAAQ,mBAAA,CAAoB,CAAA;;;UCzJd,eAAA;EACf,GAAA,CAAI,OAAA,EAAS,WAAA,GAAc,OAAA;AAAA;AAAA,UAGZ,aAAA;EACf,YAAA,cAA0B,eAAA;AAAA;AAAA,iBAGZ,MAAA,CAAO,OAAA,GAAS,aAAA,GAAqB,cAAA;;;KCNzC,UAAA,aAAuB,eAAA;AAAA,UAElB,iBAAA,SAA0B,WAAA;ENJjB;;;;AAG1B;;EMQE,OAAA;ENRsC;EMUtC,QAAA,IAAY,MAAA,EAAQ,UAAA,YAAsB,OAAA;ENVyC;EMYnF,OAAA,IAAW,MAAA,EAAQ,UAAA,EAAY,UAAA,oBAA8B,OAAA;ENZuB;EMcpF,OAAA,IAAW,MAAA,EAAQ,UAAA,EAAY,KAAA,qBAA0B,OAAA;ENdnB;EMgBtC,IAAA,IAAQ,MAAA,EAAQ,UAAA,eAAyB,OAAA;AAAA;AAAA,iBA8CrB,UAAA,CACpB,OAAA,EAAS,UAAA,IACT,OAAA,GAAS,iBAAA,GACR,OAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seed/creator.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -5,7 +5,17 @@ import { DataSource } from "typeorm";
5
5
  type EntityInstance = object;
6
6
  /** A constructor that produces an entity instance. */
7
7
  type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;
8
+ /** Context passed through a seed operation. Available inside factory callbacks and `SeederInterface.run`. */
8
9
  interface SeedContext {
10
+ /**
11
+ * The TypeORM DataSource. Automatically set by `save`/`saveMany` calls.
12
+ * Also available in factory callbacks — useful for looking up existing
13
+ * entities instead of creating new ones:
14
+ *
15
+ * @example
16
+ * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))
17
+ * role!: Role
18
+ */
9
19
  dataSource?: DataSource;
10
20
  /**
11
21
  * Set to `false` to skip automatic relation seeding. Scalar and embedded
@@ -19,7 +29,7 @@ interface SeedContext {
19
29
  }
20
30
  /** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */
21
31
  type SeedFactory<T = unknown> = (context: SeedContext) => T | Promise<T>;
22
- /** Options passed to @Seed. */
32
+ /** Options for the `@Seed` decorator. */
23
33
  interface SeedOptions {
24
34
  /**
25
35
  * Number of related entities to create. Only meaningful on one-to-many and
@@ -37,19 +47,55 @@ type MapToInstances<T extends readonly EntityConstructor[]> = { [K in keyof T]:
37
47
  type MapToInstanceArrays<T extends readonly EntityConstructor[]> = { [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never };
38
48
  //#endregion
39
49
  //#region src/seed/decorator.d.ts
40
- /** Mark a relation property for auto-seeding (creates one related entity). */
50
+ /**
51
+ * Marks a relation property for auto-seeding.
52
+ *
53
+ * The related entity class is inferred from TypeORM metadata. One instance is created
54
+ * and recursively seeded (including its own `@Seed` properties).
55
+ *
56
+ * Circular back-references are broken automatically: if the related class is already
57
+ * being seeded higher up in the same call chain, the property is left `undefined`.
58
+ * TypeORM treats `undefined` as "don't touch this column" rather than setting it to null.
59
+ */
41
60
  declare function Seed(): PropertyDecorator;
42
- /** Mark a relation property for auto-seeding with options (e.g. count for one-to-many). */
61
+ /**
62
+ * Marks a relation property for auto-seeding with options.
63
+ *
64
+ * Use `count` on one-to-many and many-to-many properties to control how many
65
+ * related entities are created. Ignored for one-to-one and many-to-one.
66
+ *
67
+ * @example
68
+ * @Seed({ count: 3 })
69
+ * @OneToMany(() => Book, (b) => b.author)
70
+ * books!: Book[]
71
+ */
43
72
  declare function Seed(options: SeedOptions): PropertyDecorator;
44
- /** Mark a scalar property with a factory callback. */
73
+ /**
74
+ * Marks a property with a factory callback.
75
+ *
76
+ * The factory receives the current {@link SeedContext} and can return any value,
77
+ * including a `Promise`. Use this for scalar properties or when you need full
78
+ * control over how a related entity is resolved.
79
+ *
80
+ * @example
81
+ * @Seed(() => faker.internet.email())
82
+ * email!: string
83
+ *
84
+ * @example
85
+ * // Look up an existing entity instead of creating a new one
86
+ * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))
87
+ * role!: Role
88
+ */
45
89
  declare function Seed(factory: SeedFactory): PropertyDecorator;
46
- /** Mark a scalar property with a factory callback and options. */
90
+ /** Marks a property with a factory callback and additional options. */
47
91
  declare function Seed(factory: SeedFactory, options: SeedOptions): PropertyDecorator;
48
92
  //#endregion
49
93
  //#region src/seed/persist.d.ts
94
+ /** Options for {@link saveSeed}. Extends {@link SeedContext} with a required DataSource. */
50
95
  interface SaveSeedOptions extends SeedContext {
51
96
  dataSource: DataSource;
52
97
  }
98
+ /** Options for {@link saveManySeed}. Extends {@link SaveSeedOptions} with a required instance count. */
53
99
  interface SaveManySeedOptions extends SaveSeedOptions {
54
100
  count: number;
55
101
  }
@@ -75,6 +121,7 @@ declare function saveManySeed<T extends EntityInstance>(EntityClass: EntityConst
75
121
  declare function saveManySeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: SaveManySeedOptions): Promise<MapToInstanceArrays<T>>;
76
122
  //#endregion
77
123
  //#region src/seed/builder.d.ts
124
+ /** Seed builder for a single entity class. Returned by {@link seed} when passed one class. */
78
125
  interface SingleSeed<T extends EntityInstance> {
79
126
  /** Creates a single instance in memory without persisting. */
80
127
  create(context?: SeedContext): Promise<T>;
@@ -85,6 +132,11 @@ interface SingleSeed<T extends EntityInstance> {
85
132
  /** Creates and persists multiple instances. */
86
133
  saveMany(count: number, options: SaveSeedOptions): Promise<T[]>;
87
134
  }
135
+ /**
136
+ * Seed builder for multiple entity classes. Returned by {@link seed} when passed an array.
137
+ * Each method returns a tuple of instances in the same order as the input array.
138
+ * Relation seeding is disabled by default; pass `relations: true` in the context to enable it.
139
+ */
88
140
  interface MultiSeed<T extends readonly EntityConstructor[]> {
89
141
  /** Creates one instance of each class in memory without persisting. */
90
142
  create(context?: SeedContext): Promise<MapToInstances<T>>;
@@ -95,29 +147,95 @@ interface MultiSeed<T extends readonly EntityConstructor[]> {
95
147
  /** Creates and persists `count` instances of each class. */
96
148
  saveMany(count: number, options: SaveSeedOptions): Promise<MapToInstanceArrays<T>>;
97
149
  }
150
+ /**
151
+ * Entry point for creating and persisting seed data.
152
+ *
153
+ * Pass a single entity class to get a {@link SingleSeed} builder, or an array of classes
154
+ * to get a {@link MultiSeed} builder that operates on all of them at once.
155
+ *
156
+ * @example
157
+ * // Create one Author in memory (no DB)
158
+ * const author = await seed(Author).create()
159
+ *
160
+ * @example
161
+ * // Persist one Author with all its seeded relations
162
+ * const author = await seed(Author).save({ dataSource })
163
+ *
164
+ * @example
165
+ * // Persist 10 Authors
166
+ * const authors = await seed(Author).saveMany(10, { dataSource })
167
+ *
168
+ * @example
169
+ * // Create multiple entity classes at once (relations disabled by default)
170
+ * const [user, post] = await seed([User, Post]).create()
171
+ */
98
172
  declare function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;
99
173
  declare function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;
100
174
  //#endregion
101
175
  //#region src/seed/creator.d.ts
176
+ /** Options for {@link createManySeed}. Extends {@link SeedContext} with a required instance count. */
102
177
  interface CreateManySeedOptions extends SeedContext {
103
178
  count: number;
104
179
  }
180
+ /**
181
+ * Creates one entity instance in memory without persisting it.
182
+ *
183
+ * When passed an array of classes, relation seeding is disabled by default
184
+ * (pass `relations: true` in the context to override). Returns a tuple of
185
+ * instances in the same order as the input array.
186
+ */
105
187
  declare function createSeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, context?: SeedContext): Promise<T>;
106
188
  declare function createSeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], context?: SeedContext): Promise<MapToInstances<T>>;
189
+ /**
190
+ * Creates multiple entity instances in memory without persisting them.
191
+ *
192
+ * When passed an array of classes, returns a tuple of arrays — one per class — each
193
+ * containing `count` instances. Relation seeding is disabled by default for the
194
+ * array variant; pass `relations: true` in the options to override.
195
+ */
107
196
  declare function createManySeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, options: CreateManySeedOptions): Promise<T[]>;
108
197
  declare function createManySeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: CreateManySeedOptions): Promise<MapToInstanceArrays<T>>;
109
198
  //#endregion
110
199
  //#region src/seeder/decorator.d.ts
200
+ /**
201
+ * Interface that seeder classes must implement.
202
+ *
203
+ * The `run` method receives the seed context (which includes the DataSource when
204
+ * called via `runSeeders`) and performs the seeding logic — typically by calling
205
+ * `seed().save()` or other seeding utilities.
206
+ */
111
207
  interface SeederInterface {
112
208
  run(context: SeedContext): Promise<void>;
113
209
  }
210
+ /** Configuration options for the {@link Seeder} decorator. */
114
211
  interface SeederOptions {
212
+ /**
213
+ * Seeder classes that must complete before this one runs.
214
+ * Resolved transitively — dependencies of dependencies are included automatically.
215
+ * {@link runSeeders} topologically sorts the full set and detects circular dependencies.
216
+ */
115
217
  dependencies?: (new () => SeederInterface)[];
116
218
  }
219
+ /**
220
+ * Marks a class as a seeder and registers its dependency metadata.
221
+ *
222
+ * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves
223
+ * all transitive dependencies, sorts them topologically, and executes them in order.
224
+ *
225
+ * @example
226
+ * @Seeder({ dependencies: [UserSeeder] })
227
+ * class PostSeeder implements SeederInterface {
228
+ * async run(ctx: SeedContext) {
229
+ * await seed(Post).saveMany(50, ctx)
230
+ * }
231
+ * }
232
+ */
117
233
  declare function Seeder(options?: SeederOptions): ClassDecorator;
118
234
  //#endregion
119
235
  //#region src/seeder/runner.d.ts
236
+ /** Constructor type for a class decorated with `@Seeder`. */
120
237
  type SeederCtor = new () => SeederInterface;
238
+ /** Options for {@link runSeeders}. Extends {@link SeedContext} with lifecycle hooks and logging control. */
121
239
  interface RunSeedersOptions extends SeedContext {
122
240
  /**
123
241
  * Enable console logging for each seeder. Set to `false` to silence output,
@@ -135,6 +253,24 @@ interface RunSeedersOptions extends SeedContext {
135
253
  /** Called for each seeder before it runs. Return `true` to skip it entirely. */
136
254
  skip?: (seeder: SeederCtor) => boolean | Promise<boolean>;
137
255
  }
256
+ /**
257
+ * Runs the given seeders (and all their transitive dependencies) in dependency order.
258
+ *
259
+ * Each seeder is instantiated, its `run` method is called with the context derived
260
+ * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called
261
+ * around it. Errors are re-thrown after `onError` returns.
262
+ *
263
+ * @example
264
+ * await runSeeders([PostSeeder], { dataSource })
265
+ *
266
+ * @example
267
+ * // With lifecycle hooks and no console output
268
+ * await runSeeders([PostSeeder], {
269
+ * dataSource,
270
+ * logging: false,
271
+ * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),
272
+ * })
273
+ */
138
274
  declare function runSeeders(seeders: SeederCtor[], options?: RunSeedersOptions): Promise<void>;
139
275
  //#endregion
140
276
  export { type CreateManySeedOptions, type EntityConstructor, type EntityInstance, type RunSeedersOptions, type SaveManySeedOptions, type SaveSeedOptions, Seed, type SeedContext, type SeedEntry, type SeedFactory, type SeedOptions, Seeder, type SeederCtor, type SeederInterface, type SeederOptions, createManySeed, createSeed, runSeeders, saveManySeed, saveSeed, seed };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seed/creator.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seed/creator.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -2,6 +2,7 @@ import { getMetadataArgsStorage } from "typeorm";
2
2
  import { DepGraph } from "dependency-graph";
3
3
  //#region src/seed/registry.ts
4
4
  const registry$1 = /* @__PURE__ */ new Map();
5
+ /** Registers a seed entry for the given class constructor. Called internally by the `@Seed` decorator. */
5
6
  function registerSeed(target, entry) {
6
7
  const entries = registry$1.get(target) ?? [];
7
8
  entries.push(entry);
@@ -36,9 +37,11 @@ function Seed(factoryOrOptions, options) {
36
37
  }
37
38
  //#endregion
38
39
  //#region src/seed/creator.ts
40
+ /** Extracts the ancestor set from an internal context, returning an empty set for external callers. */
39
41
  function getAncestors(context) {
40
42
  return context._ancestors ?? /* @__PURE__ */ new Set();
41
43
  }
44
+ /** Returns a new context with `cls` added to the ancestor set, used to detect circular relation chains. */
42
45
  function withAncestor(context, cls) {
43
46
  const ancestors = getAncestors(context);
44
47
  return {
@@ -46,6 +49,7 @@ function withAncestor(context, cls) {
46
49
  _ancestors: new Set([...ancestors, cls])
47
50
  };
48
51
  }
52
+ /** Walks the prototype chain and returns all classes from `target` up to (but not including) `Function.prototype`. */
49
53
  function getClassHierarchy(target) {
50
54
  const hierarchy = [];
51
55
  let current = target;
@@ -55,6 +59,15 @@ function getClassHierarchy(target) {
55
59
  }
56
60
  return hierarchy;
57
61
  }
62
+ /**
63
+ * Creates one fully populated instance of `EntityClass` in memory.
64
+ *
65
+ * Runs in three steps:
66
+ * 1. Factory-decorated properties (`@Seed(factory)`) — run first, in declaration order.
67
+ * 2. Embedded types (`@Embedded`) — auto-seeded if the embedded class has any `@Seed` entries.
68
+ * 3. Bare relation decorators (`@Seed()` without a factory) — skipped when `relations` is `false`,
69
+ * and also skipped for any related class already present in the ancestor chain (circular guard).
70
+ */
58
71
  async function createOneSeed(EntityClass, context) {
59
72
  const instance = new EntityClass();
60
73
  const ancestors = getAncestors(context);
@@ -118,6 +131,11 @@ async function createManySeed(classOrClasses, { count, ...context }) {
118
131
  }
119
132
  //#endregion
120
133
  //#region src/seed/persist.ts
134
+ /**
135
+ * Walks an entity object graph and collects every unique entity class encountered.
136
+ * Used to discover all entity classes that need cascade-insert temporarily enabled
137
+ * before saving so that the full in-memory graph is persisted in one shot.
138
+ */
121
139
  function collectEntityClasses(entity, visited = /* @__PURE__ */ new Set()) {
122
140
  const EntityClass = entity.constructor;
123
141
  if (visited.has(EntityClass)) return [];
@@ -128,6 +146,16 @@ function collectEntityClasses(entity, visited = /* @__PURE__ */ new Set()) {
128
146
  } else if (value && typeof value === "object" && value.constructor !== Object) classes.push(...collectEntityClasses(value, visited));
129
147
  return classes;
130
148
  }
149
+ /**
150
+ * Temporarily enables `isCascadeInsert` on every TypeORM relation for the given class.
151
+ * Returns the previous flag values so they can be restored after saving.
152
+ *
153
+ * This is necessary because the seeder builds the full object graph in memory before
154
+ * calling `save()`. Without cascade inserts, TypeORM would only persist the root entity
155
+ * and ignore any nested relations that weren't already configured with `cascade: true`.
156
+ *
157
+ * Classes not registered as TypeORM entities (e.g. embedded value objects) are silently skipped.
158
+ */
131
159
  function enableCascadeInsert(EntityClass, dataSource) {
132
160
  const states = [];
133
161
  try {
@@ -142,6 +170,10 @@ function enableCascadeInsert(EntityClass, dataSource) {
142
170
  } catch {}
143
171
  return states;
144
172
  }
173
+ /**
174
+ * Restores `isCascadeInsert` flags to their original values.
175
+ * Always called in a `finally` block to guarantee cleanup even when saving throws.
176
+ */
145
177
  function restoreCascade(states) {
146
178
  for (const { relation, original } of states) relation.isCascadeInsert = original;
147
179
  }
@@ -170,6 +202,11 @@ async function saveManySeed(classOrClasses, options) {
170
202
  }
171
203
  return await saveManySeedOne(classOrClasses, options);
172
204
  }
205
+ /**
206
+ * Creates and persists `count` instances of a single entity class.
207
+ * Enables cascade inserts on every entity class in the object graph before saving,
208
+ * then restores the original flags — regardless of whether the save succeeds or fails.
209
+ */
173
210
  async function saveManySeedOne(EntityClass, options) {
174
211
  const { count, dataSource } = options;
175
212
  if (count === 0) return [];
@@ -217,14 +254,30 @@ function seed(classOrClasses) {
217
254
  //#endregion
218
255
  //#region src/seeder/registry.ts
219
256
  const registry = /* @__PURE__ */ new WeakMap();
257
+ /** Registers seeder metadata for the given class constructor. Called internally by the `@Seeder` decorator. */
220
258
  function registerSeeder(target, meta) {
221
259
  registry.set(target, meta);
222
260
  }
261
+ /** Returns the metadata registered for the given seeder class, or `undefined` if not registered. */
223
262
  function getSeederMeta(target) {
224
263
  return registry.get(target);
225
264
  }
226
265
  //#endregion
227
266
  //#region src/seeder/decorator.ts
267
+ /**
268
+ * Marks a class as a seeder and registers its dependency metadata.
269
+ *
270
+ * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves
271
+ * all transitive dependencies, sorts them topologically, and executes them in order.
272
+ *
273
+ * @example
274
+ * @Seeder({ dependencies: [UserSeeder] })
275
+ * class PostSeeder implements SeederInterface {
276
+ * async run(ctx: SeedContext) {
277
+ * await seed(Post).saveMany(50, ctx)
278
+ * }
279
+ * }
280
+ */
228
281
  function Seeder(options = {}) {
229
282
  return (target) => {
230
283
  registerSeeder(target, { dependencies: options.dependencies ?? [] });
@@ -232,6 +285,12 @@ function Seeder(options = {}) {
232
285
  }
233
286
  //#endregion
234
287
  //#region src/seeder/runner.ts
288
+ /**
289
+ * Topologically sorts the given seeders and all their transitive dependencies.
290
+ * BFS walks from the roots to collect all nodes, then dependency edges are wired and
291
+ * the graph is sorted so that every dependency precedes the seeders that depend on it.
292
+ * Throws a descriptive error if a circular dependency is detected.
293
+ */
235
294
  function topoSort(roots) {
236
295
  const graph = new DepGraph();
237
296
  const byName = /* @__PURE__ */ new Map();
@@ -256,6 +315,24 @@ function topoSort(roots) {
256
315
  throw err;
257
316
  }
258
317
  }
318
+ /**
319
+ * Runs the given seeders (and all their transitive dependencies) in dependency order.
320
+ *
321
+ * Each seeder is instantiated, its `run` method is called with the context derived
322
+ * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called
323
+ * around it. Errors are re-thrown after `onError` returns.
324
+ *
325
+ * @example
326
+ * await runSeeders([PostSeeder], { dataSource })
327
+ *
328
+ * @example
329
+ * // With lifecycle hooks and no console output
330
+ * await runSeeders([PostSeeder], {
331
+ * dataSource,
332
+ * logging: false,
333
+ * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),
334
+ * })
335
+ */
259
336
  async function runSeeders(seeders, options = {}) {
260
337
  const { logging = true, onBefore, onAfter, onError, skip, ...context } = options;
261
338
  for (const SeederClass of topoSort(seeders)) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["registry"],"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\nexport interface SeedContext {\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/** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */\nexport type SeedFactory<T = unknown> = (context: SeedContext) => T | Promise<T>;\n\n/** Options passed to @Seed. */\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\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/** Mark a relation property for auto-seeding (creates one related entity). */\nexport function Seed(): PropertyDecorator;\n/** Mark a relation property for auto-seeding with options (e.g. count for one-to-many). */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/** Mark a scalar property with a factory callback. */\nexport function Seed(factory: SeedFactory): PropertyDecorator;\n/** Mark a scalar property with a factory callback and 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\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\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\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\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);\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\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\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\nexport interface SaveSeedOptions extends SeedContext {\n dataSource: DataSource;\n}\n\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\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\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\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\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\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\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\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\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\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\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\nexport interface SeederOptions {\n dependencies?: (new () => SeederInterface)[];\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\nexport type SeederCtor = new () => SeederInterface;\n\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\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\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.mjs","names":["registry"],"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/** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */\nexport type SeedFactory<T = unknown> = (context: SeedContext) => 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);\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":";;;AA2DA,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;;;;AC1CT,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;;;;;;ACjCzF,SAAS,aAAa,SAAqC;AACzD,QAAQ,QAA4B,8BAAc,IAAI,KAAK;;;AAI7D,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,cACb,aACA,SACY;CACZ,MAAM,WAAW,IAAI,aAAa;CAClC,MAAM,YAAY,aAAa,QAAQ;CACvC,MAAM,eAAe,aAAa,SAAS,YAAY;CACvD,MAAM,UAAU,wBAAwB;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,QAAQ;AAC5C,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,cAAc,eAAe,QAAQ;AAC3E,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,eAAe,cAAc;GACvD,OAAO,QAAQ,SAAS;GACxB,GAAG;GACJ,CAAC;MAEF,QAAO,eAAe,MAAM,cAAc,cAAc,aAAa;AAGvE,mBAAiB,IAAI,YAAY;;AAGnC,QAAO;;AAkBT,eAAsB,WACpB,gBACA,UAAuB,EAAE,EACM;AAC/B,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAgC;GAAE,WAAW;GAAO,GAAG;GAAS;AAEtE,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAAQ,cAAc,KAAK,iBAAiB,CAAC,CAC3F;;CAGH,MAAM,CAAC,UAAU,MAAM,eAAe,gBAAwC;EAC5E,OAAO;EACP,GAAG;EACJ,CAAC;AAEF,QAAO;;AAkBT,eAAsB,eACpB,gBACA,EAAE,OAAO,GAAG,WACuB;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,cAAc,KAAK,iBAAiB,CAAC,CAAC,CACvF,CACF;;AAGH,QAAO,MAAM,QAAQ,IACnB,MAAM,KAAK,EAAE,QAAQ,OAAO,QAC1B,cAAc,gBAAwC,QAAQ,CAC/D,CACF;;;;;;;;;ACrKH,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;;AAoB/B,eAAsB,SACpB,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,aAAa,KAAK,iBAAiB,CAAC,MAAM,CAAC,YAAY,OAAQ,CAChE,CACF;;CAGH,MAAM,CAAC,UAAU,MAAM,aAAa,gBAAwC;EAC1E,GAAG;EACH,OAAO;EACR,CAAC;AAEF,QAAO;;AAmBT,eAAsB,aACpB,gBACA,SACmC;AACnC,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAmB;GAAE,WAAW;GAAO,GAAG;GAAS;AAEzD,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAAQ,gBAAgB,KAAK,iBAAiB,CAAC,CAC7F;;AAGH,QAAO,MAAM,gBAAgB,gBAAwC,QAAQ;;;;;;;AAQ/E,eAAe,gBACb,aACA,SACc;CACd,MAAM,EAAE,OAAO,eAAe;AAE9B,KAAI,UAAU,EACZ,QAAO,EAAE;CAGX,MAAM,WAAW,MAAM,eAAe,aAAa,QAAQ;CAE3D,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;;;;;ACnI1B,SAAgB,KACd,gBACyD;AACzD,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,UAAU;AAEhB,SAAO;GACL,SAAS,YACP,WAAW,SAAgC,QAAQ;GAGrD,OAAO,YACL,SAAS,SAAgC,QAAQ;GAGnD,aAAa,OAAe,YAC1B,eAAe,SAAgC;IAAE;IAAO,GAAG;IAAS,CAAC;GAGvE,WAAW,OAAe,YACxB,aAAa,SAAgC;IAAE;IAAO,GAAG;IAAS,CAAC;GAGtE;;CAGH,MAAM,cAAc;AAEpB,QAAO;EACL,SAAS,YAA0B,WAAW,aAAa,QAAQ;EACnE,OAAO,YAA6B,SAAS,aAAa,QAAQ;EAClE,aAAa,OAAe,YAC1B,eAAe,aAAa;GAAE;GAAO,GAAG;GAAS,CAAC;EACpD,WAAW,OAAe,YACxB,aAAa,aAAa;GAAE;GAAO,GAAG;GAAS,CAAC;EACnD;;;;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,IAAI,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joakimbugge/typeorm-seeder",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Decorator-based seeder library for TypeORM",
5
5
  "repository": {
6
6
  "type": "git",
@@ -55,11 +55,8 @@
55
55
  "typeorm": ">=0.3.0"
56
56
  },
57
57
  "devDependencies": {
58
- "@faker-js/faker": "^10.4.0",
59
- "@types/better-sqlite3": "^7.6.13",
60
- "better-sqlite3": "^12.8.0",
61
58
  "reflect-metadata": "^0.2.2",
62
- "typeorm": "1.0.0-beta.1"
59
+ "typeorm": "1.0.0-nightly.20260327"
63
60
  },
64
61
  "dependencies": {
65
62
  "dependency-graph": "^1.0.0"