tina4-nodejs 3.9.2 → 3.9.4
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/CLAUDE.md +17 -12
- package/package.json +1 -1
- package/packages/core/src/queue.ts +3 -3
- package/packages/core/src/queueBackends/kafkaBackend.ts +2 -1
- package/packages/core/src/queueBackends/rabbitmqBackend.ts +2 -1
- package/packages/core/src/server.ts +3 -2
- package/packages/core/src/session.ts +4 -4
- package/packages/core/src/sessionHandlers/databaseHandler.ts +1 -4
- package/packages/core/src/websocketBackplane.ts +17 -16
- package/packages/orm/src/adapters/firebird.ts +1 -1
- package/packages/orm/src/adapters/mssql.ts +1 -1
- package/packages/orm/src/adapters/mysql.ts +1 -1
- package/packages/orm/src/adapters/postgres.ts +4 -11
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.9.
|
|
1
|
+
# CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.9.2)
|
|
2
2
|
|
|
3
3
|
> This file helps AI assistants (Claude, Copilot, Cursor, etc.) understand and work on this codebase effectively.
|
|
4
4
|
|
|
5
5
|
## What This Project Is
|
|
6
6
|
|
|
7
|
-
Tina4 for Node.js/TypeScript v3.9.
|
|
7
|
+
Tina4 for Node.js/TypeScript v3.9.2 — a convention-over-configuration structural paradigm. **Not a framework.** The developer writes TypeScript; Tina4 is invisible infrastructure.
|
|
8
8
|
|
|
9
9
|
The philosophy: zero ceremony, batteries included, file system as source of truth.
|
|
10
10
|
|
|
@@ -38,12 +38,12 @@ tina4-nodejs/
|
|
|
38
38
|
service.ts # Service layer helpers
|
|
39
39
|
session.ts # Session management
|
|
40
40
|
testing.ts # Inline testing framework (attach tests to functions)
|
|
41
|
-
websocket.ts # WebSocket support
|
|
41
|
+
websocket.ts # WebSocket support (with backplane)
|
|
42
42
|
wsdl.ts # WSDL / SOAP support
|
|
43
43
|
orm/ # Database adapters, models, auto-CRUD, query builder, seeding
|
|
44
44
|
src/
|
|
45
45
|
adapters/
|
|
46
|
-
sqlite.ts # SQLite via
|
|
46
|
+
sqlite.ts # SQLite via node:sqlite (default)
|
|
47
47
|
postgres.ts # PostgreSQL adapter
|
|
48
48
|
mysql.ts # MySQL adapter
|
|
49
49
|
mssql.ts # MSSQL / SQL Server adapter
|
|
@@ -69,7 +69,7 @@ This is an **npm workspaces monorepo**. All packages are in `packages/*`.
|
|
|
69
69
|
- **Language:** TypeScript (strict mode, ES2022 target, Node16 module resolution)
|
|
70
70
|
- **Runtime:** Node.js 20+ (ESM only, `"type": "module"` everywhere)
|
|
71
71
|
- **HTTP:** Native `node:http` — no Express, no Fastify
|
|
72
|
-
- **Database:** SQLite via `
|
|
72
|
+
- **Database:** SQLite via `node:sqlite` (default), with adapters for Postgres, MySQL, MSSQL/SQL Server, and Firebird
|
|
73
73
|
- **Templates:** Twig via `twig` npm package (optional)
|
|
74
74
|
- **Dev tooling:** `tsx` for runtime TS execution, `esbuild` for builds
|
|
75
75
|
- **Testing:** 43 test files via `tsx test/run-all.ts`
|
|
@@ -120,8 +120,8 @@ The HTTP foundation. Handles request/response lifecycle, route matching, middlew
|
|
|
120
120
|
- `devAdmin.ts` — Dev toolbar (fixed bottom bar injected into HTML pages) and admin dashboard at `/_dev/`
|
|
121
121
|
- `auth.ts` — Authentication helpers
|
|
122
122
|
- `cache.ts` — In-memory caching
|
|
123
|
-
- `session.ts` — Session management with pluggable handlers
|
|
124
|
-
- `websocket.ts` — WebSocket support
|
|
123
|
+
- `session.ts` — Session management with pluggable handlers. `TINA4_SESSION_SAMESITE` env var (default: Lax)
|
|
124
|
+
- `websocket.ts` — WebSocket support with backplane for scaling via Redis pub/sub (`TINA4_WS_BACKPLANE`, `TINA4_WS_BACKPLANE_URL`)
|
|
125
125
|
- `queue.ts` — Queue system with pluggable backends
|
|
126
126
|
- `graphql.ts` — GraphQL engine
|
|
127
127
|
- `i18n.ts` — Internationalization / localization
|
|
@@ -139,7 +139,7 @@ Database layer with auto-CRUD generation, seeding, fake data, and SQL translatio
|
|
|
139
139
|
|
|
140
140
|
**Key files:**
|
|
141
141
|
- `database.ts` — Adapter manager, `initDatabase()` factory
|
|
142
|
-
- `adapters/sqlite.ts` — `
|
|
142
|
+
- `adapters/sqlite.ts` — `node:sqlite` implementation of `DatabaseAdapter` interface
|
|
143
143
|
- `adapters/postgres.ts` — PostgreSQL adapter
|
|
144
144
|
- `adapters/mysql.ts` — MySQL adapter
|
|
145
145
|
- `adapters/mssql.ts` — MSSQL / SQL Server adapter (`mssql` or `sqlserver` scheme)
|
|
@@ -153,6 +153,7 @@ Database layer with auto-CRUD generation, seeding, fake data, and SQL translatio
|
|
|
153
153
|
- `fakeData.ts` — ORM-aware fake data extending core (adds `forField()` with column-name heuristics)
|
|
154
154
|
- `seeder.ts` — Database seeding (`seedTable` for raw SQL, `seedOrm` for model-based)
|
|
155
155
|
- `sqlTranslation.ts` — Cross-engine SQL translator (`SQLTranslator`) and TTL query cache (`QueryCache`)
|
|
156
|
+
- QueryBuilder supports `toMongo()` for generating MongoDB query documents from the same fluent API
|
|
156
157
|
|
|
157
158
|
### @tina4/swagger (`packages/swagger/`)
|
|
158
159
|
Auto-generates OpenAPI 3.0 docs.
|
|
@@ -173,7 +174,7 @@ Developer-facing CLI commands.
|
|
|
173
174
|
|
|
174
175
|
**Key files:**
|
|
175
176
|
- `bin.ts` — Entry point, command dispatch (`init`, `serve`, `--help`)
|
|
176
|
-
- `commands/init.ts` — Scaffolds a new project directory with sample files
|
|
177
|
+
- `commands/init.ts` — Scaffolds a new project directory with sample files, Dockerfile, and .dockerignore
|
|
177
178
|
- `commands/serve.ts` — Starts dev server with hot-reload via `@tina4/core`
|
|
178
179
|
|
|
179
180
|
## Module: Events (`packages/core/src/events.ts`)
|
|
@@ -469,7 +470,7 @@ import { Router } from "./router.js"; // .js even though the file is .ts
|
|
|
469
470
|
3. **Convention-based models** — `static fields = {}` over decorators. No special TypeScript config needed.
|
|
470
471
|
4. **CDN for Swagger UI** — Keeps install under 8MB. Single HTML file loads from unpkg.com.
|
|
471
472
|
5. **Process restart for hot-reload** — Simpler and more reliable than HMR with ESM.
|
|
472
|
-
6. **SQLite default** — `
|
|
473
|
+
6. **SQLite default** — `node:sqlite` is synchronous and fast. Full adapters for Postgres, MySQL, MSSQL/SQL Server, and Firebird.
|
|
473
474
|
7. **CLI named `tina4nodejs`** (primary) with `tina4` as alias — So `npx tina4nodejs init` or `npx tina4 init` both work.
|
|
474
475
|
8. **Event system** — Static `Events` class, synchronous dispatch, priority ordering, zero deps.
|
|
475
476
|
9. **Inline testing** — Tests as decorators on functions, no external test runner for unit-level checks.
|
|
@@ -531,7 +532,7 @@ await initDatabase({ type: "postgres", host: "localhost", port: 5432, database:
|
|
|
531
532
|
### Available adapters
|
|
532
533
|
| Adapter | Scheme(s) | Package |
|
|
533
534
|
|---------|-----------|---------|
|
|
534
|
-
| SQLite | `sqlite://` | `
|
|
535
|
+
| SQLite | `sqlite://` | `node:sqlite` |
|
|
535
536
|
| PostgreSQL | `postgres://`, `postgresql://` | `pg` |
|
|
536
537
|
| MySQL | `mysql://` | `mysql2` |
|
|
537
538
|
| MSSQL | `mssql://`, `sqlserver://` | `tedious` |
|
|
@@ -586,12 +587,16 @@ When adding new features, add a corresponding `test/<feature>.test.ts` file.
|
|
|
586
587
|
- **Production server auto-detect**: `npx tina4nodejs serve --production` auto-uses cluster mode
|
|
587
588
|
- **`npx tina4nodejs generate`**: model, route, migration, middleware scaffolding
|
|
588
589
|
- **Database**: 5 engines (SQLite, PostgreSQL, MySQL, MSSQL, Firebird), query caching (`TINA4_DB_CACHE=true`)
|
|
589
|
-
- **Sessions**: file backend (default)
|
|
590
|
+
- **Sessions**: file backend (default). `TINA4_SESSION_SAMESITE` env var (default: Lax)
|
|
590
591
|
- **Queue**: file/RabbitMQ/Kafka/MongoDB backends, configured via env vars
|
|
591
592
|
- **Cache**: memory/Redis/file backends
|
|
592
593
|
- **Messenger**: .env driven SMTP/IMAP
|
|
593
594
|
- **ORM relationships**: `hasMany`, `hasOne`, `belongsTo` with eager loading (`include`)
|
|
594
595
|
- **Frond pre-compilation**: 2.8x template render improvement
|
|
596
|
+
- **QueryBuilder** with NoSQL/MongoDB support (`toMongo()`)
|
|
597
|
+
- **WebSocket backplane** (Redis pub/sub) for horizontal scaling
|
|
598
|
+
- **SameSite=Lax** default on session cookies (`TINA4_SESSION_SAMESITE`)
|
|
599
|
+
- **`tina4 init`** generates Dockerfile and .dockerignore
|
|
595
600
|
- **Gallery**: 7 interactive examples with Try It deploy at `/_dev/`
|
|
596
601
|
|
|
597
602
|
## Don'ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tina4-nodejs",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "This is not a framework. Tina4 for Node.js/TypeScript — zero deps, 38 built-in features.",
|
|
6
6
|
"keywords": ["tina4", "framework", "web", "api", "orm", "graphql", "websocket", "typescript"],
|
|
@@ -31,6 +31,9 @@
|
|
|
31
31
|
import { mkdirSync, readdirSync, readFileSync, writeFileSync, unlinkSync, existsSync } from "node:fs";
|
|
32
32
|
import { join } from "node:path";
|
|
33
33
|
import { randomUUID } from "node:crypto";
|
|
34
|
+
import { RabbitMQBackend } from "./queueBackends/rabbitmqBackend.js";
|
|
35
|
+
import { KafkaBackend } from "./queueBackends/kafkaBackend.js";
|
|
36
|
+
import { MongoBackend } from "./queueBackends/mongoBackend.js";
|
|
34
37
|
|
|
35
38
|
// ── Types ────────────────────────────────────────────────────
|
|
36
39
|
|
|
@@ -137,13 +140,10 @@ export class Queue {
|
|
|
137
140
|
|
|
138
141
|
// Initialize external backends
|
|
139
142
|
if (this.backendName === "rabbitmq") {
|
|
140
|
-
const { RabbitMQBackend } = require("./queueBackends/rabbitmqBackend.js");
|
|
141
143
|
this.externalBackend = new RabbitMQBackend();
|
|
142
144
|
} else if (this.backendName === "kafka") {
|
|
143
|
-
const { KafkaBackend } = require("./queueBackends/kafkaBackend.js");
|
|
144
145
|
this.externalBackend = new KafkaBackend();
|
|
145
146
|
} else if (this.backendName === "mongodb" || this.backendName === "mongo") {
|
|
146
|
-
const { MongoBackend } = require("./queueBackends/mongoBackend.js");
|
|
147
147
|
this.externalBackend = new MongoBackend();
|
|
148
148
|
}
|
|
149
149
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* TINA4_KAFKA_GROUP_ID (default: "tina4_consumer_group")
|
|
10
10
|
*/
|
|
11
11
|
import net from "node:net";
|
|
12
|
+
import { execFileSync } from "node:child_process";
|
|
12
13
|
import { randomUUID } from "node:crypto";
|
|
13
14
|
import type { QueueJob } from "../queue.js";
|
|
14
15
|
|
|
@@ -72,7 +73,7 @@ export class KafkaBackend implements QueueBackend {
|
|
|
72
73
|
* Execute a Kafka operation synchronously via a child process.
|
|
73
74
|
*/
|
|
74
75
|
private execSync(operation: string, topic: string, data?: string): string {
|
|
75
|
-
|
|
76
|
+
// execFileSync imported at top level
|
|
76
77
|
const broker = this.parseBroker();
|
|
77
78
|
|
|
78
79
|
const script = `
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* TINA4_RABBITMQ_VHOST (default: "/")
|
|
13
13
|
*/
|
|
14
14
|
import net from "node:net";
|
|
15
|
+
import { execFileSync } from "node:child_process";
|
|
15
16
|
import { randomUUID } from "node:crypto";
|
|
16
17
|
import type { QueueJob } from "../queue.js";
|
|
17
18
|
|
|
@@ -144,7 +145,7 @@ export class RabbitMQBackend implements QueueBackend {
|
|
|
144
145
|
* Execute an AMQP operation synchronously via a child process.
|
|
145
146
|
*/
|
|
146
147
|
private execSync(operation: string, queue: string, data?: string): string {
|
|
147
|
-
|
|
148
|
+
// execFileSync imported at top level
|
|
148
149
|
|
|
149
150
|
const script = `
|
|
150
151
|
const net = require("node:net");
|
|
@@ -3,6 +3,7 @@ import { resolve, dirname, join, relative } from "node:path";
|
|
|
3
3
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
4
4
|
import { isatty } from "node:tty";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { execFileSync, exec } from "node:child_process";
|
|
6
7
|
import cluster from "node:cluster";
|
|
7
8
|
import os from "node:os";
|
|
8
9
|
import type { Tina4Config, Tina4Request, Tina4Response } from "./types.js";
|
|
@@ -35,7 +36,7 @@ const TINA4_VERSION = "3.0.0";
|
|
|
35
36
|
* Falls back to `start` if none of the candidates work.
|
|
36
37
|
*/
|
|
37
38
|
function findAvailablePort(start: number, maxTries = 10): number {
|
|
38
|
-
|
|
39
|
+
// execFileSync imported at top of file (ESM)
|
|
39
40
|
for (let offset = 0; offset < maxTries; offset++) {
|
|
40
41
|
const port = start + offset;
|
|
41
42
|
try {
|
|
@@ -54,7 +55,7 @@ function findAvailablePort(start: number, maxTries = 10): number {
|
|
|
54
55
|
* Open the user's default browser after a short delay so the server is ready.
|
|
55
56
|
*/
|
|
56
57
|
function openBrowser(url: string) {
|
|
57
|
-
|
|
58
|
+
// exec imported at top of file (ESM)
|
|
58
59
|
setTimeout(() => {
|
|
59
60
|
if (process.platform === "darwin") exec(`open ${url}`);
|
|
60
61
|
else if (process.platform === "win32") exec(`start "" "${url}"`);
|
|
@@ -28,6 +28,10 @@ import { randomBytes } from "node:crypto";
|
|
|
28
28
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
|
|
29
29
|
import { join } from "node:path";
|
|
30
30
|
import { execFileSync } from "node:child_process";
|
|
31
|
+
import { RedisNpmSessionHandler } from "./sessionHandlers/redisHandler.js";
|
|
32
|
+
import { ValkeySessionHandler } from "./sessionHandlers/valkeyHandler.js";
|
|
33
|
+
import { MongoSessionHandler } from "./sessionHandlers/mongoHandler.js";
|
|
34
|
+
import { DatabaseSessionHandler } from "./sessionHandlers/databaseHandler.js";
|
|
31
35
|
|
|
32
36
|
// ── Types ─────────────────────────────────────────────────────────
|
|
33
37
|
|
|
@@ -303,24 +307,20 @@ export class Session {
|
|
|
303
307
|
this.handler = new RedisSessionHandler(config);
|
|
304
308
|
break;
|
|
305
309
|
case "redis-npm": {
|
|
306
|
-
const { RedisNpmSessionHandler } = require("./sessionHandlers/redisHandler.js");
|
|
307
310
|
this.handler = new RedisNpmSessionHandler(config);
|
|
308
311
|
break;
|
|
309
312
|
}
|
|
310
313
|
case "valkey": {
|
|
311
|
-
const { ValkeySessionHandler } = require("./sessionHandlers/valkeyHandler.js");
|
|
312
314
|
this.handler = new ValkeySessionHandler(config);
|
|
313
315
|
break;
|
|
314
316
|
}
|
|
315
317
|
case "mongo":
|
|
316
318
|
case "mongodb": {
|
|
317
|
-
const { MongoSessionHandler } = require("./sessionHandlers/mongoHandler.js");
|
|
318
319
|
this.handler = new MongoSessionHandler(config);
|
|
319
320
|
break;
|
|
320
321
|
}
|
|
321
322
|
case "database":
|
|
322
323
|
case "db": {
|
|
323
|
-
const { DatabaseSessionHandler } = require("./sessionHandlers/databaseHandler.js");
|
|
324
324
|
this.handler = new DatabaseSessionHandler(config);
|
|
325
325
|
break;
|
|
326
326
|
}
|
|
@@ -10,11 +10,9 @@
|
|
|
10
10
|
* The handler dynamically imports `better-sqlite3` and throws a clear
|
|
11
11
|
* error if the package is not installed.
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
13
|
+
import { DatabaseSync } from "node:sqlite";
|
|
14
14
|
import type { SessionHandler } from "../session.js";
|
|
15
15
|
|
|
16
|
-
const _require = createRequire(import.meta.url);
|
|
17
|
-
|
|
18
16
|
interface SessionData {
|
|
19
17
|
_created: number;
|
|
20
18
|
_accessed: number;
|
|
@@ -39,7 +37,6 @@ export class DatabaseSessionHandler implements SessionHandler {
|
|
|
39
37
|
constructor(config?: DatabaseSessionConfig) {
|
|
40
38
|
const dbPath = config?.dbPath ?? this.resolveDbPath();
|
|
41
39
|
|
|
42
|
-
const { DatabaseSync } = require("node:sqlite");
|
|
43
40
|
this.db = new DatabaseSync(dbPath);
|
|
44
41
|
this.db.exec("PRAGMA journal_mode = WAL");
|
|
45
42
|
}
|
|
@@ -53,25 +53,26 @@ export class RedisBackplane implements WebSocketBackplane {
|
|
|
53
53
|
constructor(url?: string) {
|
|
54
54
|
this.url = url ?? process.env.TINA4_WS_BACKPLANE_URL ?? "redis://localhost:6379";
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
this.ready = (async () => {
|
|
57
|
+
let redis: any;
|
|
58
|
+
try {
|
|
59
|
+
redis = await import("redis");
|
|
60
|
+
} catch {
|
|
61
|
+
throw new Error(
|
|
62
|
+
"The 'redis' package is required for RedisBackplane. " +
|
|
63
|
+
"Install it with: npm install redis"
|
|
64
|
+
);
|
|
65
|
+
}
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
this.publisher = redis.createClient({ url: this.url });
|
|
68
|
+
this.subscriber = this.publisher.duplicate();
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
await Promise.all([
|
|
71
|
+
this.publisher.connect(),
|
|
72
|
+
this.subscriber.connect(),
|
|
73
|
+
]);
|
|
73
74
|
console.log(`[Tina4] RedisBackplane connected to ${this.url}`);
|
|
74
|
-
});
|
|
75
|
+
})();
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
async publish(channel: string, message: string): Promise<void> {
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { DatabaseAdapter, DatabaseResult, ColumnInfo, FieldDefinition } from "../types.js";
|
|
8
8
|
import { SQLTranslator } from "../sqlTranslation.js";
|
|
9
|
+
import { createRequire } from "node:module";
|
|
9
10
|
|
|
10
11
|
let firebird: any = null;
|
|
11
12
|
|
|
12
13
|
function requireFirebird(): any {
|
|
13
14
|
if (firebird) return firebird;
|
|
14
15
|
try {
|
|
15
|
-
const { createRequire } = require("node:module") as typeof import("node:module");
|
|
16
16
|
const req = createRequire(import.meta.url);
|
|
17
17
|
firebird = req("node-firebird");
|
|
18
18
|
return firebird;
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { DatabaseAdapter, DatabaseResult, ColumnInfo, FieldDefinition } from "../types.js";
|
|
8
8
|
import { SQLTranslator } from "../sqlTranslation.js";
|
|
9
|
+
import { createRequire } from "node:module";
|
|
9
10
|
|
|
10
11
|
let tedious: any = null;
|
|
11
12
|
|
|
12
13
|
function requireTedious(): any {
|
|
13
14
|
if (tedious) return tedious;
|
|
14
15
|
try {
|
|
15
|
-
const { createRequire } = require("node:module") as typeof import("node:module");
|
|
16
16
|
const req = createRequire(import.meta.url);
|
|
17
17
|
tedious = req("tedious");
|
|
18
18
|
return tedious;
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { DatabaseAdapter, DatabaseResult, ColumnInfo, FieldDefinition } from "../types.js";
|
|
8
8
|
import { SQLTranslator } from "../sqlTranslation.js";
|
|
9
|
+
import { createRequire } from "node:module";
|
|
9
10
|
|
|
10
11
|
let mysql2: any = null;
|
|
11
12
|
|
|
12
13
|
function requireMysql2(): any {
|
|
13
14
|
if (mysql2) return mysql2;
|
|
14
15
|
try {
|
|
15
|
-
const { createRequire } = require("node:module") as typeof import("node:module");
|
|
16
16
|
const req = createRequire(import.meta.url);
|
|
17
17
|
mysql2 = req("mysql2");
|
|
18
18
|
return mysql2;
|
|
@@ -7,15 +7,15 @@
|
|
|
7
7
|
import type { DatabaseAdapter, DatabaseResult, ColumnInfo, FieldDefinition } from "../types.js";
|
|
8
8
|
import { SQLTranslator } from "../sqlTranslation.js";
|
|
9
9
|
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
|
|
10
12
|
let pg: typeof import("pg") | null = null;
|
|
11
13
|
|
|
12
14
|
function requirePg(): typeof import("pg") {
|
|
13
15
|
if (pg) return pg;
|
|
14
16
|
try {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const require = createRequire(import.meta.url);
|
|
18
|
-
pg = require("pg");
|
|
17
|
+
const req = createRequire(import.meta.url);
|
|
18
|
+
pg = req("pg");
|
|
19
19
|
return pg!;
|
|
20
20
|
} catch {
|
|
21
21
|
throw new Error(
|
|
@@ -24,13 +24,6 @@ function requirePg(): typeof import("pg") {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
/** Synchronous helper to get createRequire — we call this at connection time. */
|
|
28
|
-
function await_import_module() {
|
|
29
|
-
// node:module is always available
|
|
30
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
31
|
-
return require("node:module") as typeof import("node:module");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
27
|
export interface PostgresConfig {
|
|
35
28
|
host?: string;
|
|
36
29
|
port?: number;
|