@joakimbugge/nest-typeorm-seeder 0.2.0 → 0.3.0

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
@@ -1,10 +1,20 @@
1
1
  # @joakimbugge/nest-typeorm-seeder
2
2
 
3
- NestJS module for [@joakimbugge/typeorm-seeder](../typeorm-seeder). Runs your `@Seeder` classes automatically on application bootstrap — once per seeder by default, tracked in a database table so watch-mode restarts do not re-seed.
3
+ NestJS module for [@joakimbugge/typeorm-seeder](../typeorm-seeder). Runs your `@Seeder` classes automatically on application bootstrap — once per seeder by default, tracked in a database table so watch-mode restarts do not re-seed. For simple cases, a `run` callback lets you seed without any class boilerplate.
4
4
 
5
5
  > [!TIP]
6
6
  > This package handles the NestJS integration. The seeding itself — `@Seed()`, `@Seeder`, `seed()`, entity factories — is all defined in [@joakimbugge/typeorm-seeder](../typeorm-seeder/README.md). Familiarity with that package will make this one much easier to use.
7
7
 
8
+ Coded by AI. Reviewed by humans.
9
+
10
+ ---
11
+
12
+ - [Installation](#installation)
13
+ - [Basic usage](#basic-usage)
14
+ - [Running once](#running-once)
15
+ - [Seed scripts](#seed-scripts)
16
+ - [API reference](#api-reference)
17
+
8
18
  ---
9
19
 
10
20
  ## Installation
@@ -88,6 +98,20 @@ When TypeORM's `dropSchema: true` is set, the entire schema — including the `s
88
98
 
89
99
  `dropSchema: true` is typical in development when you want a clean slate on every restart — seeding every run is exactly what you want in that scenario. `runOnce: true` with a persistent schema is the right default for staging and production, where duplicate data is the concern.
90
100
 
101
+ ### Evolving seed data
102
+
103
+ Treat seeders the way you treat migrations: once a seeder has run in a persistent environment, consider it immutable. If you need more data or different data, create a new seeder class rather than editing the existing one:
104
+
105
+ ```ts
106
+ @Seeder()
107
+ class UserSeeder implements SeederInterface { ... } // already ran, leave it alone
108
+
109
+ @Seeder({ dependencies: [UserSeeder] })
110
+ class UserSeederV2 implements SeederInterface { ... } // adds more users on next boot
111
+ ```
112
+
113
+ This keeps the history table accurate and avoids the question of what re-running a seeder would mean for data that already exists. This applies to environments where `dropSchema: false` and `runOnce: true` — in development with `dropSchema: true`, the schema is wiped on every restart anyway.
114
+
91
115
  ### Re-seeding
92
116
 
93
117
  To force a seeder to run again, delete its row from the `seeders` table:
@@ -107,6 +131,41 @@ DELETE FROM "seeders";
107
131
 
108
132
  ---
109
133
 
134
+ ## Seed scripts
135
+
136
+ For simple cases where named, tracked seeders are more structure than you need, provide a `run` callback instead. It receives the resolved `DataSource` and executes on every boot — no run-once tracking applies:
137
+
138
+ ```ts
139
+ SeederModule.forRoot({
140
+ async run({ dataSource }) {
141
+ await seed(User).saveMany(10, { dataSource })
142
+ },
143
+ })
144
+ ```
145
+
146
+ `run` is the escape hatch for seeding that should always happen. If you need run-once semantics, the named `@Seeder` pattern is the right tool.
147
+
148
+ > [!NOTE]
149
+ > Because `run` always executes, `runOnce` is not accepted when `seeders` is omitted — TypeScript will reject it at compile time.
150
+
151
+ ### Using both together
152
+
153
+ `seeders` and `run` can coexist. Seeders run first (sorted, tracked per their `runOnce` setting), then `run` is called. This means the callback can safely assume seeder data is already in place:
154
+
155
+ ```ts
156
+ SeederModule.forRoot({
157
+ seeders: [UserSeeder],
158
+ async run({ dataSource }) {
159
+ // UserSeeder has already run
160
+ await seed(AdminUser).save({ dataSource })
161
+ },
162
+ })
163
+ ```
164
+
165
+ `runOnce` applies only to `seeders` — `run` always executes regardless.
166
+
167
+ ---
168
+
110
169
  ## API reference
111
170
 
112
171
  ### `SeederModule.forRoot(options)`
@@ -129,15 +188,36 @@ Registers the module with options resolved from the DI container.
129
188
 
130
189
  ### `SeederModuleOptions`
131
190
 
191
+ `SeederModuleOptions` is a discriminated union with two shapes depending on which properties are provided.
192
+
193
+ **Shared properties** (available in both shapes)
194
+
132
195
  | Property | Type | Default | Description |
133
196
  |---|---|---|---|
134
- | `seeders` | `SeederCtor[]` | — | Seeder classes to run. Transitive dependencies are resolved automatically. |
135
197
  | `dataSource` | `DataSource?` | — | Explicit DataSource. When omitted, the module resolves the DataSource registered by `TypeOrmModule`. |
136
198
  | `relations` | `boolean?` | `true` | Passed through to `runSeeders`. Set to `false` to skip relation seeding. |
137
199
  | `enabled` | `boolean?` | `true` | When `false`, seeding is skipped entirely. Useful for gating on an environment variable. |
200
+ | `onBefore` | `(seeder) => void \| Promise<void>` | — | Called before each seeder runs. |
201
+ | `onAfter` | `(seeder, durationMs) => void \| Promise<void>` | — | Called after each seeder completes successfully. |
202
+ | `onError` | `(seeder, error) => void \| Promise<void>` | — | Called when a seeder throws. The error is still re-thrown after this returns. |
203
+
204
+ The hooks behave identically to the hooks in [`runSeeders`](../typeorm-seeder/README.md#hooks) and are passed through to it directly.
205
+
206
+ **With `seeders`** — `run` is optional; `runOnce` and `historyTableName` apply
207
+
208
+ | Property | Type | Default | Description |
209
+ |---|---|---|---|
210
+ | `seeders` | `SeederCtor[]` | — | Seeder classes to run. Transitive dependencies are resolved automatically. |
211
+ | `run` | `RunCallback?` | — | Inline callback executed after all seeders. Always runs — `runOnce` does not apply to it. |
138
212
  | `runOnce` | `boolean?` | `true` | Track executed seeders in the database and skip them on subsequent boots. |
139
213
  | `historyTableName` | `string?` | `'seeders'` | Name of the table used to track which seeders have run. |
140
214
 
215
+ **With `run` only** — no `seeders`, no `runOnce`
216
+
217
+ | Property | Type | Description |
218
+ |---|---|---|
219
+ | `run` | `RunCallback` | Inline callback executed on every boot. No run-once tracking is applied. |
220
+
141
221
  ---
142
222
 
143
223
  ## License
package/dist/index.cjs CHANGED
@@ -36,29 +36,39 @@ let SeederRunnerService = _SeederRunnerService = class SeederRunnerService {
36
36
  async onApplicationBootstrap() {
37
37
  if (this.options.enabled === false) return;
38
38
  const dataSource = await this.resolveDataSource();
39
- const runOnce = this.options.runOnce ?? true;
40
- const tableName = this.options.historyTableName ?? DEFAULT_HISTORY_TABLE;
41
- let executedSeeders = /* @__PURE__ */ new Set();
42
- if (runOnce) {
43
- await this.ensureHistoryTable(dataSource, tableName);
44
- executedSeeders = await this.getExecutedSeeders(dataSource, tableName);
39
+ if (this.options.seeders) {
40
+ const runOnce = this.options.runOnce ?? true;
41
+ const tableName = this.options.historyTableName ?? DEFAULT_HISTORY_TABLE;
42
+ let executedSeeders = /* @__PURE__ */ new Set();
43
+ if (runOnce) {
44
+ await this.ensureHistoryTable(dataSource, tableName);
45
+ executedSeeders = await this.getExecutedSeeders(dataSource, tableName);
46
+ }
47
+ await (0, _joakimbugge_typeorm_seeder.runSeeders)(this.options.seeders, {
48
+ dataSource,
49
+ relations: this.options.relations,
50
+ logging: false,
51
+ skip: (seeder) => {
52
+ const shouldSkip = executedSeeders.has(seeder.name);
53
+ if (shouldSkip) this.logger.log(`[${seeder.name}] Skipping (already run)`);
54
+ return shouldSkip;
55
+ },
56
+ onBefore: async (seeder) => {
57
+ this.logger.log(`[${seeder.name}] Starting...`);
58
+ await this.options.onBefore?.(seeder);
59
+ },
60
+ onAfter: async (seeder, durationMs) => {
61
+ if (runOnce) await this.recordRun(dataSource, tableName, seeder.name);
62
+ this.logger.log(`[${seeder.name}] Done in ${durationMs}ms`);
63
+ await this.options.onAfter?.(seeder, durationMs);
64
+ },
65
+ onError: async (seeder, error) => {
66
+ this.logger.error(`[${seeder.name}] Failed`, error instanceof Error ? error.stack : String(error));
67
+ await this.options.onError?.(seeder, error);
68
+ }
69
+ });
45
70
  }
46
- await (0, _joakimbugge_typeorm_seeder.runSeeders)(this.options.seeders, {
47
- dataSource,
48
- relations: this.options.relations,
49
- logging: false,
50
- skip: (seeder) => {
51
- const shouldSkip = executedSeeders.has(seeder.name);
52
- if (shouldSkip) this.logger.log(`[${seeder.name}] Skipping (already run)`);
53
- return shouldSkip;
54
- },
55
- onBefore: (seeder) => this.logger.log(`[${seeder.name}] Starting...`),
56
- onAfter: async (seeder, durationMs) => {
57
- if (runOnce) await this.recordRun(dataSource, tableName, seeder.name);
58
- this.logger.log(`[${seeder.name}] Done in ${durationMs}ms`);
59
- },
60
- onError: (seeder, error) => this.logger.error(`[${seeder.name}] Failed`, error instanceof Error ? error.stack : String(error))
61
- });
71
+ if (this.options.run) await this.options.run({ dataSource });
62
72
  }
63
73
  async ensureHistoryTable(dataSource, tableName) {
64
74
  await dataSource.query(`CREATE TABLE IF NOT EXISTS "${tableName}" (name VARCHAR(255) PRIMARY KEY NOT NULL, executed_at VARCHAR(32) NOT NULL)`);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["Logger","DataSource"],"sources":["../src/SeederRunnerService.ts","../src/SeederModule.ts"],"sourcesContent":["import { Inject, Injectable, Logger, type OnApplicationBootstrap } from '@nestjs/common';\nimport { ModuleRef } from '@nestjs/core';\nimport { runSeeders } from '@joakimbugge/typeorm-seeder';\nimport { DataSource } from 'typeorm';\nimport type { SeederModuleOptions } from './SeederModule.js';\n\nexport const SEEDER_MODULE_OPTIONS = Symbol('SEEDER_MODULE_OPTIONS');\n\nconst DEFAULT_HISTORY_TABLE = 'seeders';\n\n@Injectable()\nexport class SeederRunnerService implements OnApplicationBootstrap {\n private readonly logger = new Logger(SeederRunnerService.name);\n\n constructor(\n @Inject(SEEDER_MODULE_OPTIONS) private readonly options: SeederModuleOptions,\n private readonly moduleRef: ModuleRef,\n ) {}\n\n async onApplicationBootstrap(): Promise<void> {\n if (this.options.enabled === false) {\n return;\n }\n\n const dataSource = await this.resolveDataSource();\n const runOnce = this.options.runOnce ?? true;\n const tableName = this.options.historyTableName ?? DEFAULT_HISTORY_TABLE;\n\n let executedSeeders = new Set<string>();\n\n if (runOnce) {\n await this.ensureHistoryTable(dataSource, tableName);\n executedSeeders = await this.getExecutedSeeders(dataSource, tableName);\n }\n\n await runSeeders(this.options.seeders, {\n dataSource,\n relations: this.options.relations,\n logging: false,\n skip: (seeder) => {\n const shouldSkip = executedSeeders.has(seeder.name);\n\n if (shouldSkip) {\n this.logger.log(`[${seeder.name}] Skipping (already run)`);\n }\n\n return shouldSkip;\n },\n onBefore: (seeder) => this.logger.log(`[${seeder.name}] Starting...`),\n onAfter: async (seeder, durationMs) => {\n if (runOnce) {\n await this.recordRun(dataSource, tableName, seeder.name);\n }\n\n this.logger.log(`[${seeder.name}] Done in ${durationMs}ms`);\n },\n onError: (seeder, error) =>\n this.logger.error(\n `[${seeder.name}] Failed`,\n error instanceof Error ? error.stack : String(error),\n ),\n });\n }\n\n private async ensureHistoryTable(dataSource: DataSource, tableName: string): Promise<void> {\n await dataSource.query(\n `CREATE TABLE IF NOT EXISTS \"${tableName}\" (name VARCHAR(255) PRIMARY KEY NOT NULL, executed_at VARCHAR(32) NOT NULL)`,\n );\n }\n\n private async getExecutedSeeders(\n dataSource: DataSource,\n tableName: string,\n ): Promise<Set<string>> {\n const rows: { name: string }[] = await dataSource.query(`SELECT name FROM \"${tableName}\"`);\n\n return new Set(rows.map((r) => r.name));\n }\n\n private async recordRun(dataSource: DataSource, tableName: string, name: string): Promise<void> {\n const executedAt = new Date().toISOString();\n\n await dataSource.query(\n `INSERT INTO \"${tableName}\" (name, executed_at) VALUES ('${name}', '${executedAt}')`,\n );\n }\n\n private async resolveDataSource(): Promise<DataSource> {\n if (this.options.dataSource) {\n return this.options.dataSource;\n }\n\n try {\n return this.moduleRef.get(DataSource, { strict: false });\n } catch {\n throw new Error(\n 'SeederModule could not resolve a DataSource. Either import TypeOrmModule or provide a dataSource in SeederModule options.',\n );\n }\n }\n}\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport type { SeederInterface } from '@joakimbugge/typeorm-seeder';\nimport type { DataSource } from 'typeorm';\nimport { SeederRunnerService, SEEDER_MODULE_OPTIONS } from './SeederRunnerService.js';\n\nexport type SeederCtor = new () => SeederInterface;\n\nexport interface SeederModuleOptions {\n seeders: SeederCtor[];\n dataSource?: DataSource;\n relations?: boolean;\n /**\n * When `false`, seeding is skipped entirely. Useful for gating on an env var.\n *\n * @default true\n */\n enabled?: boolean;\n /**\n * Track executed seeders in a database table and skip them on subsequent boots.\n * Set to `false` to always run every seeder regardless.\n *\n * When TypeORM's `dropSchema` is `true`, the history table is dropped with the\n * rest of the schema on every start, so all seeders run regardless of this setting.\n *\n * @default true\n */\n runOnce?: boolean;\n /**\n * Name of the table used to track which seeders have run.\n *\n * @default 'seeders'\n */\n historyTableName?: string;\n}\n\nexport interface SeederModuleAsyncOptions {\n imports?: any[];\n inject?: any[];\n useFactory: (...args: any[]) => SeederModuleOptions | Promise<SeederModuleOptions>;\n}\n\n@Module({})\nexport class SeederModule {\n static forRoot(options: SeederModuleOptions): DynamicModule {\n return {\n module: SeederModule,\n providers: [{ provide: SEEDER_MODULE_OPTIONS, useValue: options }, SeederRunnerService],\n };\n }\n\n static forRootAsync(options: SeederModuleAsyncOptions): DynamicModule {\n return {\n module: SeederModule,\n imports: options.imports ?? [],\n providers: [\n {\n provide: SEEDER_MODULE_OPTIONS,\n inject: options.inject ?? [],\n useFactory: options.useFactory,\n },\n SeederRunnerService,\n ],\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,MAAa,wBAAwB,OAAO,wBAAwB;AAEpE,MAAM,wBAAwB;AAGvB,IAAA,sBAAA,uBAAA,MAAM,oBAAsD;CAGjE,YACE,SACA,WACA;AAFgD,OAAA,UAAA;AAC/B,OAAA,YAAA;gBAJO,IAAIA,eAAAA,OAAAA,qBAA2B,KAAK;;CAO9D,MAAM,yBAAwC;AAC5C,MAAI,KAAK,QAAQ,YAAY,MAC3B;EAGF,MAAM,aAAa,MAAM,KAAK,mBAAmB;EACjD,MAAM,UAAU,KAAK,QAAQ,WAAW;EACxC,MAAM,YAAY,KAAK,QAAQ,oBAAoB;EAEnD,IAAI,kCAAkB,IAAI,KAAa;AAEvC,MAAI,SAAS;AACX,SAAM,KAAK,mBAAmB,YAAY,UAAU;AACpD,qBAAkB,MAAM,KAAK,mBAAmB,YAAY,UAAU;;AAGxE,SAAA,GAAA,4BAAA,YAAiB,KAAK,QAAQ,SAAS;GACrC;GACA,WAAW,KAAK,QAAQ;GACxB,SAAS;GACT,OAAO,WAAW;IAChB,MAAM,aAAa,gBAAgB,IAAI,OAAO,KAAK;AAEnD,QAAI,WACF,MAAK,OAAO,IAAI,IAAI,OAAO,KAAK,0BAA0B;AAG5D,WAAO;;GAET,WAAW,WAAW,KAAK,OAAO,IAAI,IAAI,OAAO,KAAK,eAAe;GACrE,SAAS,OAAO,QAAQ,eAAe;AACrC,QAAI,QACF,OAAM,KAAK,UAAU,YAAY,WAAW,OAAO,KAAK;AAG1D,SAAK,OAAO,IAAI,IAAI,OAAO,KAAK,YAAY,WAAW,IAAI;;GAE7D,UAAU,QAAQ,UAChB,KAAK,OAAO,MACV,IAAI,OAAO,KAAK,WAChB,iBAAiB,QAAQ,MAAM,QAAQ,OAAO,MAAM,CACrD;GACJ,CAAC;;CAGJ,MAAc,mBAAmB,YAAwB,WAAkC;AACzF,QAAM,WAAW,MACf,+BAA+B,UAAU,8EAC1C;;CAGH,MAAc,mBACZ,YACA,WACsB;EACtB,MAAM,OAA2B,MAAM,WAAW,MAAM,qBAAqB,UAAU,GAAG;AAE1F,SAAO,IAAI,IAAI,KAAK,KAAK,MAAM,EAAE,KAAK,CAAC;;CAGzC,MAAc,UAAU,YAAwB,WAAmB,MAA6B;EAC9F,MAAM,8BAAa,IAAI,MAAM,EAAC,aAAa;AAE3C,QAAM,WAAW,MACf,gBAAgB,UAAU,iCAAiC,KAAK,MAAM,WAAW,IAClF;;CAGH,MAAc,oBAAyC;AACrD,MAAI,KAAK,QAAQ,WACf,QAAO,KAAK,QAAQ;AAGtB,MAAI;AACF,UAAO,KAAK,UAAU,IAAIC,QAAAA,YAAY,EAAE,QAAQ,OAAO,CAAC;UAClD;AACN,SAAM,IAAI,MACR,4HACD;;;;;iCAvFM;+CAKD,sBAAsB,CAAA;;;;;;AC2B3B,IAAA,eAAA,gBAAA,MAAM,aAAa;CACxB,OAAO,QAAQ,SAA6C;AAC1D,SAAO;GACL,QAAA;GACA,WAAW,CAAC;IAAE,SAAS;IAAuB,UAAU;IAAS,EAAE,oBAAoB;GACxF;;CAGH,OAAO,aAAa,SAAkD;AACpE,SAAO;GACL,QAAA;GACA,SAAS,QAAQ,WAAW,EAAE;GAC9B,WAAW,CACT;IACE,SAAS;IACT,QAAQ,QAAQ,UAAU,EAAE;IAC5B,YAAY,QAAQ;IACrB,EACD,oBACD;GACF;;;sEArBG,EAAE,CAAC,CAAA,EAAA,aAAA"}
1
+ {"version":3,"file":"index.cjs","names":["Logger","DataSource"],"sources":["../src/SeederRunnerService.ts","../src/SeederModule.ts"],"sourcesContent":["import { Inject, Injectable, Logger, type OnApplicationBootstrap } from '@nestjs/common';\nimport { ModuleRef } from '@nestjs/core';\nimport { runSeeders } from '@joakimbugge/typeorm-seeder';\nimport { DataSource } from 'typeorm';\nimport type { SeederModuleOptions } from './SeederModule.js';\n\nexport const SEEDER_MODULE_OPTIONS = Symbol('SEEDER_MODULE_OPTIONS');\n\nconst DEFAULT_HISTORY_TABLE = 'seeders';\n\n@Injectable()\nexport class SeederRunnerService implements OnApplicationBootstrap {\n private readonly logger = new Logger(SeederRunnerService.name);\n\n constructor(\n @Inject(SEEDER_MODULE_OPTIONS) private readonly options: SeederModuleOptions,\n private readonly moduleRef: ModuleRef,\n ) {}\n\n async onApplicationBootstrap(): Promise<void> {\n if (this.options.enabled === false) {\n return;\n }\n\n const dataSource = await this.resolveDataSource();\n\n if (this.options.seeders) {\n const runOnce = this.options.runOnce ?? true;\n const tableName = this.options.historyTableName ?? DEFAULT_HISTORY_TABLE;\n\n let executedSeeders = new Set<string>();\n\n if (runOnce) {\n await this.ensureHistoryTable(dataSource, tableName);\n executedSeeders = await this.getExecutedSeeders(dataSource, tableName);\n }\n\n await runSeeders(this.options.seeders, {\n dataSource,\n relations: this.options.relations,\n logging: false,\n skip: (seeder) => {\n const shouldSkip = executedSeeders.has(seeder.name);\n\n if (shouldSkip) {\n this.logger.log(`[${seeder.name}] Skipping (already run)`);\n }\n\n return shouldSkip;\n },\n onBefore: async (seeder) => {\n this.logger.log(`[${seeder.name}] Starting...`);\n await this.options.onBefore?.(seeder);\n },\n onAfter: async (seeder, durationMs) => {\n if (runOnce) {\n await this.recordRun(dataSource, tableName, seeder.name);\n }\n\n this.logger.log(`[${seeder.name}] Done in ${durationMs}ms`);\n await this.options.onAfter?.(seeder, durationMs);\n },\n onError: async (seeder, error) => {\n this.logger.error(\n `[${seeder.name}] Failed`,\n error instanceof Error ? error.stack : String(error),\n );\n await this.options.onError?.(seeder, error);\n },\n });\n }\n\n if (this.options.run) {\n await this.options.run({ dataSource });\n }\n }\n\n private async ensureHistoryTable(dataSource: DataSource, tableName: string): Promise<void> {\n await dataSource.query(\n `CREATE TABLE IF NOT EXISTS \"${tableName}\" (name VARCHAR(255) PRIMARY KEY NOT NULL, executed_at VARCHAR(32) NOT NULL)`,\n );\n }\n\n private async getExecutedSeeders(\n dataSource: DataSource,\n tableName: string,\n ): Promise<Set<string>> {\n const rows: { name: string }[] = await dataSource.query(`SELECT name FROM \"${tableName}\"`);\n\n return new Set(rows.map((r) => r.name));\n }\n\n private async recordRun(dataSource: DataSource, tableName: string, name: string): Promise<void> {\n const executedAt = new Date().toISOString();\n\n await dataSource.query(\n `INSERT INTO \"${tableName}\" (name, executed_at) VALUES ('${name}', '${executedAt}')`,\n );\n }\n\n private async resolveDataSource(): Promise<DataSource> {\n if (this.options.dataSource) {\n return this.options.dataSource;\n }\n\n try {\n return this.moduleRef.get(DataSource, { strict: false });\n } catch {\n throw new Error(\n 'SeederModule could not resolve a DataSource. Either import TypeOrmModule or provide a dataSource in SeederModule options.',\n );\n }\n }\n}\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport type { RunSeedersOptions, SeederInterface } from '@joakimbugge/typeorm-seeder';\nimport type { DataSource } from 'typeorm';\nimport { SeederRunnerService, SEEDER_MODULE_OPTIONS } from './SeederRunnerService.js';\n\nexport type SeederCtor = new () => SeederInterface;\n\nexport type RunCallback = (ctx: { dataSource: DataSource }) => void | Promise<void>;\n\ninterface SeederModuleBaseOptions extends Pick<\n RunSeedersOptions,\n 'onBefore' | 'onAfter' | 'onError'\n> {\n /**\n * Explicit DataSource. When omitted, the module resolves the DataSource\n * registered by `TypeOrmModule`.\n */\n dataSource?: DataSource;\n /** Passed through to `runSeeders`. Set to `false` to skip relation seeding. */\n relations?: boolean;\n /**\n * When `false`, seeding is skipped entirely. Useful for gating on an env var.\n *\n * @default true\n */\n enabled?: boolean;\n}\n\ninterface SeederModuleSeedersOptions extends SeederModuleBaseOptions {\n /** Seeder classes to run. Transitive dependencies are resolved automatically. */\n seeders: SeederCtor[];\n /**\n * Inline callback executed after all seeders have run. Always executes on\n * every boot — `runOnce` does not apply to it.\n */\n run?: RunCallback;\n /**\n * Track executed seeders in a database table and skip them on subsequent boots.\n * Set to `false` to always run every seeder regardless.\n *\n * When TypeORM's `dropSchema` is `true`, the history table is dropped with the\n * rest of the schema on every start, so all seeders run regardless of this setting.\n *\n * @default true\n */\n runOnce?: boolean;\n /**\n * Name of the table used to track which seeders have run.\n *\n * @default 'seeders'\n */\n historyTableName?: string;\n}\n\ninterface SeederModuleRunOptions extends SeederModuleBaseOptions {\n seeders?: never;\n /**\n * Inline callback executed on every boot. runOnce is false.\n */\n run: RunCallback;\n runOnce?: false;\n historyTableName?: never;\n}\n\nexport type SeederModuleOptions = SeederModuleSeedersOptions | SeederModuleRunOptions;\n\nexport interface SeederModuleAsyncOptions {\n imports?: any[];\n inject?: any[];\n useFactory: (...args: any[]) => SeederModuleOptions | Promise<SeederModuleOptions>;\n}\n\n@Module({})\nexport class SeederModule {\n static forRoot(options: SeederModuleOptions): DynamicModule {\n return {\n module: SeederModule,\n providers: [{ provide: SEEDER_MODULE_OPTIONS, useValue: options }, SeederRunnerService],\n };\n }\n\n static forRootAsync(options: SeederModuleAsyncOptions): DynamicModule {\n return {\n module: SeederModule,\n imports: options.imports ?? [],\n providers: [\n {\n provide: SEEDER_MODULE_OPTIONS,\n inject: options.inject ?? [],\n useFactory: options.useFactory,\n },\n SeederRunnerService,\n ],\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,MAAa,wBAAwB,OAAO,wBAAwB;AAEpE,MAAM,wBAAwB;AAGvB,IAAA,sBAAA,uBAAA,MAAM,oBAAsD;CAGjE,YACE,SACA,WACA;AAFgD,OAAA,UAAA;AAC/B,OAAA,YAAA;gBAJO,IAAIA,eAAAA,OAAAA,qBAA2B,KAAK;;CAO9D,MAAM,yBAAwC;AAC5C,MAAI,KAAK,QAAQ,YAAY,MAC3B;EAGF,MAAM,aAAa,MAAM,KAAK,mBAAmB;AAEjD,MAAI,KAAK,QAAQ,SAAS;GACxB,MAAM,UAAU,KAAK,QAAQ,WAAW;GACxC,MAAM,YAAY,KAAK,QAAQ,oBAAoB;GAEnD,IAAI,kCAAkB,IAAI,KAAa;AAEvC,OAAI,SAAS;AACX,UAAM,KAAK,mBAAmB,YAAY,UAAU;AACpD,sBAAkB,MAAM,KAAK,mBAAmB,YAAY,UAAU;;AAGxE,UAAA,GAAA,4BAAA,YAAiB,KAAK,QAAQ,SAAS;IACrC;IACA,WAAW,KAAK,QAAQ;IACxB,SAAS;IACT,OAAO,WAAW;KAChB,MAAM,aAAa,gBAAgB,IAAI,OAAO,KAAK;AAEnD,SAAI,WACF,MAAK,OAAO,IAAI,IAAI,OAAO,KAAK,0BAA0B;AAG5D,YAAO;;IAET,UAAU,OAAO,WAAW;AAC1B,UAAK,OAAO,IAAI,IAAI,OAAO,KAAK,eAAe;AAC/C,WAAM,KAAK,QAAQ,WAAW,OAAO;;IAEvC,SAAS,OAAO,QAAQ,eAAe;AACrC,SAAI,QACF,OAAM,KAAK,UAAU,YAAY,WAAW,OAAO,KAAK;AAG1D,UAAK,OAAO,IAAI,IAAI,OAAO,KAAK,YAAY,WAAW,IAAI;AAC3D,WAAM,KAAK,QAAQ,UAAU,QAAQ,WAAW;;IAElD,SAAS,OAAO,QAAQ,UAAU;AAChC,UAAK,OAAO,MACV,IAAI,OAAO,KAAK,WAChB,iBAAiB,QAAQ,MAAM,QAAQ,OAAO,MAAM,CACrD;AACD,WAAM,KAAK,QAAQ,UAAU,QAAQ,MAAM;;IAE9C,CAAC;;AAGJ,MAAI,KAAK,QAAQ,IACf,OAAM,KAAK,QAAQ,IAAI,EAAE,YAAY,CAAC;;CAI1C,MAAc,mBAAmB,YAAwB,WAAkC;AACzF,QAAM,WAAW,MACf,+BAA+B,UAAU,8EAC1C;;CAGH,MAAc,mBACZ,YACA,WACsB;EACtB,MAAM,OAA2B,MAAM,WAAW,MAAM,qBAAqB,UAAU,GAAG;AAE1F,SAAO,IAAI,IAAI,KAAK,KAAK,MAAM,EAAE,KAAK,CAAC;;CAGzC,MAAc,UAAU,YAAwB,WAAmB,MAA6B;EAC9F,MAAM,8BAAa,IAAI,MAAM,EAAC,aAAa;AAE3C,QAAM,WAAW,MACf,gBAAgB,UAAU,iCAAiC,KAAK,MAAM,WAAW,IAClF;;CAGH,MAAc,oBAAyC;AACrD,MAAI,KAAK,QAAQ,WACf,QAAO,KAAK,QAAQ;AAGtB,MAAI;AACF,UAAO,KAAK,UAAU,IAAIC,QAAAA,YAAY,EAAE,QAAQ,OAAO,CAAC;UAClD;AACN,SAAM,IAAI,MACR,4HACD;;;;;iCApGM;+CAKD,sBAAsB,CAAA;;;;;;AC0D3B,IAAA,eAAA,gBAAA,MAAM,aAAa;CACxB,OAAO,QAAQ,SAA6C;AAC1D,SAAO;GACL,QAAA;GACA,WAAW,CAAC;IAAE,SAAS;IAAuB,UAAU;IAAS,EAAE,oBAAoB;GACxF;;CAGH,OAAO,aAAa,SAAkD;AACpE,SAAO;GACL,QAAA;GACA,SAAS,QAAQ,WAAW,EAAE;GAC9B,WAAW,CACT;IACE,SAAS;IACT,QAAQ,QAAQ,UAAU,EAAE;IAC5B,YAAY,QAAQ;IACrB,EACD,oBACD;GACF;;;sEArBG,EAAE,CAAC,CAAA,EAAA,aAAA"}
package/dist/index.d.cts CHANGED
@@ -1,12 +1,19 @@
1
1
  import { DynamicModule } from "@nestjs/common";
2
- import { SeederInterface } from "@joakimbugge/typeorm-seeder";
2
+ import { RunSeedersOptions, SeederInterface } from "@joakimbugge/typeorm-seeder";
3
3
  import { DataSource } from "typeorm";
4
4
 
5
5
  //#region src/SeederModule.d.ts
6
6
  type SeederCtor = new () => SeederInterface;
7
- interface SeederModuleOptions {
8
- seeders: SeederCtor[];
7
+ type RunCallback = (ctx: {
8
+ dataSource: DataSource;
9
+ }) => void | Promise<void>;
10
+ interface SeederModuleBaseOptions extends Pick<RunSeedersOptions, 'onBefore' | 'onAfter' | 'onError'> {
11
+ /**
12
+ * Explicit DataSource. When omitted, the module resolves the DataSource
13
+ * registered by `TypeOrmModule`.
14
+ */
9
15
  dataSource?: DataSource;
16
+ /** Passed through to `runSeeders`. Set to `false` to skip relation seeding. */
10
17
  relations?: boolean;
11
18
  /**
12
19
  * When `false`, seeding is skipped entirely. Useful for gating on an env var.
@@ -14,6 +21,15 @@ interface SeederModuleOptions {
14
21
  * @default true
15
22
  */
16
23
  enabled?: boolean;
24
+ }
25
+ interface SeederModuleSeedersOptions extends SeederModuleBaseOptions {
26
+ /** Seeder classes to run. Transitive dependencies are resolved automatically. */
27
+ seeders: SeederCtor[];
28
+ /**
29
+ * Inline callback executed after all seeders have run. Always executes on
30
+ * every boot — `runOnce` does not apply to it.
31
+ */
32
+ run?: RunCallback;
17
33
  /**
18
34
  * Track executed seeders in a database table and skip them on subsequent boots.
19
35
  * Set to `false` to always run every seeder regardless.
@@ -31,6 +47,16 @@ interface SeederModuleOptions {
31
47
  */
32
48
  historyTableName?: string;
33
49
  }
50
+ interface SeederModuleRunOptions extends SeederModuleBaseOptions {
51
+ seeders?: never;
52
+ /**
53
+ * Inline callback executed on every boot. runOnce is false.
54
+ */
55
+ run: RunCallback;
56
+ runOnce?: false;
57
+ historyTableName?: never;
58
+ }
59
+ type SeederModuleOptions = SeederModuleSeedersOptions | SeederModuleRunOptions;
34
60
  interface SeederModuleAsyncOptions {
35
61
  imports?: any[];
36
62
  inject?: any[];
@@ -41,5 +67,5 @@ declare class SeederModule {
41
67
  static forRootAsync(options: SeederModuleAsyncOptions): DynamicModule;
42
68
  }
43
69
  //#endregion
44
- export { type SeederCtor, SeederModule, type SeederModuleAsyncOptions, type SeederModuleOptions };
70
+ export { type RunCallback, type SeederCtor, SeederModule, type SeederModuleAsyncOptions, type SeederModuleOptions };
45
71
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/SeederModule.ts"],"mappings":";;;;;KAKY,UAAA,aAAuB,eAAA;AAAA,UAElB,mBAAA;EACf,OAAA,EAAS,UAAA;EACT,UAAA,GAAa,UAAA;EACb,SAAA;EALiC;;AAEnC;;;EASE,OAAA;EARA;;;;;;;;;EAkBA,OAAA;EASe;;;;;EAHf,gBAAA;AAAA;AAAA,UAGe,wBAAA;EACf,OAAA;EACA,MAAA;EACA,UAAA,MAAgB,IAAA,YAAgB,mBAAA,GAAsB,OAAA,CAAQ,mBAAA;AAAA;AAAA,cAInD,YAAA;EAAA,OACJ,OAAA,CAAQ,OAAA,EAAS,mBAAA,GAAsB,aAAA;EAAA,OAOvC,YAAA,CAAa,OAAA,EAAS,wBAAA,GAA2B,aAAA;AAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/SeederModule.ts"],"mappings":";;;;;KAKY,UAAA,aAAuB,eAAA;AAAA,KAEvB,WAAA,IAAe,GAAA;EAAO,UAAA,EAAY,UAAA;AAAA,aAAwB,OAAA;AAAA,UAE5D,uBAAA,SAAgC,IAAA,CACxC,iBAAA;EALiC;;AAEnC;;EAUE,UAAA,GAAa,UAAA;EAV8D;EAY3E,SAAA;EAZ4C;;;;;EAkB5C,OAAA;AAAA;AAAA,UAGQ,0BAAA,SAAmC,uBAAA;EAlB3C;EAoBA,OAAA,EAAS,UAAA;EArB+B;;;;EA0BxC,GAAA,GAAM,WAAA;EAlBN;;;;;;AAQO;;;EAoBP,OAAA;EAVM;;;;;EAgBN,gBAAA;AAAA;AAAA,UAGQ,sBAAA,SAA+B,uBAAA;EACvC,OAAA;EAVA;;;EAcA,GAAA,EAAK,WAAA;EACL,OAAA;EACA,gBAAA;AAAA;AAAA,KAGU,mBAAA,GAAsB,0BAAA,GAA6B,sBAAA;AAAA,UAE9C,wBAAA;EACf,OAAA;EACA,MAAA;EACA,UAAA,MAAgB,IAAA,YAAgB,mBAAA,GAAsB,OAAA,CAAQ,mBAAA;AAAA;AAAA,cAInD,YAAA;EAAA,OACJ,OAAA,CAAQ,OAAA,EAAS,mBAAA,GAAsB,aAAA;EAAA,OAOvC,YAAA,CAAa,OAAA,EAAS,wBAAA,GAA2B,aAAA;AAAA"}
package/dist/index.d.mts CHANGED
@@ -1,12 +1,19 @@
1
1
  import { DynamicModule } from "@nestjs/common";
2
- import { SeederInterface } from "@joakimbugge/typeorm-seeder";
2
+ import { RunSeedersOptions, SeederInterface } from "@joakimbugge/typeorm-seeder";
3
3
  import { DataSource } from "typeorm";
4
4
 
5
5
  //#region src/SeederModule.d.ts
6
6
  type SeederCtor = new () => SeederInterface;
7
- interface SeederModuleOptions {
8
- seeders: SeederCtor[];
7
+ type RunCallback = (ctx: {
8
+ dataSource: DataSource;
9
+ }) => void | Promise<void>;
10
+ interface SeederModuleBaseOptions extends Pick<RunSeedersOptions, 'onBefore' | 'onAfter' | 'onError'> {
11
+ /**
12
+ * Explicit DataSource. When omitted, the module resolves the DataSource
13
+ * registered by `TypeOrmModule`.
14
+ */
9
15
  dataSource?: DataSource;
16
+ /** Passed through to `runSeeders`. Set to `false` to skip relation seeding. */
10
17
  relations?: boolean;
11
18
  /**
12
19
  * When `false`, seeding is skipped entirely. Useful for gating on an env var.
@@ -14,6 +21,15 @@ interface SeederModuleOptions {
14
21
  * @default true
15
22
  */
16
23
  enabled?: boolean;
24
+ }
25
+ interface SeederModuleSeedersOptions extends SeederModuleBaseOptions {
26
+ /** Seeder classes to run. Transitive dependencies are resolved automatically. */
27
+ seeders: SeederCtor[];
28
+ /**
29
+ * Inline callback executed after all seeders have run. Always executes on
30
+ * every boot — `runOnce` does not apply to it.
31
+ */
32
+ run?: RunCallback;
17
33
  /**
18
34
  * Track executed seeders in a database table and skip them on subsequent boots.
19
35
  * Set to `false` to always run every seeder regardless.
@@ -31,6 +47,16 @@ interface SeederModuleOptions {
31
47
  */
32
48
  historyTableName?: string;
33
49
  }
50
+ interface SeederModuleRunOptions extends SeederModuleBaseOptions {
51
+ seeders?: never;
52
+ /**
53
+ * Inline callback executed on every boot. runOnce is false.
54
+ */
55
+ run: RunCallback;
56
+ runOnce?: false;
57
+ historyTableName?: never;
58
+ }
59
+ type SeederModuleOptions = SeederModuleSeedersOptions | SeederModuleRunOptions;
34
60
  interface SeederModuleAsyncOptions {
35
61
  imports?: any[];
36
62
  inject?: any[];
@@ -41,5 +67,5 @@ declare class SeederModule {
41
67
  static forRootAsync(options: SeederModuleAsyncOptions): DynamicModule;
42
68
  }
43
69
  //#endregion
44
- export { type SeederCtor, SeederModule, type SeederModuleAsyncOptions, type SeederModuleOptions };
70
+ export { type RunCallback, type SeederCtor, SeederModule, type SeederModuleAsyncOptions, type SeederModuleOptions };
45
71
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/SeederModule.ts"],"mappings":";;;;;KAKY,UAAA,aAAuB,eAAA;AAAA,UAElB,mBAAA;EACf,OAAA,EAAS,UAAA;EACT,UAAA,GAAa,UAAA;EACb,SAAA;EALiC;;AAEnC;;;EASE,OAAA;EARA;;;;;;;;;EAkBA,OAAA;EASe;;;;;EAHf,gBAAA;AAAA;AAAA,UAGe,wBAAA;EACf,OAAA;EACA,MAAA;EACA,UAAA,MAAgB,IAAA,YAAgB,mBAAA,GAAsB,OAAA,CAAQ,mBAAA;AAAA;AAAA,cAInD,YAAA;EAAA,OACJ,OAAA,CAAQ,OAAA,EAAS,mBAAA,GAAsB,aAAA;EAAA,OAOvC,YAAA,CAAa,OAAA,EAAS,wBAAA,GAA2B,aAAA;AAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/SeederModule.ts"],"mappings":";;;;;KAKY,UAAA,aAAuB,eAAA;AAAA,KAEvB,WAAA,IAAe,GAAA;EAAO,UAAA,EAAY,UAAA;AAAA,aAAwB,OAAA;AAAA,UAE5D,uBAAA,SAAgC,IAAA,CACxC,iBAAA;EALiC;;AAEnC;;EAUE,UAAA,GAAa,UAAA;EAV8D;EAY3E,SAAA;EAZ4C;;;;;EAkB5C,OAAA;AAAA;AAAA,UAGQ,0BAAA,SAAmC,uBAAA;EAlB3C;EAoBA,OAAA,EAAS,UAAA;EArB+B;;;;EA0BxC,GAAA,GAAM,WAAA;EAlBN;;;;;;AAQO;;;EAoBP,OAAA;EAVM;;;;;EAgBN,gBAAA;AAAA;AAAA,UAGQ,sBAAA,SAA+B,uBAAA;EACvC,OAAA;EAVA;;;EAcA,GAAA,EAAK,WAAA;EACL,OAAA;EACA,gBAAA;AAAA;AAAA,KAGU,mBAAA,GAAsB,0BAAA,GAA6B,sBAAA;AAAA,UAE9C,wBAAA;EACf,OAAA;EACA,MAAA;EACA,UAAA,MAAgB,IAAA,YAAgB,mBAAA,GAAsB,OAAA,CAAQ,mBAAA;AAAA;AAAA,cAInD,YAAA;EAAA,OACJ,OAAA,CAAQ,OAAA,EAAS,mBAAA,GAAsB,aAAA;EAAA,OAOvC,YAAA,CAAa,OAAA,EAAS,wBAAA,GAA2B,aAAA;AAAA"}
package/dist/index.mjs CHANGED
@@ -35,29 +35,39 @@ let SeederRunnerService = _SeederRunnerService = class SeederRunnerService {
35
35
  async onApplicationBootstrap() {
36
36
  if (this.options.enabled === false) return;
37
37
  const dataSource = await this.resolveDataSource();
38
- const runOnce = this.options.runOnce ?? true;
39
- const tableName = this.options.historyTableName ?? DEFAULT_HISTORY_TABLE;
40
- let executedSeeders = /* @__PURE__ */ new Set();
41
- if (runOnce) {
42
- await this.ensureHistoryTable(dataSource, tableName);
43
- executedSeeders = await this.getExecutedSeeders(dataSource, tableName);
38
+ if (this.options.seeders) {
39
+ const runOnce = this.options.runOnce ?? true;
40
+ const tableName = this.options.historyTableName ?? DEFAULT_HISTORY_TABLE;
41
+ let executedSeeders = /* @__PURE__ */ new Set();
42
+ if (runOnce) {
43
+ await this.ensureHistoryTable(dataSource, tableName);
44
+ executedSeeders = await this.getExecutedSeeders(dataSource, tableName);
45
+ }
46
+ await runSeeders(this.options.seeders, {
47
+ dataSource,
48
+ relations: this.options.relations,
49
+ logging: false,
50
+ skip: (seeder) => {
51
+ const shouldSkip = executedSeeders.has(seeder.name);
52
+ if (shouldSkip) this.logger.log(`[${seeder.name}] Skipping (already run)`);
53
+ return shouldSkip;
54
+ },
55
+ onBefore: async (seeder) => {
56
+ this.logger.log(`[${seeder.name}] Starting...`);
57
+ await this.options.onBefore?.(seeder);
58
+ },
59
+ onAfter: async (seeder, durationMs) => {
60
+ if (runOnce) await this.recordRun(dataSource, tableName, seeder.name);
61
+ this.logger.log(`[${seeder.name}] Done in ${durationMs}ms`);
62
+ await this.options.onAfter?.(seeder, durationMs);
63
+ },
64
+ onError: async (seeder, error) => {
65
+ this.logger.error(`[${seeder.name}] Failed`, error instanceof Error ? error.stack : String(error));
66
+ await this.options.onError?.(seeder, error);
67
+ }
68
+ });
44
69
  }
45
- await runSeeders(this.options.seeders, {
46
- dataSource,
47
- relations: this.options.relations,
48
- logging: false,
49
- skip: (seeder) => {
50
- const shouldSkip = executedSeeders.has(seeder.name);
51
- if (shouldSkip) this.logger.log(`[${seeder.name}] Skipping (already run)`);
52
- return shouldSkip;
53
- },
54
- onBefore: (seeder) => this.logger.log(`[${seeder.name}] Starting...`),
55
- onAfter: async (seeder, durationMs) => {
56
- if (runOnce) await this.recordRun(dataSource, tableName, seeder.name);
57
- this.logger.log(`[${seeder.name}] Done in ${durationMs}ms`);
58
- },
59
- onError: (seeder, error) => this.logger.error(`[${seeder.name}] Failed`, error instanceof Error ? error.stack : String(error))
60
- });
70
+ if (this.options.run) await this.options.run({ dataSource });
61
71
  }
62
72
  async ensureHistoryTable(dataSource, tableName) {
63
73
  await dataSource.query(`CREATE TABLE IF NOT EXISTS "${tableName}" (name VARCHAR(255) PRIMARY KEY NOT NULL, executed_at VARCHAR(32) NOT NULL)`);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/SeederRunnerService.ts","../src/SeederModule.ts"],"sourcesContent":["import { Inject, Injectable, Logger, type OnApplicationBootstrap } from '@nestjs/common';\nimport { ModuleRef } from '@nestjs/core';\nimport { runSeeders } from '@joakimbugge/typeorm-seeder';\nimport { DataSource } from 'typeorm';\nimport type { SeederModuleOptions } from './SeederModule.js';\n\nexport const SEEDER_MODULE_OPTIONS = Symbol('SEEDER_MODULE_OPTIONS');\n\nconst DEFAULT_HISTORY_TABLE = 'seeders';\n\n@Injectable()\nexport class SeederRunnerService implements OnApplicationBootstrap {\n private readonly logger = new Logger(SeederRunnerService.name);\n\n constructor(\n @Inject(SEEDER_MODULE_OPTIONS) private readonly options: SeederModuleOptions,\n private readonly moduleRef: ModuleRef,\n ) {}\n\n async onApplicationBootstrap(): Promise<void> {\n if (this.options.enabled === false) {\n return;\n }\n\n const dataSource = await this.resolveDataSource();\n const runOnce = this.options.runOnce ?? true;\n const tableName = this.options.historyTableName ?? DEFAULT_HISTORY_TABLE;\n\n let executedSeeders = new Set<string>();\n\n if (runOnce) {\n await this.ensureHistoryTable(dataSource, tableName);\n executedSeeders = await this.getExecutedSeeders(dataSource, tableName);\n }\n\n await runSeeders(this.options.seeders, {\n dataSource,\n relations: this.options.relations,\n logging: false,\n skip: (seeder) => {\n const shouldSkip = executedSeeders.has(seeder.name);\n\n if (shouldSkip) {\n this.logger.log(`[${seeder.name}] Skipping (already run)`);\n }\n\n return shouldSkip;\n },\n onBefore: (seeder) => this.logger.log(`[${seeder.name}] Starting...`),\n onAfter: async (seeder, durationMs) => {\n if (runOnce) {\n await this.recordRun(dataSource, tableName, seeder.name);\n }\n\n this.logger.log(`[${seeder.name}] Done in ${durationMs}ms`);\n },\n onError: (seeder, error) =>\n this.logger.error(\n `[${seeder.name}] Failed`,\n error instanceof Error ? error.stack : String(error),\n ),\n });\n }\n\n private async ensureHistoryTable(dataSource: DataSource, tableName: string): Promise<void> {\n await dataSource.query(\n `CREATE TABLE IF NOT EXISTS \"${tableName}\" (name VARCHAR(255) PRIMARY KEY NOT NULL, executed_at VARCHAR(32) NOT NULL)`,\n );\n }\n\n private async getExecutedSeeders(\n dataSource: DataSource,\n tableName: string,\n ): Promise<Set<string>> {\n const rows: { name: string }[] = await dataSource.query(`SELECT name FROM \"${tableName}\"`);\n\n return new Set(rows.map((r) => r.name));\n }\n\n private async recordRun(dataSource: DataSource, tableName: string, name: string): Promise<void> {\n const executedAt = new Date().toISOString();\n\n await dataSource.query(\n `INSERT INTO \"${tableName}\" (name, executed_at) VALUES ('${name}', '${executedAt}')`,\n );\n }\n\n private async resolveDataSource(): Promise<DataSource> {\n if (this.options.dataSource) {\n return this.options.dataSource;\n }\n\n try {\n return this.moduleRef.get(DataSource, { strict: false });\n } catch {\n throw new Error(\n 'SeederModule could not resolve a DataSource. Either import TypeOrmModule or provide a dataSource in SeederModule options.',\n );\n }\n }\n}\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport type { SeederInterface } from '@joakimbugge/typeorm-seeder';\nimport type { DataSource } from 'typeorm';\nimport { SeederRunnerService, SEEDER_MODULE_OPTIONS } from './SeederRunnerService.js';\n\nexport type SeederCtor = new () => SeederInterface;\n\nexport interface SeederModuleOptions {\n seeders: SeederCtor[];\n dataSource?: DataSource;\n relations?: boolean;\n /**\n * When `false`, seeding is skipped entirely. Useful for gating on an env var.\n *\n * @default true\n */\n enabled?: boolean;\n /**\n * Track executed seeders in a database table and skip them on subsequent boots.\n * Set to `false` to always run every seeder regardless.\n *\n * When TypeORM's `dropSchema` is `true`, the history table is dropped with the\n * rest of the schema on every start, so all seeders run regardless of this setting.\n *\n * @default true\n */\n runOnce?: boolean;\n /**\n * Name of the table used to track which seeders have run.\n *\n * @default 'seeders'\n */\n historyTableName?: string;\n}\n\nexport interface SeederModuleAsyncOptions {\n imports?: any[];\n inject?: any[];\n useFactory: (...args: any[]) => SeederModuleOptions | Promise<SeederModuleOptions>;\n}\n\n@Module({})\nexport class SeederModule {\n static forRoot(options: SeederModuleOptions): DynamicModule {\n return {\n module: SeederModule,\n providers: [{ provide: SEEDER_MODULE_OPTIONS, useValue: options }, SeederRunnerService],\n };\n }\n\n static forRootAsync(options: SeederModuleAsyncOptions): DynamicModule {\n return {\n module: SeederModule,\n imports: options.imports ?? [],\n providers: [\n {\n provide: SEEDER_MODULE_OPTIONS,\n inject: options.inject ?? [],\n useFactory: options.useFactory,\n },\n SeederRunnerService,\n ],\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,MAAa,wBAAwB,OAAO,wBAAwB;AAEpE,MAAM,wBAAwB;AAGvB,IAAA,sBAAA,uBAAA,MAAM,oBAAsD;CAGjE,YACE,SACA,WACA;AAFgD,OAAA,UAAA;AAC/B,OAAA,YAAA;gBAJO,IAAI,OAAA,qBAA2B,KAAK;;CAO9D,MAAM,yBAAwC;AAC5C,MAAI,KAAK,QAAQ,YAAY,MAC3B;EAGF,MAAM,aAAa,MAAM,KAAK,mBAAmB;EACjD,MAAM,UAAU,KAAK,QAAQ,WAAW;EACxC,MAAM,YAAY,KAAK,QAAQ,oBAAoB;EAEnD,IAAI,kCAAkB,IAAI,KAAa;AAEvC,MAAI,SAAS;AACX,SAAM,KAAK,mBAAmB,YAAY,UAAU;AACpD,qBAAkB,MAAM,KAAK,mBAAmB,YAAY,UAAU;;AAGxE,QAAM,WAAW,KAAK,QAAQ,SAAS;GACrC;GACA,WAAW,KAAK,QAAQ;GACxB,SAAS;GACT,OAAO,WAAW;IAChB,MAAM,aAAa,gBAAgB,IAAI,OAAO,KAAK;AAEnD,QAAI,WACF,MAAK,OAAO,IAAI,IAAI,OAAO,KAAK,0BAA0B;AAG5D,WAAO;;GAET,WAAW,WAAW,KAAK,OAAO,IAAI,IAAI,OAAO,KAAK,eAAe;GACrE,SAAS,OAAO,QAAQ,eAAe;AACrC,QAAI,QACF,OAAM,KAAK,UAAU,YAAY,WAAW,OAAO,KAAK;AAG1D,SAAK,OAAO,IAAI,IAAI,OAAO,KAAK,YAAY,WAAW,IAAI;;GAE7D,UAAU,QAAQ,UAChB,KAAK,OAAO,MACV,IAAI,OAAO,KAAK,WAChB,iBAAiB,QAAQ,MAAM,QAAQ,OAAO,MAAM,CACrD;GACJ,CAAC;;CAGJ,MAAc,mBAAmB,YAAwB,WAAkC;AACzF,QAAM,WAAW,MACf,+BAA+B,UAAU,8EAC1C;;CAGH,MAAc,mBACZ,YACA,WACsB;EACtB,MAAM,OAA2B,MAAM,WAAW,MAAM,qBAAqB,UAAU,GAAG;AAE1F,SAAO,IAAI,IAAI,KAAK,KAAK,MAAM,EAAE,KAAK,CAAC;;CAGzC,MAAc,UAAU,YAAwB,WAAmB,MAA6B;EAC9F,MAAM,8BAAa,IAAI,MAAM,EAAC,aAAa;AAE3C,QAAM,WAAW,MACf,gBAAgB,UAAU,iCAAiC,KAAK,MAAM,WAAW,IAClF;;CAGH,MAAc,oBAAyC;AACrD,MAAI,KAAK,QAAQ,WACf,QAAO,KAAK,QAAQ;AAGtB,MAAI;AACF,UAAO,KAAK,UAAU,IAAI,YAAY,EAAE,QAAQ,OAAO,CAAC;UAClD;AACN,SAAM,IAAI,MACR,4HACD;;;;;CAvFN,YAAY;oBAKR,OAAO,sBAAsB,CAAA;;;;;;AC2B3B,IAAA,eAAA,gBAAA,MAAM,aAAa;CACxB,OAAO,QAAQ,SAA6C;AAC1D,SAAO;GACL,QAAA;GACA,WAAW,CAAC;IAAE,SAAS;IAAuB,UAAU;IAAS,EAAE,oBAAoB;GACxF;;CAGH,OAAO,aAAa,SAAkD;AACpE,SAAO;GACL,QAAA;GACA,SAAS,QAAQ,WAAW,EAAE;GAC9B,WAAW,CACT;IACE,SAAS;IACT,QAAQ,QAAQ,UAAU,EAAE;IAC5B,YAAY,QAAQ;IACrB,EACD,oBACD;GACF;;;2CArBJ,OAAO,EAAE,CAAC,CAAA,EAAA,aAAA"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/SeederRunnerService.ts","../src/SeederModule.ts"],"sourcesContent":["import { Inject, Injectable, Logger, type OnApplicationBootstrap } from '@nestjs/common';\nimport { ModuleRef } from '@nestjs/core';\nimport { runSeeders } from '@joakimbugge/typeorm-seeder';\nimport { DataSource } from 'typeorm';\nimport type { SeederModuleOptions } from './SeederModule.js';\n\nexport const SEEDER_MODULE_OPTIONS = Symbol('SEEDER_MODULE_OPTIONS');\n\nconst DEFAULT_HISTORY_TABLE = 'seeders';\n\n@Injectable()\nexport class SeederRunnerService implements OnApplicationBootstrap {\n private readonly logger = new Logger(SeederRunnerService.name);\n\n constructor(\n @Inject(SEEDER_MODULE_OPTIONS) private readonly options: SeederModuleOptions,\n private readonly moduleRef: ModuleRef,\n ) {}\n\n async onApplicationBootstrap(): Promise<void> {\n if (this.options.enabled === false) {\n return;\n }\n\n const dataSource = await this.resolveDataSource();\n\n if (this.options.seeders) {\n const runOnce = this.options.runOnce ?? true;\n const tableName = this.options.historyTableName ?? DEFAULT_HISTORY_TABLE;\n\n let executedSeeders = new Set<string>();\n\n if (runOnce) {\n await this.ensureHistoryTable(dataSource, tableName);\n executedSeeders = await this.getExecutedSeeders(dataSource, tableName);\n }\n\n await runSeeders(this.options.seeders, {\n dataSource,\n relations: this.options.relations,\n logging: false,\n skip: (seeder) => {\n const shouldSkip = executedSeeders.has(seeder.name);\n\n if (shouldSkip) {\n this.logger.log(`[${seeder.name}] Skipping (already run)`);\n }\n\n return shouldSkip;\n },\n onBefore: async (seeder) => {\n this.logger.log(`[${seeder.name}] Starting...`);\n await this.options.onBefore?.(seeder);\n },\n onAfter: async (seeder, durationMs) => {\n if (runOnce) {\n await this.recordRun(dataSource, tableName, seeder.name);\n }\n\n this.logger.log(`[${seeder.name}] Done in ${durationMs}ms`);\n await this.options.onAfter?.(seeder, durationMs);\n },\n onError: async (seeder, error) => {\n this.logger.error(\n `[${seeder.name}] Failed`,\n error instanceof Error ? error.stack : String(error),\n );\n await this.options.onError?.(seeder, error);\n },\n });\n }\n\n if (this.options.run) {\n await this.options.run({ dataSource });\n }\n }\n\n private async ensureHistoryTable(dataSource: DataSource, tableName: string): Promise<void> {\n await dataSource.query(\n `CREATE TABLE IF NOT EXISTS \"${tableName}\" (name VARCHAR(255) PRIMARY KEY NOT NULL, executed_at VARCHAR(32) NOT NULL)`,\n );\n }\n\n private async getExecutedSeeders(\n dataSource: DataSource,\n tableName: string,\n ): Promise<Set<string>> {\n const rows: { name: string }[] = await dataSource.query(`SELECT name FROM \"${tableName}\"`);\n\n return new Set(rows.map((r) => r.name));\n }\n\n private async recordRun(dataSource: DataSource, tableName: string, name: string): Promise<void> {\n const executedAt = new Date().toISOString();\n\n await dataSource.query(\n `INSERT INTO \"${tableName}\" (name, executed_at) VALUES ('${name}', '${executedAt}')`,\n );\n }\n\n private async resolveDataSource(): Promise<DataSource> {\n if (this.options.dataSource) {\n return this.options.dataSource;\n }\n\n try {\n return this.moduleRef.get(DataSource, { strict: false });\n } catch {\n throw new Error(\n 'SeederModule could not resolve a DataSource. Either import TypeOrmModule or provide a dataSource in SeederModule options.',\n );\n }\n }\n}\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport type { RunSeedersOptions, SeederInterface } from '@joakimbugge/typeorm-seeder';\nimport type { DataSource } from 'typeorm';\nimport { SeederRunnerService, SEEDER_MODULE_OPTIONS } from './SeederRunnerService.js';\n\nexport type SeederCtor = new () => SeederInterface;\n\nexport type RunCallback = (ctx: { dataSource: DataSource }) => void | Promise<void>;\n\ninterface SeederModuleBaseOptions extends Pick<\n RunSeedersOptions,\n 'onBefore' | 'onAfter' | 'onError'\n> {\n /**\n * Explicit DataSource. When omitted, the module resolves the DataSource\n * registered by `TypeOrmModule`.\n */\n dataSource?: DataSource;\n /** Passed through to `runSeeders`. Set to `false` to skip relation seeding. */\n relations?: boolean;\n /**\n * When `false`, seeding is skipped entirely. Useful for gating on an env var.\n *\n * @default true\n */\n enabled?: boolean;\n}\n\ninterface SeederModuleSeedersOptions extends SeederModuleBaseOptions {\n /** Seeder classes to run. Transitive dependencies are resolved automatically. */\n seeders: SeederCtor[];\n /**\n * Inline callback executed after all seeders have run. Always executes on\n * every boot — `runOnce` does not apply to it.\n */\n run?: RunCallback;\n /**\n * Track executed seeders in a database table and skip them on subsequent boots.\n * Set to `false` to always run every seeder regardless.\n *\n * When TypeORM's `dropSchema` is `true`, the history table is dropped with the\n * rest of the schema on every start, so all seeders run regardless of this setting.\n *\n * @default true\n */\n runOnce?: boolean;\n /**\n * Name of the table used to track which seeders have run.\n *\n * @default 'seeders'\n */\n historyTableName?: string;\n}\n\ninterface SeederModuleRunOptions extends SeederModuleBaseOptions {\n seeders?: never;\n /**\n * Inline callback executed on every boot. runOnce is false.\n */\n run: RunCallback;\n runOnce?: false;\n historyTableName?: never;\n}\n\nexport type SeederModuleOptions = SeederModuleSeedersOptions | SeederModuleRunOptions;\n\nexport interface SeederModuleAsyncOptions {\n imports?: any[];\n inject?: any[];\n useFactory: (...args: any[]) => SeederModuleOptions | Promise<SeederModuleOptions>;\n}\n\n@Module({})\nexport class SeederModule {\n static forRoot(options: SeederModuleOptions): DynamicModule {\n return {\n module: SeederModule,\n providers: [{ provide: SEEDER_MODULE_OPTIONS, useValue: options }, SeederRunnerService],\n };\n }\n\n static forRootAsync(options: SeederModuleAsyncOptions): DynamicModule {\n return {\n module: SeederModule,\n imports: options.imports ?? [],\n providers: [\n {\n provide: SEEDER_MODULE_OPTIONS,\n inject: options.inject ?? [],\n useFactory: options.useFactory,\n },\n SeederRunnerService,\n ],\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,MAAa,wBAAwB,OAAO,wBAAwB;AAEpE,MAAM,wBAAwB;AAGvB,IAAA,sBAAA,uBAAA,MAAM,oBAAsD;CAGjE,YACE,SACA,WACA;AAFgD,OAAA,UAAA;AAC/B,OAAA,YAAA;gBAJO,IAAI,OAAA,qBAA2B,KAAK;;CAO9D,MAAM,yBAAwC;AAC5C,MAAI,KAAK,QAAQ,YAAY,MAC3B;EAGF,MAAM,aAAa,MAAM,KAAK,mBAAmB;AAEjD,MAAI,KAAK,QAAQ,SAAS;GACxB,MAAM,UAAU,KAAK,QAAQ,WAAW;GACxC,MAAM,YAAY,KAAK,QAAQ,oBAAoB;GAEnD,IAAI,kCAAkB,IAAI,KAAa;AAEvC,OAAI,SAAS;AACX,UAAM,KAAK,mBAAmB,YAAY,UAAU;AACpD,sBAAkB,MAAM,KAAK,mBAAmB,YAAY,UAAU;;AAGxE,SAAM,WAAW,KAAK,QAAQ,SAAS;IACrC;IACA,WAAW,KAAK,QAAQ;IACxB,SAAS;IACT,OAAO,WAAW;KAChB,MAAM,aAAa,gBAAgB,IAAI,OAAO,KAAK;AAEnD,SAAI,WACF,MAAK,OAAO,IAAI,IAAI,OAAO,KAAK,0BAA0B;AAG5D,YAAO;;IAET,UAAU,OAAO,WAAW;AAC1B,UAAK,OAAO,IAAI,IAAI,OAAO,KAAK,eAAe;AAC/C,WAAM,KAAK,QAAQ,WAAW,OAAO;;IAEvC,SAAS,OAAO,QAAQ,eAAe;AACrC,SAAI,QACF,OAAM,KAAK,UAAU,YAAY,WAAW,OAAO,KAAK;AAG1D,UAAK,OAAO,IAAI,IAAI,OAAO,KAAK,YAAY,WAAW,IAAI;AAC3D,WAAM,KAAK,QAAQ,UAAU,QAAQ,WAAW;;IAElD,SAAS,OAAO,QAAQ,UAAU;AAChC,UAAK,OAAO,MACV,IAAI,OAAO,KAAK,WAChB,iBAAiB,QAAQ,MAAM,QAAQ,OAAO,MAAM,CACrD;AACD,WAAM,KAAK,QAAQ,UAAU,QAAQ,MAAM;;IAE9C,CAAC;;AAGJ,MAAI,KAAK,QAAQ,IACf,OAAM,KAAK,QAAQ,IAAI,EAAE,YAAY,CAAC;;CAI1C,MAAc,mBAAmB,YAAwB,WAAkC;AACzF,QAAM,WAAW,MACf,+BAA+B,UAAU,8EAC1C;;CAGH,MAAc,mBACZ,YACA,WACsB;EACtB,MAAM,OAA2B,MAAM,WAAW,MAAM,qBAAqB,UAAU,GAAG;AAE1F,SAAO,IAAI,IAAI,KAAK,KAAK,MAAM,EAAE,KAAK,CAAC;;CAGzC,MAAc,UAAU,YAAwB,WAAmB,MAA6B;EAC9F,MAAM,8BAAa,IAAI,MAAM,EAAC,aAAa;AAE3C,QAAM,WAAW,MACf,gBAAgB,UAAU,iCAAiC,KAAK,MAAM,WAAW,IAClF;;CAGH,MAAc,oBAAyC;AACrD,MAAI,KAAK,QAAQ,WACf,QAAO,KAAK,QAAQ;AAGtB,MAAI;AACF,UAAO,KAAK,UAAU,IAAI,YAAY,EAAE,QAAQ,OAAO,CAAC;UAClD;AACN,SAAM,IAAI,MACR,4HACD;;;;;CApGN,YAAY;oBAKR,OAAO,sBAAsB,CAAA;;;;;;AC0D3B,IAAA,eAAA,gBAAA,MAAM,aAAa;CACxB,OAAO,QAAQ,SAA6C;AAC1D,SAAO;GACL,QAAA;GACA,WAAW,CAAC;IAAE,SAAS;IAAuB,UAAU;IAAS,EAAE,oBAAoB;GACxF;;CAGH,OAAO,aAAa,SAAkD;AACpE,SAAO;GACL,QAAA;GACA,SAAS,QAAQ,WAAW,EAAE;GAC9B,WAAW,CACT;IACE,SAAS;IACT,QAAQ,QAAQ,UAAU,EAAE;IAC5B,YAAY,QAAQ;IACrB,EACD,oBACD;GACF;;;2CArBJ,OAAO,EAAE,CAAC,CAAA,EAAA,aAAA"}
package/package.json CHANGED
@@ -1,73 +1,72 @@
1
- {
2
- "name": "@joakimbugge/nest-typeorm-seeder",
3
- "version": "0.2.0",
4
- "description": "NestJS module for @joakimbugge/typeorm-seeder",
5
- "repository": {
6
- "type": "git",
7
- "url": "git+https://github.com/joakimbugge/to-seeder.git"
8
- },
9
- "homepage": "https://github.com/joakimbugge/to-seeder#readme",
10
- "bugs": "https://github.com/joakimbugge/to-seeder/issues",
11
- "type": "module",
12
- "main": "./dist/index.cjs",
13
- "module": "./dist/index.mjs",
14
- "types": "./dist/index.d.mts",
15
- "exports": {
16
- ".": {
17
- "import": {
18
- "types": "./dist/index.d.mts",
19
- "default": "./dist/index.mjs"
20
- },
21
- "require": {
22
- "types": "./dist/index.d.cts",
23
- "default": "./dist/index.cjs"
24
- }
25
- }
26
- },
27
- "files": [
28
- "dist"
29
- ],
30
- "scripts": {
31
- "build": "tsdown",
32
- "prepublishOnly": "pnpm run build",
33
- "dev": "tsdown --watch",
34
- "typecheck": "tsc --noEmit",
35
- "test": "vitest",
36
- "test:run": "vitest run",
37
- "lint": "oxlint src tests",
38
- "lint:fix": "oxlint --fix src tests",
39
- "fmt": "oxfmt src tests",
40
- "fmt:check": "oxfmt --check src tests"
41
- },
42
- "keywords": [
43
- "typeorm",
44
- "seeder",
45
- "decorator",
46
- "database",
47
- "seed",
48
- "nestjs"
49
- ],
50
- "license": "MIT",
51
- "engines": {
52
- "node": ">=16.13.0"
53
- },
54
- "peerDependencies": {
55
- "@nestjs/common": ">=10.0.0",
56
- "@nestjs/core": ">=10.0.0",
57
- "reflect-metadata": ">=0.1.0",
58
- "typeorm": ">=0.3.0"
59
- },
60
- "devDependencies": {
61
- "@faker-js/faker": "^10.4.0",
62
- "@nestjs/common": "^11.0.0",
63
- "@nestjs/core": "^11.0.0",
64
- "@nestjs/testing": "^11.0.0",
65
- "@types/better-sqlite3": "^7.6.13",
66
- "better-sqlite3": "^12.8.0",
67
- "reflect-metadata": "^0.2.2",
68
- "typeorm": "1.0.0-beta.1"
69
- },
70
- "dependencies": {
71
- "@joakimbugge/typeorm-seeder": "workspace:*"
72
- }
73
- }
1
+ {
2
+ "name": "@joakimbugge/nest-typeorm-seeder",
3
+ "version": "0.3.0",
4
+ "description": "NestJS module for @joakimbugge/typeorm-seeder",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/joakimbugge/to-seeder.git"
8
+ },
9
+ "homepage": "https://github.com/joakimbugge/to-seeder#readme",
10
+ "bugs": "https://github.com/joakimbugge/to-seeder/issues",
11
+ "type": "module",
12
+ "main": "./dist/index.cjs",
13
+ "module": "./dist/index.mjs",
14
+ "types": "./dist/index.d.mts",
15
+ "exports": {
16
+ ".": {
17
+ "import": {
18
+ "types": "./dist/index.d.mts",
19
+ "default": "./dist/index.mjs"
20
+ },
21
+ "require": {
22
+ "types": "./dist/index.d.cts",
23
+ "default": "./dist/index.cjs"
24
+ }
25
+ }
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsdown",
32
+ "prepublishOnly": "pnpm run build",
33
+ "dev": "tsdown --watch",
34
+ "typecheck": "tsc --noEmit",
35
+ "test": "vitest",
36
+ "test:run": "vitest run",
37
+ "lint": "oxlint src tests",
38
+ "lint:fix": "oxlint --fix src tests",
39
+ "fmt": "oxfmt src tests",
40
+ "fmt:check": "oxfmt --check src tests"
41
+ },
42
+ "keywords": [
43
+ "typeorm",
44
+ "seeder",
45
+ "decorator",
46
+ "database",
47
+ "seed",
48
+ "nestjs"
49
+ ],
50
+ "license": "MIT",
51
+ "engines": {
52
+ "node": ">=16.13.0"
53
+ },
54
+ "peerDependencies": {
55
+ "@joakimbugge/typeorm-seeder": ">=0.4.0",
56
+ "@nestjs/common": ">=10.0.0",
57
+ "@nestjs/core": ">=10.0.0",
58
+ "reflect-metadata": ">=0.1.0",
59
+ "typeorm": ">=0.3.0"
60
+ },
61
+ "devDependencies": {
62
+ "@joakimbugge/typeorm-seeder": "workspace:^",
63
+ "@faker-js/faker": "^10.4.0",
64
+ "@nestjs/common": "^11.0.0",
65
+ "@nestjs/core": "^11.0.0",
66
+ "@nestjs/testing": "^11.0.0",
67
+ "@types/better-sqlite3": "^7.6.13",
68
+ "better-sqlite3": "^12.8.0",
69
+ "reflect-metadata": "^0.2.2",
70
+ "typeorm": "1.0.0-beta.1"
71
+ }
72
+ }