@nest-boot/mikro-orm 7.7.1 → 7.7.2

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.
@@ -1,4 +1,4 @@
1
- import { Configuration, IDatabaseDriver } from "@mikro-orm/core";
1
+ import { Configuration, IDatabaseDriver, type Options } from "@mikro-orm/core";
2
2
  /** Constructor type for a MikroORM database driver. */
3
3
  export type DatabaseDriverConstructor = new (config: Configuration) => IDatabaseDriver;
4
4
  /** Database driver configuration for MikroORM. */
@@ -6,7 +6,7 @@ export interface DriverConfig {
6
6
  /** Database driver class constructor. */
7
7
  driver?: DatabaseDriverConstructor;
8
8
  }
9
- /** URL-based database connection configuration. */
9
+ /** URL-based database connection configuration for explicit module options. */
10
10
  export interface UrlConfig {
11
11
  /** Database connection URL. */
12
12
  clientUrl?: string;
@@ -23,15 +23,25 @@ export interface HostConfig {
23
23
  user?: string;
24
24
  /** Database password. */
25
25
  password?: string;
26
+ /** Default database schema. */
27
+ schema?: string;
28
+ /** Driver connection options parsed from URL query parameters. */
29
+ driverOptions?: Options["driverOptions"];
26
30
  }
27
31
  /**
28
32
  * Loads MikroORM configuration from environment variables.
29
33
  *
30
34
  * @remarks
31
- * Supports both connection URL (`DB_URL` / `DATABASE_URL`) and individual
32
- * host/port/dbName/user/password variables. Automatically resolves the
33
- * database driver based on the URL protocol or `DB_TYPE`.
35
+ * Supports `DATABASE_URL`, which is parsed into individual connection options,
36
+ * including structured query options. The `postgresql:` and `postgres:`
37
+ * protocols select PostgreSQL, `mysql:` selects MySQL, and `file:` selects
38
+ * SQLite. Only the URL forms documented by those databases are accepted;
39
+ * other protocol names and driver-specific compatibility forms are rejected.
40
+ * PostgreSQL supports `sslmode=disable`, `require`, `verify-ca`, and
41
+ * `verify-full`; MySQL supports `ssl-mode=DISABLED`, `REQUIRED`, `VERIFY_CA`,
42
+ * and `VERIFY_IDENTITY`. Modes that require a plaintext fallback are rejected
43
+ * because one structured driver configuration cannot preserve that behavior.
34
44
  *
35
45
  * @returns MikroORM options derived from environment variables
36
46
  */
37
- export declare function loadConfigFromEnv(): Promise<DriverConfig & (UrlConfig | HostConfig)>;
47
+ export declare function loadConfigFromEnv(): Promise<DriverConfig & HostConfig>;
@@ -34,77 +34,220 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.loadConfigFromEnv = loadConfigFromEnv;
37
- const core_1 = require("@mikro-orm/core");
38
- const reflection_1 = require("@mikro-orm/reflection");
39
- async function getDriver(type) {
40
- switch (type) {
41
- case "mysql":
37
+ const promises_1 = require("node:fs/promises");
38
+ const node_url_1 = require("node:url");
39
+ const load_default_config_util_1 = require("./load-default-config.util");
40
+ async function getDriver(protocol) {
41
+ switch (protocol) {
42
+ case "file:":
43
+ return (await Promise.resolve().then(() => __importStar(require("@mikro-orm/better-sqlite")))).BetterSqliteDriver;
44
+ case "mysql:":
42
45
  return (await Promise.resolve().then(() => __importStar(require("@mikro-orm/mysql")))).MySqlDriver;
43
- case "postgres":
44
- case "postgresql":
46
+ case "postgres:":
47
+ case "postgresql:":
45
48
  return (await Promise.resolve().then(() => __importStar(require("@mikro-orm/postgresql")))).PostgreSqlDriver;
49
+ default:
50
+ throw new TypeError(`Unsupported DATABASE_URL protocol: ${protocol}`);
46
51
  }
47
52
  }
53
+ function normalizeHostname(hostname) {
54
+ if (hostname.startsWith("[") && hostname.endsWith("]")) {
55
+ return hostname.slice(1, -1);
56
+ }
57
+ return hostname;
58
+ }
59
+ async function loadTlsFiles(files) {
60
+ const ssl = {};
61
+ let hasTlsFile = false;
62
+ for (const [path, sslKey] of files) {
63
+ if (typeof path === "string" && path) {
64
+ ssl[sslKey] = await (0, promises_1.readFile)(path, "utf8");
65
+ hasTlsFile = true;
66
+ }
67
+ }
68
+ return hasTlsFile ? ssl : undefined;
69
+ }
70
+ async function loadPostgreSqlTlsFiles(connection) {
71
+ const ssl = await loadTlsFiles([
72
+ [connection.sslrootcert, "ca"],
73
+ [connection.sslcert, "cert"],
74
+ [connection.sslkey, "key"],
75
+ ]);
76
+ delete connection.sslrootcert;
77
+ delete connection.sslcert;
78
+ delete connection.sslkey;
79
+ return ssl;
80
+ }
81
+ async function loadMySqlTlsConfig(connection) {
82
+ const supportedParameters = ["ssl-mode", "ssl-ca", "ssl-cert", "ssl-key"];
83
+ for (const parameter of Object.keys(connection)) {
84
+ if (!supportedParameters.includes(parameter)) {
85
+ throw new TypeError(`Unsupported MySQL DATABASE_URL parameter: ${parameter}`);
86
+ }
87
+ }
88
+ const sslMode = connection["ssl-mode"];
89
+ const tlsFiles = [
90
+ [connection["ssl-ca"], "ca"],
91
+ [connection["ssl-cert"], "cert"],
92
+ [connection["ssl-key"], "key"],
93
+ ];
94
+ delete connection["ssl-ca"];
95
+ delete connection["ssl-cert"];
96
+ delete connection["ssl-key"];
97
+ delete connection["ssl-mode"];
98
+ const normalizedSslMode = typeof sslMode === "string" ? sslMode.toUpperCase() : sslMode;
99
+ if (normalizedSslMode === "DISABLED") {
100
+ connection.ssl = false;
101
+ return;
102
+ }
103
+ if (normalizedSslMode === "PREFERRED") {
104
+ throw new TypeError("Unsupported MySQL ssl-mode: PREFERRED");
105
+ }
106
+ const ssl = await loadTlsFiles(tlsFiles);
107
+ switch (normalizedSslMode) {
108
+ case "REQUIRED":
109
+ connection.ssl = { ...ssl, rejectUnauthorized: false };
110
+ break;
111
+ case "VERIFY_CA":
112
+ if (!ssl?.ca) {
113
+ throw new TypeError("MySQL ssl-mode=VERIFY_CA requires ssl-ca");
114
+ }
115
+ connection.ssl = {
116
+ ...ssl,
117
+ rejectUnauthorized: true,
118
+ verifyIdentity: false,
119
+ };
120
+ break;
121
+ case "VERIFY_IDENTITY":
122
+ if (!ssl?.ca) {
123
+ throw new TypeError("MySQL ssl-mode=VERIFY_IDENTITY requires ssl-ca");
124
+ }
125
+ connection.ssl = {
126
+ ...ssl,
127
+ rejectUnauthorized: true,
128
+ verifyIdentity: true,
129
+ };
130
+ break;
131
+ case undefined:
132
+ if (ssl) {
133
+ connection.ssl = {
134
+ ...ssl,
135
+ rejectUnauthorized: true,
136
+ verifyIdentity: false,
137
+ };
138
+ }
139
+ break;
140
+ default:
141
+ throw new TypeError(`Unsupported MySQL ssl-mode: ${String(sslMode)}`);
142
+ }
143
+ }
144
+ async function loadQueryConfig(url, protocol) {
145
+ const connection = Object.fromEntries(url.searchParams);
146
+ const schema = url.searchParams.get("schema") ?? undefined;
147
+ delete connection.schema;
148
+ if (protocol === "mysql:") {
149
+ await loadMySqlTlsConfig(connection);
150
+ }
151
+ if (protocol === "postgres:" || protocol === "postgresql:") {
152
+ if (connection.ssl !== undefined) {
153
+ throw new TypeError("Unsupported PostgreSQL DATABASE_URL parameter: ssl");
154
+ }
155
+ if (connection.uselibpqcompat !== undefined) {
156
+ throw new TypeError("Unsupported PostgreSQL DATABASE_URL parameter: uselibpqcompat");
157
+ }
158
+ const sslMode = connection.sslmode;
159
+ delete connection.uselibpqcompat;
160
+ delete connection.sslmode;
161
+ if (sslMode === "disable") {
162
+ delete connection.sslrootcert;
163
+ delete connection.sslcert;
164
+ delete connection.sslkey;
165
+ connection.ssl = false;
166
+ }
167
+ else if (sslMode === "allow" || sslMode === "prefer") {
168
+ throw new TypeError(`Unsupported PostgreSQL sslmode: ${sslMode}`);
169
+ }
170
+ else {
171
+ const tls = await loadPostgreSqlTlsFiles(connection);
172
+ if (tls) {
173
+ connection.ssl = tls;
174
+ }
175
+ switch (sslMode) {
176
+ case "require":
177
+ connection.ssl = tls?.ca
178
+ ? { ...tls, checkServerIdentity: () => undefined }
179
+ : { ...tls, rejectUnauthorized: false };
180
+ break;
181
+ case "verify-ca":
182
+ if (!tls?.ca) {
183
+ throw new TypeError("PostgreSQL sslmode=verify-ca requires sslrootcert");
184
+ }
185
+ connection.ssl = { ...tls, checkServerIdentity: () => undefined };
186
+ break;
187
+ case "verify-full":
188
+ connection.ssl = tls ?? {};
189
+ break;
190
+ case undefined:
191
+ break;
192
+ default:
193
+ throw new TypeError(`Unsupported PostgreSQL sslmode: ${String(sslMode)}`);
194
+ }
195
+ }
196
+ }
197
+ return {
198
+ schema,
199
+ driverOptions: Object.keys(connection).length ? { connection } : undefined,
200
+ };
201
+ }
48
202
  /**
49
203
  * Loads MikroORM configuration from environment variables.
50
204
  *
51
205
  * @remarks
52
- * Supports both connection URL (`DB_URL` / `DATABASE_URL`) and individual
53
- * host/port/dbName/user/password variables. Automatically resolves the
54
- * database driver based on the URL protocol or `DB_TYPE`.
206
+ * Supports `DATABASE_URL`, which is parsed into individual connection options,
207
+ * including structured query options. The `postgresql:` and `postgres:`
208
+ * protocols select PostgreSQL, `mysql:` selects MySQL, and `file:` selects
209
+ * SQLite. Only the URL forms documented by those databases are accepted;
210
+ * other protocol names and driver-specific compatibility forms are rejected.
211
+ * PostgreSQL supports `sslmode=disable`, `require`, `verify-ca`, and
212
+ * `verify-full`; MySQL supports `ssl-mode=DISABLED`, `REQUIRED`, `VERIFY_CA`,
213
+ * and `VERIFY_IDENTITY`. Modes that require a plaintext fallback are rejected
214
+ * because one structured driver configuration cannot preserve that behavior.
55
215
  *
56
216
  * @returns MikroORM options derived from environment variables
57
217
  */
58
218
  async function loadConfigFromEnv() {
59
- const baseConfig = {
60
- colors: false,
61
- debug: !!(process.env.DB_DEBUG ?? process.env.DATABASE_DEBUG),
62
- dataloader: core_1.DataloaderType.ALL,
63
- timezone: "UTC",
64
- metadataProvider: reflection_1.TsMorphMetadataProvider,
65
- entities: ["dist/**/*.entity.js"],
66
- entitiesTs: ["src/**/*.entity.ts"],
67
- migrations: {
68
- snapshot: false,
69
- path: "dist/database/migrations",
70
- pathTs: "src/database/migrations",
71
- },
72
- seeder: {
73
- path: "dist/database/seeders",
74
- pathTs: "src/database/seeders",
75
- defaultSeeder: "DatabaseSeeder",
76
- fileName: (className) => className,
77
- },
78
- };
79
- const dbUrl = process.env.DB_URL ?? process.env.DATABASE_URL;
80
- if (dbUrl) {
81
- const dbType = new URL(dbUrl).protocol.replace(":", "");
219
+ const baseConfig = (0, load_default_config_util_1.loadDefaultConfig)();
220
+ const databaseUrl = process.env.DATABASE_URL;
221
+ if (databaseUrl) {
222
+ const url = new URL(databaseUrl);
223
+ const driver = await getDriver(url.protocol);
224
+ if (url.protocol === "file:") {
225
+ return {
226
+ ...baseConfig,
227
+ driver,
228
+ dbName: (0, node_url_1.fileURLToPath)(url),
229
+ };
230
+ }
231
+ const dbName = url.pathname.slice(1);
82
232
  return {
83
233
  ...baseConfig,
84
- driver: await getDriver(dbType),
85
- clientUrl: dbUrl,
234
+ driver,
235
+ host: normalizeHostname(url.hostname),
236
+ port: +url.port,
237
+ dbName: dbName ? decodeURIComponent(dbName) : undefined,
238
+ user: decodeURIComponent(url.username),
239
+ password: decodeURIComponent(url.password),
240
+ ...(await loadQueryConfig(url, url.protocol)),
86
241
  };
87
242
  }
88
- const dbType = process.env.DB_TYPE ?? process.env.DATABASE_TYPE;
89
- const dbHost = process.env.DB_HOST ?? process.env.DATABASE_HOST;
90
- const dbPort = process.env.DB_PORT ?? process.env.DATABASE_PORT;
91
- const dbName = process.env.DB_NAME ?? process.env.DB_DATABASE ?? process.env.DATABASE_NAME;
92
- const dbUsername = process.env.DB_USER ??
93
- process.env.DB_USERNAME ??
94
- process.env.DATABASE_USER ??
95
- process.env.DATABASE_USERNAME;
96
- const dbPassword = process.env.DB_PASS ??
97
- process.env.DB_PASSWORD ??
98
- process.env.DATABASE_PASS ??
99
- process.env.DATABASE_PASSWORD;
100
243
  return {
101
244
  ...baseConfig,
102
- driver: await getDriver(dbType),
103
- host: dbHost,
104
- port: dbPort ? +dbPort : undefined,
105
- dbName,
106
- user: dbUsername,
107
- password: dbPassword,
245
+ driver: undefined,
246
+ host: undefined,
247
+ port: undefined,
248
+ dbName: undefined,
249
+ user: undefined,
250
+ password: undefined,
108
251
  };
109
252
  }
110
253
  //# sourceMappingURL=load-config-from-env.util.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"load-config-from-env.util.js","sourceRoot":"","sources":["../../src/utils/load-config-from-env.util.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"load-config-from-env.util.js","sourceRoot":"","sources":["../../src/utils/load-config-from-env.util.ts"],"names":[],"mappings":"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"}
@@ -1,29 +1,55 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const promises_1 = require("node:fs/promises");
4
+ const node_os_1 = require("node:os");
5
+ const node_path_1 = require("node:path");
6
+ const better_sqlite_1 = require("@mikro-orm/better-sqlite");
3
7
  const core_1 = require("@mikro-orm/core");
4
8
  const mysql_1 = require("@mikro-orm/mysql");
5
9
  const postgresql_1 = require("@mikro-orm/postgresql");
6
10
  const reflection_1 = require("@mikro-orm/reflection");
7
11
  const load_config_from_env_util_1 = require("./load-config-from-env.util");
8
12
  const ORIGINAL_ENV = process.env;
13
+ async function withTlsFiles(callback) {
14
+ const directory = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "nest-boot-mikro-orm-"));
15
+ const paths = {
16
+ clientCert: (0, node_path_1.join)(directory, "client.crt"),
17
+ clientKey: (0, node_path_1.join)(directory, "client.key"),
18
+ rootCert: (0, node_path_1.join)(directory, "root.crt"),
19
+ };
20
+ try {
21
+ await Promise.all([
22
+ (0, promises_1.writeFile)(paths.rootCert, "root certificate"),
23
+ (0, promises_1.writeFile)(paths.clientCert, "client certificate"),
24
+ (0, promises_1.writeFile)(paths.clientKey, "client key"),
25
+ ]);
26
+ await callback(paths);
27
+ }
28
+ finally {
29
+ await (0, promises_1.rm)(directory, { force: true, recursive: true });
30
+ }
31
+ }
9
32
  describe("loadConfigFromEnv", () => {
10
33
  beforeEach(() => {
11
- process.env = Object.fromEntries(Object.entries(ORIGINAL_ENV).filter(([key]) => !key.startsWith("DB_") && !key.startsWith("DATABASE_")));
34
+ process.env = { ...ORIGINAL_ENV };
35
+ delete process.env.DATABASE_URL;
12
36
  });
13
37
  afterAll(() => {
14
38
  process.env = ORIGINAL_ENV;
15
39
  });
16
40
  it("should load URL-based MySQL config", async () => {
17
- process.env.DB_URL = "mysql://user:pass@localhost:3306/app";
18
- process.env.DB_DEBUG = "true";
19
- await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).resolves.toMatchObject({
20
- clientUrl: "mysql://user:pass@localhost:3306/app",
41
+ process.env.DATABASE_URL =
42
+ "mysql://user%40example.com:p%40ss%2Fword@localhost:3306/app";
43
+ const config = await (0, load_config_from_env_util_1.loadConfigFromEnv)();
44
+ expect(config).toMatchObject({
21
45
  colors: false,
22
46
  dataloader: core_1.DataloaderType.ALL,
23
- debug: true,
47
+ dbName: "app",
48
+ debug: false,
24
49
  driver: mysql_1.MySqlDriver,
25
50
  entities: ["dist/**/*.entity.js"],
26
51
  entitiesTs: ["src/**/*.entity.ts"],
52
+ host: "localhost",
27
53
  metadataProvider: reflection_1.TsMorphMetadataProvider,
28
54
  migrations: {
29
55
  path: "dist/database/migrations",
@@ -35,33 +61,234 @@ describe("loadConfigFromEnv", () => {
35
61
  path: "dist/database/seeders",
36
62
  pathTs: "src/database/seeders",
37
63
  },
64
+ password: "p@ss/word",
65
+ port: 3306,
38
66
  timezone: "UTC",
67
+ user: "user@example.com",
39
68
  });
69
+ expect(config).not.toHaveProperty("clientUrl");
70
+ expect(config.seeder?.fileName?.("CustomSeeder")).toBe("CustomSeeder");
40
71
  });
41
72
  it("should load URL-based PostgreSQL config", async () => {
42
- process.env.DATABASE_URL = "postgresql://user:pass@localhost:5432/app";
73
+ process.env.DATABASE_URL =
74
+ "postgresql://user:pass@[2001:db8::1]:5432/app?schema=tenant&sslmode=require&application_name=nest-boot";
43
75
  await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).resolves.toMatchObject({
44
- clientUrl: "postgresql://user:pass@localhost:5432/app",
76
+ dbName: "app",
45
77
  driver: postgresql_1.PostgreSqlDriver,
78
+ driverOptions: {
79
+ connection: {
80
+ application_name: "nest-boot",
81
+ ssl: {},
82
+ },
83
+ },
84
+ host: "2001:db8::1",
85
+ password: "pass",
86
+ port: 5432,
87
+ schema: "tenant",
88
+ user: "user",
46
89
  });
47
90
  });
48
- it("should load host-based config from aliases", async () => {
49
- process.env.DATABASE_TYPE = "postgres";
50
- process.env.DATABASE_HOST = "localhost";
51
- process.env.DATABASE_PORT = "5432";
52
- process.env.DATABASE_NAME = "app";
53
- process.env.DATABASE_USERNAME = "user";
54
- process.env.DATABASE_PASSWORD = "pass";
91
+ it("should load the postgres PostgreSQL URI form", async () => {
92
+ process.env.DATABASE_URL = "postgres://user:pass@localhost/app";
55
93
  await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).resolves.toMatchObject({
56
94
  dbName: "app",
57
95
  driver: postgresql_1.PostgreSqlDriver,
58
96
  host: "localhost",
59
97
  password: "pass",
60
- port: 5432,
61
98
  user: "user",
62
99
  });
63
100
  });
64
- it("should return undefined driver and port when env vars are absent", async () => {
101
+ it("should load a file URL as SQLite config", async () => {
102
+ process.env.DATABASE_URL = "file:///var/lib/nest-boot/app%20data.db";
103
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).resolves.toMatchObject({
104
+ dbName: "/var/lib/nest-boot/app data.db",
105
+ driver: better_sqlite_1.BetterSqliteDriver,
106
+ });
107
+ });
108
+ it.each([
109
+ ["mysql", "ssl-mode=DISABLED", { ssl: false }],
110
+ ["mysql", "ssl-mode=REQUIRED", { ssl: { rejectUnauthorized: false } }],
111
+ ["postgresql", "sslmode=disable", { ssl: false }],
112
+ ["postgresql", "sslmode=require", { ssl: { rejectUnauthorized: false } }],
113
+ ["postgresql", "sslmode=verify-full", { ssl: {} }],
114
+ ])("should parse %s driver query option %s", async (protocol, query, expected) => {
115
+ process.env.DATABASE_URL = `${protocol}://user:pass@localhost/app?${query}`;
116
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).resolves.toMatchObject({
117
+ driverOptions: {
118
+ connection: expected,
119
+ },
120
+ });
121
+ });
122
+ it("should preserve omitted URL credentials and port", async () => {
123
+ process.env.DATABASE_URL = "postgresql://db.internal";
124
+ const config = await (0, load_config_from_env_util_1.loadConfigFromEnv)();
125
+ expect(config).toMatchObject({
126
+ dbName: undefined,
127
+ host: "db.internal",
128
+ password: "",
129
+ port: 0,
130
+ user: "",
131
+ });
132
+ const mikroOrmConfig = new core_1.Configuration(config, false);
133
+ expect(mikroOrmConfig.getDriver().getConnection().getConnectionOptions()).toMatchObject({
134
+ host: "db.internal",
135
+ password: "",
136
+ port: 0,
137
+ user: "",
138
+ });
139
+ });
140
+ it("should load PostgreSQL TLS files into structured SSL options", async () => {
141
+ await withTlsFiles(async ({ clientCert, clientKey, rootCert }) => {
142
+ const databaseUrl = new URL("postgresql://user:pass@localhost/app");
143
+ databaseUrl.searchParams.set("sslmode", "verify-full");
144
+ databaseUrl.searchParams.set("sslrootcert", rootCert);
145
+ databaseUrl.searchParams.set("sslcert", clientCert);
146
+ databaseUrl.searchParams.set("sslkey", clientKey);
147
+ process.env.DATABASE_URL = databaseUrl.href;
148
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).resolves.toMatchObject({
149
+ driverOptions: {
150
+ connection: {
151
+ ssl: {
152
+ ca: "root certificate",
153
+ cert: "client certificate",
154
+ key: "client key",
155
+ },
156
+ },
157
+ },
158
+ });
159
+ });
160
+ });
161
+ it.each(["require", "verify-ca"])("should map PostgreSQL sslmode=%s with a root certificate", async (sslMode) => {
162
+ await withTlsFiles(async ({ rootCert }) => {
163
+ const databaseUrl = new URL("postgresql://user:pass@localhost/app");
164
+ databaseUrl.searchParams.set("sslmode", sslMode);
165
+ databaseUrl.searchParams.set("sslrootcert", rootCert);
166
+ process.env.DATABASE_URL = databaseUrl.href;
167
+ const config = await (0, load_config_from_env_util_1.loadConfigFromEnv)();
168
+ const connection = config.driverOptions?.connection;
169
+ const ssl = connection.ssl;
170
+ expect(ssl).toMatchObject({
171
+ ca: "root certificate",
172
+ checkServerIdentity: expect.any(Function),
173
+ });
174
+ const checkServerIdentity = ssl.checkServerIdentity;
175
+ checkServerIdentity();
176
+ });
177
+ });
178
+ it("should load MySQL TLS files into structured SSL options", async () => {
179
+ await withTlsFiles(async ({ clientCert, clientKey, rootCert }) => {
180
+ const databaseUrl = new URL("mysql://user:pass@localhost/app");
181
+ databaseUrl.searchParams.set("ssl-ca", rootCert);
182
+ databaseUrl.searchParams.set("ssl-cert", clientCert);
183
+ databaseUrl.searchParams.set("ssl-key", clientKey);
184
+ process.env.DATABASE_URL = databaseUrl.href;
185
+ const config = await (0, load_config_from_env_util_1.loadConfigFromEnv)();
186
+ expect(config.driverOptions).toEqual({
187
+ connection: {
188
+ ssl: {
189
+ ca: "root certificate",
190
+ cert: "client certificate",
191
+ key: "client key",
192
+ rejectUnauthorized: true,
193
+ verifyIdentity: false,
194
+ },
195
+ },
196
+ });
197
+ });
198
+ });
199
+ it.each([
200
+ ["VERIFY_CA", false],
201
+ ["VERIFY_IDENTITY", true],
202
+ ])("should map MySQL ssl-mode=%s with a CA certificate", async (sslMode, verifyIdentity) => {
203
+ await withTlsFiles(async ({ rootCert }) => {
204
+ const databaseUrl = new URL("mysql://user:pass@localhost/app");
205
+ databaseUrl.searchParams.set("ssl-mode", sslMode);
206
+ databaseUrl.searchParams.set("ssl-ca", rootCert);
207
+ process.env.DATABASE_URL = databaseUrl.href;
208
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).resolves.toMatchObject({
209
+ driverOptions: {
210
+ connection: {
211
+ ssl: {
212
+ ca: "root certificate",
213
+ rejectUnauthorized: true,
214
+ verifyIdentity,
215
+ },
216
+ },
217
+ },
218
+ });
219
+ });
220
+ });
221
+ it("should not read MySQL TLS files when SSL is disabled", async () => {
222
+ process.env.DATABASE_URL =
223
+ "mysql://user:pass@localhost/app?ssl-mode=DISABLED&ssl-ca=/missing/ca.pem";
224
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).resolves.toMatchObject({
225
+ driverOptions: {
226
+ connection: {
227
+ ssl: false,
228
+ },
229
+ },
230
+ });
231
+ });
232
+ it("should reject unsupported MySQL SSL modes", async () => {
233
+ process.env.DATABASE_URL =
234
+ "mysql://user:pass@localhost/app?ssl-mode=VERIFY_HOSTNAME";
235
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).rejects.toThrow("Unsupported MySQL ssl-mode: VERIFY_HOSTNAME");
236
+ });
237
+ it.each([
238
+ ["mysql://user:pass@localhost/app?ssl-mode=PREFERRED", "PREFERRED"],
239
+ ["postgresql://user:pass@localhost/app?sslmode=allow", "allow"],
240
+ ["postgresql://user:pass@localhost/app?sslmode=prefer", "prefer"],
241
+ ])("should reject SSL fallback mode %s that structured options cannot express", async (databaseUrl, sslMode) => {
242
+ process.env.DATABASE_URL = databaseUrl;
243
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).rejects.toThrow(`Unsupported ${databaseUrl.startsWith("mysql:") ? "MySQL ssl-mode" : "PostgreSQL sslmode"}: ${sslMode}`);
244
+ });
245
+ it.each(["VERIFY_CA", "VERIFY_IDENTITY"])("should require ssl-ca for MySQL ssl-mode=%s", async (sslMode) => {
246
+ process.env.DATABASE_URL = `mysql://user:pass@localhost/app?ssl-mode=${sslMode}`;
247
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).rejects.toThrow(`MySQL ssl-mode=${sslMode} requires ssl-ca`);
248
+ });
249
+ it("should require sslrootcert for PostgreSQL verify-ca", async () => {
250
+ process.env.DATABASE_URL =
251
+ "postgresql://user:pass@localhost/app?sslmode=verify-ca";
252
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).rejects.toThrow("PostgreSQL sslmode=verify-ca requires sslrootcert");
253
+ });
254
+ it.each([
255
+ [
256
+ "mysql://user:pass@localhost/app?ssl=true",
257
+ "Unsupported MySQL DATABASE_URL parameter: ssl",
258
+ ],
259
+ [
260
+ "mysql://user:pass@localhost/app?multipleStatements=false",
261
+ "Unsupported MySQL DATABASE_URL parameter: multipleStatements",
262
+ ],
263
+ [
264
+ "postgresql://user:pass@localhost/app?ssl=true",
265
+ "Unsupported PostgreSQL DATABASE_URL parameter: ssl",
266
+ ],
267
+ [
268
+ "postgresql://user:pass@localhost/app?ssl=1",
269
+ "Unsupported PostgreSQL DATABASE_URL parameter: ssl",
270
+ ],
271
+ [
272
+ "postgresql://user:pass@localhost/app?uselibpqcompat=true",
273
+ "Unsupported PostgreSQL DATABASE_URL parameter: uselibpqcompat",
274
+ ],
275
+ [
276
+ "postgresql://user:pass@localhost/app?sslmode=no-verify",
277
+ "Unsupported PostgreSQL sslmode: no-verify",
278
+ ],
279
+ ])("should reject non-standard database URL options", async (url, error) => {
280
+ process.env.DATABASE_URL = url;
281
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).rejects.toThrow(error);
282
+ });
283
+ it.each(["mysql2://localhost/app", "sqlite:///var/lib/app.db"])("should reject non-standard database URL %s", async (databaseUrl) => {
284
+ process.env.DATABASE_URL = databaseUrl;
285
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).rejects.toThrow(`Unsupported DATABASE_URL protocol: ${new URL(databaseUrl).protocol}`);
286
+ });
287
+ it("should reject unsupported database URL protocols", async () => {
288
+ process.env.DATABASE_URL = "mongodb://localhost/app";
289
+ await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).rejects.toThrow("Unsupported DATABASE_URL protocol: mongodb:");
290
+ });
291
+ it("should return undefined connection fields when DATABASE_URL is absent", async () => {
65
292
  await expect((0, load_config_from_env_util_1.loadConfigFromEnv)()).resolves.toMatchObject({
66
293
  dbName: undefined,
67
294
  driver: undefined,